From: erik.corry@gmail.com Date: Fri, 21 May 2010 09:23:33 +0000 (+0000) Subject: Remove the fledgling Thumb2 support since we are concentrating X-Git-Tag: upstream/4.7.83~21764 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d0241c98c51061d97af9f0b923824c9ca11c21a1;p=platform%2Fupstream%2Fv8.git Remove the fledgling Thumb2 support since we are concentrating on other ways to make ARM code more compact. Review URL: http://codereview.chromium.org/2080017 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4698 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/SConstruct b/SConstruct index 1056de7..cf6b57d 100644 --- a/SConstruct +++ b/SConstruct @@ -210,12 +210,6 @@ LIBRARY_FLAGS = { 'CCFLAGS': ['-m32', '-DCAN_USE_UNALIGNED_ACCESSES=1'], 'LINKFLAGS': ['-m32'] }, - 'armvariant:thumb2': { - 'CPPDEFINES': ['V8_ARM_VARIANT_THUMB'] - }, - 'armvariant:arm': { - 'CPPDEFINES': ['V8_ARM_VARIANT_ARM'] - }, 'arch:mips': { 'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'], 'simulator:none': { @@ -765,11 +759,6 @@ SIMPLE_OPTIONS = { 'default': 'hidden', 'help': 'shared library symbol visibility' }, - 'armvariant': { - 'values': ['arm', 'thumb2', 'none'], - 'default': 'none', - 'help': 'generate thumb2 instructions instead of arm instructions (default)' - }, 'pgo': { 'values': ['off', 'instrument', 'optimize'], 'default': 'off', @@ -963,10 +952,6 @@ def PostprocessOptions(options, os): if 'msvcltcg' in ARGUMENTS: print "Warning: forcing msvcltcg on as it is required for pgo (%s)" % options['pgo'] options['msvcltcg'] = 'on' - if (options['armvariant'] == 'none' and options['arch'] == 'arm'): - options['armvariant'] = 'arm' - if (options['armvariant'] != 'none' and options['arch'] != 'arm'): - options['armvariant'] = 'none' if options['arch'] == 'mips': if ('regexp' in ARGUMENTS) and options['regexp'] == 'native': # Print a warning if native regexp is specified for mips diff --git a/src/SConscript b/src/SConscript index b68f6d1..8466a0c 100755 --- a/src/SConscript +++ b/src/SConscript @@ -136,13 +136,8 @@ SOURCES = { arm/register-allocator-arm.cc arm/stub-cache-arm.cc arm/virtual-frame-arm.cc - """), - 'armvariant:arm': Split(""" arm/assembler-arm.cc """), - 'armvariant:thumb2': Split(""" - arm/assembler-thumb2.cc - """), 'arch:mips': Split(""" fast-codegen.cc mips/assembler-mips.cc diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index f2fc020..dba62e6 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -36,7 +36,7 @@ #include "v8.h" -#if defined(V8_TARGET_ARCH_ARM) && defined(V8_ARM_VARIANT_ARM) +#if defined(V8_TARGET_ARCH_ARM) #include "arm/assembler-arm-inl.h" #include "serialize.h" @@ -2228,4 +2228,4 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { } } // namespace v8::internal -#endif // V8_TARGET_ARCH_ARM && V8_ARM_VARIANT_ARM +#endif // V8_TARGET_ARCH_ARM diff --git a/src/arm/assembler-thumb2-inl.h b/src/arm/assembler-thumb2-inl.h deleted file mode 100644 index 9e0fc2f..0000000 --- a/src/arm/assembler-thumb2-inl.h +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright (c) 1994-2006 Sun Microsystems 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: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// - Redistribution 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. -// -// - Neither the name of Sun Microsystems or the names of contributors may -// be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE -// COPYRIGHT OWNER 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. - -// The original source code covered by the above license above has been modified -// significantly by Google Inc. -// Copyright 2006-2008 the V8 project authors. All rights reserved. - -#ifndef V8_ARM_ASSEMBLER_THUMB2_INL_H_ -#define V8_ARM_ASSEMBLER_THUMB2_INL_H_ - -#include "arm/assembler-thumb2.h" -#include "cpu.h" - - -namespace v8 { -namespace internal { - -Condition NegateCondition(Condition cc) { - ASSERT(cc != al); - return static_cast(cc ^ ne); -} - - -void RelocInfo::apply(intptr_t delta) { - if (RelocInfo::IsInternalReference(rmode_)) { - // absolute code pointer inside code object moves with the code object. - int32_t* p = reinterpret_cast(pc_); - *p += delta; // relocate entry - } - // We do not use pc relative addressing on ARM, so there is - // nothing else to do. -} - - -Address RelocInfo::target_address() { - ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); - return Assembler::target_address_at(pc_); -} - - -Address RelocInfo::target_address_address() { - ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); - return reinterpret_cast
(Assembler::target_address_address_at(pc_)); -} - - -void RelocInfo::set_target_address(Address target) { - ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); - Assembler::set_target_address_at(pc_, target); -} - - -Object* RelocInfo::target_object() { - ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return Memory::Object_at(Assembler::target_address_address_at(pc_)); -} - - -Handle RelocInfo::target_object_handle(Assembler* origin) { - ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_)); -} - - -Object** RelocInfo::target_object_address() { - ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return reinterpret_cast(Assembler::target_address_address_at(pc_)); -} - - -void RelocInfo::set_target_object(Object* target) { - ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - Assembler::set_target_address_at(pc_, reinterpret_cast
(target)); -} - - -Address* RelocInfo::target_reference_address() { - ASSERT(rmode_ == EXTERNAL_REFERENCE); - return reinterpret_cast(Assembler::target_address_address_at(pc_)); -} - - -Address RelocInfo::call_address() { - ASSERT(IsPatchedReturnSequence()); - // The 2 instructions offset assumes patched return sequence. - ASSERT(IsJSReturn(rmode())); - return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize); -} - - -void RelocInfo::set_call_address(Address target) { - ASSERT(IsPatchedReturnSequence()); - // The 2 instructions offset assumes patched return sequence. - ASSERT(IsJSReturn(rmode())); - Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target; -} - - -Object* RelocInfo::call_object() { - return *call_object_address(); -} - - -Object** RelocInfo::call_object_address() { - ASSERT(IsPatchedReturnSequence()); - // The 2 instructions offset assumes patched return sequence. - ASSERT(IsJSReturn(rmode())); - return reinterpret_cast(pc_ + 2 * Assembler::kInstrSize); -} - - -void RelocInfo::set_call_object(Object* target) { - *call_object_address() = target; -} - - -bool RelocInfo::IsPatchedReturnSequence() { - // On ARM a "call instruction" is actually two instructions. - // mov lr, pc - // ldr pc, [pc, #XXX] - return (Assembler::instr_at(pc_) == kMovLrPc) - && ((Assembler::instr_at(pc_ + Assembler::kInstrSize) & kLdrPCPattern) - == kLdrPCPattern); -} - - -Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) { - rm_ = no_reg; - imm32_ = immediate; - rmode_ = rmode; -} - - -Operand::Operand(const char* s) { - rm_ = no_reg; - imm32_ = reinterpret_cast(s); - rmode_ = RelocInfo::EMBEDDED_STRING; -} - - -Operand::Operand(const ExternalReference& f) { - rm_ = no_reg; - imm32_ = reinterpret_cast(f.address()); - rmode_ = RelocInfo::EXTERNAL_REFERENCE; -} - - -Operand::Operand(Smi* value) { - rm_ = no_reg; - imm32_ = reinterpret_cast(value); - rmode_ = RelocInfo::NONE; -} - - -Operand::Operand(Register rm) { - rm_ = rm; - rs_ = no_reg; - shift_op_ = LSL; - shift_imm_ = 0; -} - - -bool Operand::is_reg() const { - return rm_.is_valid() && - rs_.is(no_reg) && - shift_op_ == LSL && - shift_imm_ == 0; -} - - -void Assembler::CheckBuffer() { - if (buffer_space() <= kGap) { - GrowBuffer(); - } - if (pc_offset() >= next_buffer_check_) { - CheckConstPool(false, true); - } -} - - -void Assembler::emit(Instr x) { - CheckBuffer(); - *reinterpret_cast(pc_) = x; - pc_ += kInstrSize; -} - - -Address Assembler::target_address_address_at(Address pc) { - Address target_pc = pc; - Instr instr = Memory::int32_at(target_pc); - // If we have a bx instruction, the instruction before the bx is - // what we need to patch. - static const int32_t kBxInstMask = 0x0ffffff0; - static const int32_t kBxInstPattern = 0x012fff10; - if ((instr & kBxInstMask) == kBxInstPattern) { - target_pc -= kInstrSize; - instr = Memory::int32_at(target_pc); - } - // Verify that the instruction to patch is a - // ldr , [pc +/- offset_12]. - ASSERT((instr & 0x0f7f0000) == 0x051f0000); - int offset = instr & 0xfff; // offset_12 is unsigned - if ((instr & (1 << 23)) == 0) offset = -offset; // U bit defines offset sign - // Verify that the constant pool comes after the instruction referencing it. - ASSERT(offset >= -4); - return target_pc + offset + 8; -} - - -Address Assembler::target_address_at(Address pc) { - return Memory::Address_at(target_address_address_at(pc)); -} - - -void Assembler::set_target_at(Address constant_pool_entry, - Address target) { - Memory::Address_at(constant_pool_entry) = target; -} - - -void Assembler::set_target_address_at(Address pc, Address target) { - Memory::Address_at(target_address_address_at(pc)) = target; - // Intuitively, we would think it is necessary to flush the instruction cache - // after patching a target address in the code as follows: - // CPU::FlushICache(pc, sizeof(target)); - // However, on ARM, no instruction was actually patched by the assignment - // above; the target address is not part of an instruction, it is patched in - // the constant pool and is read via a data access; the instruction accessing - // this address in the constant pool remains unchanged. -} - -} } // namespace v8::internal - -#endif // V8_ARM_ASSEMBLER_THUMB2_INL_H_ diff --git a/src/arm/assembler-thumb2.cc b/src/arm/assembler-thumb2.cc deleted file mode 100644 index c98a11a..0000000 --- a/src/arm/assembler-thumb2.cc +++ /dev/null @@ -1,1833 +0,0 @@ -// Copyright (c) 1994-2006 Sun Microsystems 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: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// - Redistribution 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. -// -// - Neither the name of Sun Microsystems or the names of contributors may -// be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE -// COPYRIGHT OWNER 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. - -// The original source code covered by the above license above has been -// modified significantly by Google Inc. -// Copyright 2010 the V8 project authors. All rights reserved. - -#include "v8.h" - -#if defined(V8_TARGET_ARCH_ARM) && defined(V8_ARM_VARIANT_THUMB) - -#include "arm/assembler-thumb2-inl.h" -#include "serialize.h" - -namespace v8 { -namespace internal { - -// Safe default is no features. -unsigned CpuFeatures::supported_ = 0; -unsigned CpuFeatures::enabled_ = 0; -unsigned CpuFeatures::found_by_runtime_probing_ = 0; - -void CpuFeatures::Probe() { - // If the compiler is allowed to use vfp then we can use vfp too in our - // code generation. -#if !defined(__arm__) - // For the simulator=arm build, use VFP when FLAG_enable_vfp3 is enabled. - if (FLAG_enable_vfp3) { - supported_ |= 1u << VFP3; - } - // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled - if (FLAG_enable_armv7) { - supported_ |= 1u << ARMv7; - } -#else - if (Serializer::enabled()) { - supported_ |= OS::CpuFeaturesImpliedByPlatform(); - return; // No features if we might serialize. - } - - if (OS::ArmCpuHasFeature(VFP3)) { - // This implementation also sets the VFP flags if - // runtime detection of VFP returns true. - supported_ |= 1u << VFP3; - found_by_runtime_probing_ |= 1u << VFP3; - } - - if (OS::ArmCpuHasFeature(ARMv7)) { - supported_ |= 1u << ARMv7; - found_by_runtime_probing_ |= 1u << ARMv7; - } -#endif -} - - -// ----------------------------------------------------------------------------- -// Implementation of Register and CRegister - -Register no_reg = { -1 }; - -Register r0 = { 0 }; -Register r1 = { 1 }; -Register r2 = { 2 }; -Register r3 = { 3 }; -Register r4 = { 4 }; -Register r5 = { 5 }; -Register r6 = { 6 }; -Register r7 = { 7 }; -Register r8 = { 8 }; // Used as context register. -Register r9 = { 9 }; -Register r10 = { 10 }; // Used as roots register. -Register fp = { 11 }; -Register ip = { 12 }; -Register sp = { 13 }; -Register lr = { 14 }; -Register pc = { 15 }; - - -CRegister no_creg = { -1 }; - -CRegister cr0 = { 0 }; -CRegister cr1 = { 1 }; -CRegister cr2 = { 2 }; -CRegister cr3 = { 3 }; -CRegister cr4 = { 4 }; -CRegister cr5 = { 5 }; -CRegister cr6 = { 6 }; -CRegister cr7 = { 7 }; -CRegister cr8 = { 8 }; -CRegister cr9 = { 9 }; -CRegister cr10 = { 10 }; -CRegister cr11 = { 11 }; -CRegister cr12 = { 12 }; -CRegister cr13 = { 13 }; -CRegister cr14 = { 14 }; -CRegister cr15 = { 15 }; - -// Support for the VFP registers s0 to s31 (d0 to d15). -// Note that "sN:sM" is the same as "dN/2". -SwVfpRegister s0 = { 0 }; -SwVfpRegister s1 = { 1 }; -SwVfpRegister s2 = { 2 }; -SwVfpRegister s3 = { 3 }; -SwVfpRegister s4 = { 4 }; -SwVfpRegister s5 = { 5 }; -SwVfpRegister s6 = { 6 }; -SwVfpRegister s7 = { 7 }; -SwVfpRegister s8 = { 8 }; -SwVfpRegister s9 = { 9 }; -SwVfpRegister s10 = { 10 }; -SwVfpRegister s11 = { 11 }; -SwVfpRegister s12 = { 12 }; -SwVfpRegister s13 = { 13 }; -SwVfpRegister s14 = { 14 }; -SwVfpRegister s15 = { 15 }; -SwVfpRegister s16 = { 16 }; -SwVfpRegister s17 = { 17 }; -SwVfpRegister s18 = { 18 }; -SwVfpRegister s19 = { 19 }; -SwVfpRegister s20 = { 20 }; -SwVfpRegister s21 = { 21 }; -SwVfpRegister s22 = { 22 }; -SwVfpRegister s23 = { 23 }; -SwVfpRegister s24 = { 24 }; -SwVfpRegister s25 = { 25 }; -SwVfpRegister s26 = { 26 }; -SwVfpRegister s27 = { 27 }; -SwVfpRegister s28 = { 28 }; -SwVfpRegister s29 = { 29 }; -SwVfpRegister s30 = { 30 }; -SwVfpRegister s31 = { 31 }; - -DwVfpRegister d0 = { 0 }; -DwVfpRegister d1 = { 1 }; -DwVfpRegister d2 = { 2 }; -DwVfpRegister d3 = { 3 }; -DwVfpRegister d4 = { 4 }; -DwVfpRegister d5 = { 5 }; -DwVfpRegister d6 = { 6 }; -DwVfpRegister d7 = { 7 }; -DwVfpRegister d8 = { 8 }; -DwVfpRegister d9 = { 9 }; -DwVfpRegister d10 = { 10 }; -DwVfpRegister d11 = { 11 }; -DwVfpRegister d12 = { 12 }; -DwVfpRegister d13 = { 13 }; -DwVfpRegister d14 = { 14 }; -DwVfpRegister d15 = { 15 }; - -// ----------------------------------------------------------------------------- -// Implementation of RelocInfo - -const int RelocInfo::kApplyMask = 0; - - -void RelocInfo::PatchCode(byte* instructions, int instruction_count) { - // Patch the code at the current address with the supplied instructions. - Instr* pc = reinterpret_cast(pc_); - Instr* instr = reinterpret_cast(instructions); - for (int i = 0; i < instruction_count; i++) { - *(pc + i) = *(instr + i); - } - - // Indicate that code has changed. - CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize); -} - - -// Patch the code at the current PC with a call to the target address. -// Additional guard instructions can be added if required. -void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { - // Patch the code at the current address with a call to the target. - UNIMPLEMENTED(); -} - - -// ----------------------------------------------------------------------------- -// Implementation of Operand and MemOperand -// See assembler-thumb2-inl.h for inlined constructors - -Operand::Operand(Handle handle) { - rm_ = no_reg; - // Verify all Objects referred by code are NOT in new space. - Object* obj = *handle; - ASSERT(!Heap::InNewSpace(obj)); - if (obj->IsHeapObject()) { - imm32_ = reinterpret_cast(handle.location()); - rmode_ = RelocInfo::EMBEDDED_OBJECT; - } else { - // no relocation needed - imm32_ = reinterpret_cast(obj); - rmode_ = RelocInfo::NONE; - } -} - - -Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) { - ASSERT(is_uint5(shift_imm)); - ASSERT(shift_op != ROR || shift_imm != 0); // use RRX if you mean it - rm_ = rm; - rs_ = no_reg; - shift_op_ = shift_op; - shift_imm_ = shift_imm & 31; - if (shift_op == RRX) { - // encoded as ROR with shift_imm == 0 - ASSERT(shift_imm == 0); - shift_op_ = ROR; - shift_imm_ = 0; - } -} - - -Operand::Operand(Register rm, ShiftOp shift_op, Register rs) { - ASSERT(shift_op != RRX); - rm_ = rm; - rs_ = no_reg; - shift_op_ = shift_op; - rs_ = rs; -} - - -MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) { - rn_ = rn; - rm_ = no_reg; - offset_ = offset; - am_ = am; -} - -MemOperand::MemOperand(Register rn, Register rm, AddrMode am) { - rn_ = rn; - rm_ = rm; - shift_op_ = LSL; - shift_imm_ = 0; - am_ = am; -} - - -MemOperand::MemOperand(Register rn, Register rm, - ShiftOp shift_op, int shift_imm, AddrMode am) { - ASSERT(is_uint5(shift_imm)); - rn_ = rn; - rm_ = rm; - shift_op_ = shift_op; - shift_imm_ = shift_imm & 31; - am_ = am; -} - - -// ----------------------------------------------------------------------------- -// Implementation of Assembler. - -// Instruction encoding bits. -enum { - H = 1 << 5, // halfword (or byte) - S6 = 1 << 6, // signed (or unsigned) - L = 1 << 20, // load (or store) - S = 1 << 20, // set condition code (or leave unchanged) - W = 1 << 21, // writeback base register (or leave unchanged) - A = 1 << 21, // accumulate in multiply instruction (or not) - B = 1 << 22, // unsigned byte (or word) - N = 1 << 22, // long (or short) - U = 1 << 23, // positive (or negative) offset/index - P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) - I = 1 << 25, // immediate shifter operand (or not) - - B4 = 1 << 4, - B5 = 1 << 5, - B6 = 1 << 6, - B7 = 1 << 7, - B8 = 1 << 8, - B9 = 1 << 9, - B12 = 1 << 12, - B16 = 1 << 16, - B18 = 1 << 18, - B19 = 1 << 19, - B20 = 1 << 20, - B21 = 1 << 21, - B22 = 1 << 22, - B23 = 1 << 23, - B24 = 1 << 24, - B25 = 1 << 25, - B26 = 1 << 26, - B27 = 1 << 27, - - // Instruction bit masks. - RdMask = 15 << 12, // in str instruction - CondMask = 15 << 28, - CoprocessorMask = 15 << 8, - OpCodeMask = 15 << 21, // in data-processing instructions - Imm24Mask = (1 << 24) - 1, - Off12Mask = (1 << 12) - 1, - // Reserved condition. - nv = 15 << 28 -}; - - -// add(sp, sp, 4) instruction (aka Pop()) -static const Instr kPopInstruction = - al | 4 * B21 | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12; -// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) -// register r is not encoded. -static const Instr kPushRegPattern = - al | B26 | 4 | NegPreIndex | sp.code() * B16; -// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) -// register r is not encoded. -static const Instr kPopRegPattern = - al | B26 | L | 4 | PostIndex | sp.code() * B16; -// mov lr, pc -const Instr kMovLrPc = al | 13*B21 | pc.code() | lr.code() * B12; -// ldr pc, [pc, #XXX] -const Instr kLdrPCPattern = al | B26 | L | pc.code() * B16; - -// Spare buffer. -static const int kMinimalBufferSize = 4*KB; -static byte* spare_buffer_ = NULL; - -Assembler::Assembler(void* buffer, int buffer_size) { - if (buffer == NULL) { - // Do our own buffer management. - if (buffer_size <= kMinimalBufferSize) { - buffer_size = kMinimalBufferSize; - - if (spare_buffer_ != NULL) { - buffer = spare_buffer_; - spare_buffer_ = NULL; - } - } - if (buffer == NULL) { - buffer_ = NewArray(buffer_size); - } else { - buffer_ = static_cast(buffer); - } - buffer_size_ = buffer_size; - own_buffer_ = true; - - } else { - // Use externally provided buffer instead. - ASSERT(buffer_size > 0); - buffer_ = static_cast(buffer); - buffer_size_ = buffer_size; - own_buffer_ = false; - } - - // Setup buffer pointers. - ASSERT(buffer_ != NULL); - pc_ = buffer_; - reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); - num_prinfo_ = 0; - next_buffer_check_ = 0; - no_const_pool_before_ = 0; - last_const_pool_end_ = 0; - last_bound_pos_ = 0; - current_statement_position_ = RelocInfo::kNoPosition; - current_position_ = RelocInfo::kNoPosition; - written_statement_position_ = current_statement_position_; - written_position_ = current_position_; -} - - -Assembler::~Assembler() { - if (own_buffer_) { - if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { - spare_buffer_ = buffer_; - } else { - DeleteArray(buffer_); - } - } -} - - -void Assembler::GetCode(CodeDesc* desc) { - // Emit constant pool if necessary. - CheckConstPool(true, false); - ASSERT(num_prinfo_ == 0); - - // Setup code descriptor. - desc->buffer = buffer_; - desc->buffer_size = buffer_size_; - desc->instr_size = pc_offset(); - desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); -} - - -void Assembler::Align(int m) { - ASSERT(m >= 4 && IsPowerOf2(m)); - while ((pc_offset() & (m - 1)) != 0) { - nop(); - } -} - - -// Labels refer to positions in the (to be) generated code. -// There are bound, linked, and unused labels. -// -// Bound labels refer to known positions in the already -// generated code. pos() is the position the label refers to. -// -// Linked labels refer to unknown positions in the code -// to be generated; pos() is the position of the last -// instruction using the label. - - -// The link chain is terminated by a negative code position (must be aligned) -const int kEndOfChain = -4; - - -int Assembler::target_at(int pos) { - Instr instr = instr_at(pos); - if ((instr & ~Imm24Mask) == 0) { - // Emitted label constant, not part of a branch. - return instr - (Code::kHeaderSize - kHeapObjectTag); - } - ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 - int imm26 = ((instr & Imm24Mask) << 8) >> 6; - if ((instr & CondMask) == nv && (instr & B24) != 0) - // blx uses bit 24 to encode bit 2 of imm26 - imm26 += 2; - - return pos + kPcLoadDelta + imm26; -} - - -void Assembler::target_at_put(int pos, int target_pos) { - Instr instr = instr_at(pos); - if ((instr & ~Imm24Mask) == 0) { - ASSERT(target_pos == kEndOfChain || target_pos >= 0); - // Emitted label constant, not part of a branch. - // Make label relative to Code* of generated Code object. - instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); - return; - } - int imm26 = target_pos - (pos + kPcLoadDelta); - ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 - if ((instr & CondMask) == nv) { - // blx uses bit 24 to encode bit 2 of imm26 - ASSERT((imm26 & 1) == 0); - instr = (instr & ~(B24 | Imm24Mask)) | ((imm26 & 2) >> 1)*B24; - } else { - ASSERT((imm26 & 3) == 0); - instr &= ~Imm24Mask; - } - int imm24 = imm26 >> 2; - ASSERT(is_int24(imm24)); - instr_at_put(pos, instr | (imm24 & Imm24Mask)); -} - - -void Assembler::print(Label* L) { - if (L->is_unused()) { - PrintF("unused label\n"); - } else if (L->is_bound()) { - PrintF("bound label to %d\n", L->pos()); - } else if (L->is_linked()) { - Label l = *L; - PrintF("unbound label"); - while (l.is_linked()) { - PrintF("@ %d ", l.pos()); - Instr instr = instr_at(l.pos()); - if ((instr & ~Imm24Mask) == 0) { - PrintF("value\n"); - } else { - ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx - int cond = instr & CondMask; - const char* b; - const char* c; - if (cond == nv) { - b = "blx"; - c = ""; - } else { - if ((instr & B24) != 0) - b = "bl"; - else - b = "b"; - - switch (cond) { - case eq: c = "eq"; break; - case ne: c = "ne"; break; - case hs: c = "hs"; break; - case lo: c = "lo"; break; - case mi: c = "mi"; break; - case pl: c = "pl"; break; - case vs: c = "vs"; break; - case vc: c = "vc"; break; - case hi: c = "hi"; break; - case ls: c = "ls"; break; - case ge: c = "ge"; break; - case lt: c = "lt"; break; - case gt: c = "gt"; break; - case le: c = "le"; break; - case al: c = ""; break; - default: - c = ""; - UNREACHABLE(); - } - } - PrintF("%s%s\n", b, c); - } - next(&l); - } - } else { - PrintF("label in inconsistent state (pos = %d)\n", L->pos_); - } -} - - -void Assembler::bind_to(Label* L, int pos) { - ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position - while (L->is_linked()) { - int fixup_pos = L->pos(); - next(L); // call next before overwriting link with target at fixup_pos - target_at_put(fixup_pos, pos); - } - L->bind_to(pos); - - // Keep track of the last bound label so we don't eliminate any instructions - // before a bound label. - if (pos > last_bound_pos_) - last_bound_pos_ = pos; -} - - -void Assembler::link_to(Label* L, Label* appendix) { - if (appendix->is_linked()) { - if (L->is_linked()) { - // Append appendix to L's list. - int fixup_pos; - int link = L->pos(); - do { - fixup_pos = link; - link = target_at(fixup_pos); - } while (link > 0); - ASSERT(link == kEndOfChain); - target_at_put(fixup_pos, appendix->pos()); - } else { - // L is empty, simply use appendix. - *L = *appendix; - } - } - appendix->Unuse(); // appendix should not be used anymore -} - - -void Assembler::bind(Label* L) { - ASSERT(!L->is_bound()); // label can only be bound once - bind_to(L, pc_offset()); -} - - -void Assembler::next(Label* L) { - ASSERT(L->is_linked()); - int link = target_at(L->pos()); - if (link > 0) { - L->link_to(link); - } else { - ASSERT(link == kEndOfChain); - L->Unuse(); - } -} - - -// Low-level code emission routines depending on the addressing mode. -static bool fits_shifter(uint32_t imm32, - uint32_t* rotate_imm, - uint32_t* immed_8, - Instr* instr) { - // imm32 must be unsigned. - for (int rot = 0; rot < 16; rot++) { - uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot)); - if ((imm8 <= 0xff)) { - *rotate_imm = rot; - *immed_8 = imm8; - return true; - } - } - // If the opcode is mov or mvn and if ~imm32 fits, change the opcode. - if (instr != NULL && (*instr & 0xd*B21) == 0xd*B21) { - if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { - *instr ^= 0x2*B21; - return true; - } - } - return false; -} - - -// We have to use the temporary register for things that can be relocated even -// if they can be encoded in the ARM's 12 bits of immediate-offset instruction -// space. There is no guarantee that the relocated location can be similarly -// encoded. -static bool MustUseIp(RelocInfo::Mode rmode) { - if (rmode == RelocInfo::EXTERNAL_REFERENCE) { -#ifdef DEBUG - if (!Serializer::enabled()) { - Serializer::TooLateToEnableNow(); - } -#endif - return Serializer::enabled(); - } else if (rmode == RelocInfo::NONE) { - return false; - } - return true; -} - - -void Assembler::addrmod1(Instr instr, - Register rn, - Register rd, - const Operand& x) { - CheckBuffer(); - ASSERT((instr & ~(CondMask | OpCodeMask | S)) == 0); - if (!x.rm_.is_valid()) { - // Immediate. - uint32_t rotate_imm; - uint32_t immed_8; - if (MustUseIp(x.rmode_) || - !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { - // The immediate operand cannot be encoded as a shifter operand, so load - // it first to register ip and change the original instruction to use ip. - // However, if the original instruction is a 'mov rd, x' (not setting the - // condition code), then replace it with a 'ldr rd, [pc]'. - RecordRelocInfo(x.rmode_, x.imm32_); - CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed - Condition cond = static_cast(instr & CondMask); - if ((instr & ~CondMask) == 13*B21) { // mov, S not set - ldr(rd, MemOperand(pc, 0), cond); - } else { - ldr(ip, MemOperand(pc, 0), cond); - addrmod1(instr, rn, rd, Operand(ip)); - } - return; - } - instr |= I | rotate_imm*B8 | immed_8; - } else if (!x.rs_.is_valid()) { - // Immediate shift. - instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); - } else { - // Register shift. - ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); - instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); - } - emit(instr | rn.code()*B16 | rd.code()*B12); - if (rn.is(pc) || x.rm_.is(pc)) - // Block constant pool emission for one instruction after reading pc. - BlockConstPoolBefore(pc_offset() + kInstrSize); -} - - -void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { - ASSERT((instr & ~(CondMask | B | L)) == B26); - int am = x.am_; - if (!x.rm_.is_valid()) { - // Immediate offset. - int offset_12 = x.offset_; - if (offset_12 < 0) { - offset_12 = -offset_12; - am ^= U; - } - if (!is_uint12(offset_12)) { - // Immediate offset cannot be encoded, load it first to register ip - // rn (and rd in a load) should never be ip, or will be trashed. - ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); - mov(ip, Operand(x.offset_), LeaveCC, - static_cast(instr & CondMask)); - addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_)); - return; - } - ASSERT(offset_12 >= 0); // no masking needed - instr |= offset_12; - } else { - // Register offset (shift_imm_ and shift_op_ are 0) or scaled - // register offset the constructors make sure than both shift_imm_ - // and shift_op_ are initialized. - ASSERT(!x.rm_.is(pc)); - instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); - } - ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback - emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); -} - - -void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { - ASSERT((instr & ~(CondMask | L | S6 | H)) == (B4 | B7)); - ASSERT(x.rn_.is_valid()); - int am = x.am_; - if (!x.rm_.is_valid()) { - // Immediate offset. - int offset_8 = x.offset_; - if (offset_8 < 0) { - offset_8 = -offset_8; - am ^= U; - } - if (!is_uint8(offset_8)) { - // Immediate offset cannot be encoded, load it first to register ip - // rn (and rd in a load) should never be ip, or will be trashed. - ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); - mov(ip, Operand(x.offset_), LeaveCC, - static_cast(instr & CondMask)); - addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); - return; - } - ASSERT(offset_8 >= 0); // no masking needed - instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf); - } else if (x.shift_imm_ != 0) { - // Scaled register offset not supported, load index first - // rn (and rd in a load) should never be ip, or will be trashed. - ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); - mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC, - static_cast(instr & CondMask)); - addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); - return; - } else { - // Register offset. - ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback - instr |= x.rm_.code(); - } - ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback - emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); -} - - -void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { - ASSERT((instr & ~(CondMask | P | U | W | L)) == B27); - ASSERT(rl != 0); - ASSERT(!rn.is(pc)); - emit(instr | rn.code()*B16 | rl); -} - - -void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) { - // Unindexed addressing is not encoded by this function. - ASSERT_EQ((B27 | B26), - (instr & ~(CondMask | CoprocessorMask | P | U | N | W | L))); - ASSERT(x.rn_.is_valid() && !x.rm_.is_valid()); - int am = x.am_; - int offset_8 = x.offset_; - ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset - offset_8 >>= 2; - if (offset_8 < 0) { - offset_8 = -offset_8; - am ^= U; - } - ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte - ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback - - // Post-indexed addressing requires W == 1; different than in addrmod2/3. - if ((am & P) == 0) - am |= W; - - ASSERT(offset_8 >= 0); // no masking needed - emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8); -} - - -int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { - int target_pos; - if (L->is_bound()) { - target_pos = L->pos(); - } else { - if (L->is_linked()) { - target_pos = L->pos(); // L's link - } else { - target_pos = kEndOfChain; - } - L->link_to(pc_offset()); - } - - // Block the emission of the constant pool, since the branch instruction must - // be emitted at the pc offset recorded by the label. - BlockConstPoolBefore(pc_offset() + kInstrSize); - return target_pos - (pc_offset() + kPcLoadDelta); -} - - -void Assembler::label_at_put(Label* L, int at_offset) { - int target_pos; - if (L->is_bound()) { - target_pos = L->pos(); - } else { - if (L->is_linked()) { - target_pos = L->pos(); // L's link - } else { - target_pos = kEndOfChain; - } - L->link_to(at_offset); - instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); - } -} - - -// Branch instructions. -void Assembler::b(int branch_offset, Condition cond) { - ASSERT((branch_offset & 3) == 0); - int imm24 = branch_offset >> 2; - ASSERT(is_int24(imm24)); - emit(cond | B27 | B25 | (imm24 & Imm24Mask)); - - if (cond == al) - // Dead code is a good location to emit the constant pool. - CheckConstPool(false, false); -} - - -void Assembler::bl(int branch_offset, Condition cond) { - ASSERT((branch_offset & 3) == 0); - int imm24 = branch_offset >> 2; - ASSERT(is_int24(imm24)); - emit(cond | B27 | B25 | B24 | (imm24 & Imm24Mask)); -} - - -void Assembler::blx(int branch_offset) { // v5 and above - WriteRecordedPositions(); - ASSERT((branch_offset & 1) == 0); - int h = ((branch_offset & 2) >> 1)*B24; - int imm24 = branch_offset >> 2; - ASSERT(is_int24(imm24)); - emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask)); -} - - -void Assembler::blx(Register target, Condition cond) { // v5 and above - WriteRecordedPositions(); - ASSERT(!target.is(pc)); - emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code()); -} - - -void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t - WriteRecordedPositions(); - ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged - emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code()); -} - - -// Data-processing instructions. - -// UBFX ,,#,# -// Instruction details available in ARM DDI 0406A, A8-464. -// cond(31-28) | 01111(27-23)| 1(22) | 1(21) | widthm1(20-16) | -// Rd(15-12) | lsb(11-7) | 101(6-4) | Rn(3-0) -void Assembler::ubfx(Register dst, Register src1, const Operand& src2, - const Operand& src3, Condition cond) { - ASSERT(!src2.rm_.is_valid() && !src3.rm_.is_valid()); - ASSERT(static_cast(src2.imm32_) <= 0x1f); - ASSERT(static_cast(src3.imm32_) <= 0x1f); - emit(cond | 0x3F*B21 | src3.imm32_*B16 | - dst.code()*B12 | src2.imm32_*B7 | 0x5*B4 | src1.code()); -} - - -void Assembler::and_(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 0*B21 | s, src1, dst, src2); -} - - -void Assembler::eor(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 1*B21 | s, src1, dst, src2); -} - - -void Assembler::sub(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 2*B21 | s, src1, dst, src2); -} - - -void Assembler::rsb(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 3*B21 | s, src1, dst, src2); -} - - -void Assembler::add(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 4*B21 | s, src1, dst, src2); - - // Eliminate pattern: push(r), pop() - // str(src, MemOperand(sp, 4, NegPreIndex), al); - // add(sp, sp, Operand(kPointerSize)); - // Both instructions can be eliminated. - int pattern_size = 2 * kInstrSize; - if (FLAG_push_pop_elimination && - last_bound_pos_ <= (pc_offset() - pattern_size) && - reloc_info_writer.last_pc() <= (pc_ - pattern_size) && - // Pattern. - instr_at(pc_ - 1 * kInstrSize) == kPopInstruction && - (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) { - pc_ -= 2 * kInstrSize; - if (FLAG_print_push_pop_elimination) { - PrintF("%x push(reg)/pop() eliminated\n", pc_offset()); - } - } -} - - -void Assembler::adc(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 5*B21 | s, src1, dst, src2); -} - - -void Assembler::sbc(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 6*B21 | s, src1, dst, src2); -} - - -void Assembler::rsc(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 7*B21 | s, src1, dst, src2); -} - - -void Assembler::tst(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 8*B21 | S, src1, r0, src2); -} - - -void Assembler::teq(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 9*B21 | S, src1, r0, src2); -} - - -void Assembler::cmp(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 10*B21 | S, src1, r0, src2); -} - - -void Assembler::cmn(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 11*B21 | S, src1, r0, src2); -} - - -void Assembler::orr(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 12*B21 | s, src1, dst, src2); -} - - -void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { - if (dst.is(pc)) { - WriteRecordedPositions(); - } - addrmod1(cond | 13*B21 | s, r0, dst, src); -} - - -void Assembler::bic(Register dst, Register src1, const Operand& src2, - SBit s, Condition cond) { - addrmod1(cond | 14*B21 | s, src1, dst, src2); -} - - -void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) { - addrmod1(cond | 15*B21 | s, r0, dst, src); -} - - -// Multiply instructions. -void Assembler::mla(Register dst, Register src1, Register src2, Register srcA, - SBit s, Condition cond) { - ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); - emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 | - src2.code()*B8 | B7 | B4 | src1.code()); -} - - -void Assembler::mul(Register dst, Register src1, Register src2, - SBit s, Condition cond) { - ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); - // dst goes in bits 16-19 for this instruction! - emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code()); -} - - -void Assembler::smlal(Register dstL, - Register dstH, - Register src1, - Register src2, - SBit s, - Condition cond) { - ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); - ASSERT(!dstL.is(dstH)); - emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 | - src2.code()*B8 | B7 | B4 | src1.code()); -} - - -void Assembler::smull(Register dstL, - Register dstH, - Register src1, - Register src2, - SBit s, - Condition cond) { - ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); - ASSERT(!dstL.is(dstH)); - emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 | - src2.code()*B8 | B7 | B4 | src1.code()); -} - - -void Assembler::umlal(Register dstL, - Register dstH, - Register src1, - Register src2, - SBit s, - Condition cond) { - ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); - ASSERT(!dstL.is(dstH)); - emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 | - src2.code()*B8 | B7 | B4 | src1.code()); -} - - -void Assembler::umull(Register dstL, - Register dstH, - Register src1, - Register src2, - SBit s, - Condition cond) { - ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); - ASSERT(!dstL.is(dstH)); - emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 | - src2.code()*B8 | B7 | B4 | src1.code()); -} - - -// Miscellaneous arithmetic instructions. -void Assembler::clz(Register dst, Register src, Condition cond) { - // v5 and above. - ASSERT(!dst.is(pc) && !src.is(pc)); - emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 | - 15*B8 | B4 | src.code()); -} - - -// Status register access instructions. -void Assembler::mrs(Register dst, SRegister s, Condition cond) { - ASSERT(!dst.is(pc)); - emit(cond | B24 | s | 15*B16 | dst.code()*B12); -} - - -void Assembler::msr(SRegisterFieldMask fields, const Operand& src, - Condition cond) { - ASSERT(fields >= B16 && fields < B20); // at least one field set - Instr instr; - if (!src.rm_.is_valid()) { - // Immediate. - uint32_t rotate_imm; - uint32_t immed_8; - if (MustUseIp(src.rmode_) || - !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { - // Immediate operand cannot be encoded, load it first to register ip. - RecordRelocInfo(src.rmode_, src.imm32_); - ldr(ip, MemOperand(pc, 0), cond); - msr(fields, Operand(ip), cond); - return; - } - instr = I | rotate_imm*B8 | immed_8; - } else { - ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed - instr = src.rm_.code(); - } - emit(cond | instr | B24 | B21 | fields | 15*B12); -} - - -// Load/Store instructions. -void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { - if (dst.is(pc)) { - WriteRecordedPositions(); - } - addrmod2(cond | B26 | L, dst, src); - - // Eliminate pattern: push(r), pop(r) - // str(r, MemOperand(sp, 4, NegPreIndex), al) - // ldr(r, MemOperand(sp, 4, PostIndex), al) - // Both instructions can be eliminated. - int pattern_size = 2 * kInstrSize; - if (FLAG_push_pop_elimination && - last_bound_pos_ <= (pc_offset() - pattern_size) && - reloc_info_writer.last_pc() <= (pc_ - pattern_size) && - // Pattern. - instr_at(pc_ - 1 * kInstrSize) == (kPopRegPattern | dst.code() * B12) && - instr_at(pc_ - 2 * kInstrSize) == (kPushRegPattern | dst.code() * B12)) { - pc_ -= 2 * kInstrSize; - if (FLAG_print_push_pop_elimination) { - PrintF("%x push/pop (same reg) eliminated\n", pc_offset()); - } - } -} - - -void Assembler::str(Register src, const MemOperand& dst, Condition cond) { - addrmod2(cond | B26, src, dst); - - // Eliminate pattern: pop(), push(r) - // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al - // -> str r, [sp, 0], al - int pattern_size = 2 * kInstrSize; - if (FLAG_push_pop_elimination && - last_bound_pos_ <= (pc_offset() - pattern_size) && - reloc_info_writer.last_pc() <= (pc_ - pattern_size) && - // Pattern. - instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) && - instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) { - pc_ -= 2 * kInstrSize; - emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12); - if (FLAG_print_push_pop_elimination) { - PrintF("%x pop()/push(reg) eliminated\n", pc_offset()); - } - } -} - - -void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) { - addrmod2(cond | B26 | B | L, dst, src); -} - - -void Assembler::strb(Register src, const MemOperand& dst, Condition cond) { - addrmod2(cond | B26 | B, src, dst); -} - - -void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) { - addrmod3(cond | L | B7 | H | B4, dst, src); -} - - -void Assembler::strh(Register src, const MemOperand& dst, Condition cond) { - addrmod3(cond | B7 | H | B4, src, dst); -} - - -void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) { - addrmod3(cond | L | B7 | S6 | B4, dst, src); -} - - -void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) { - addrmod3(cond | L | B7 | S6 | H | B4, dst, src); -} - - -// Load/Store multiple instructions. -void Assembler::ldm(BlockAddrMode am, - Register base, - RegList dst, - Condition cond) { - // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable. - ASSERT(base.is(sp) || (dst & sp.bit()) == 0); - - addrmod4(cond | B27 | am | L, base, dst); - - // Emit the constant pool after a function return implemented by ldm ..{..pc}. - if (cond == al && (dst & pc.bit()) != 0) { - // There is a slight chance that the ldm instruction was actually a call, - // in which case it would be wrong to return into the constant pool; we - // recognize this case by checking if the emission of the pool was blocked - // at the pc of the ldm instruction by a mov lr, pc instruction; if this is - // the case, we emit a jump over the pool. - CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize); - } -} - - -void Assembler::stm(BlockAddrMode am, - Register base, - RegList src, - Condition cond) { - addrmod4(cond | B27 | am, base, src); -} - - -// Exception-generating instructions and debugging support. -void Assembler::stop(const char* msg) { -#if !defined(__arm__) - // The simulator handles these special instructions and stops execution. - emit(15 << 28 | ((intptr_t) msg)); -#else - // Just issue a simple break instruction for now. Alternatively we could use - // the swi(0x9f0001) instruction on Linux. - bkpt(0); -#endif -} - - -void Assembler::bkpt(uint32_t imm16) { // v5 and above - ASSERT(is_uint16(imm16)); - emit(al | B24 | B21 | (imm16 >> 4)*B8 | 7*B4 | (imm16 & 0xf)); -} - - -void Assembler::swi(uint32_t imm24, Condition cond) { - ASSERT(is_uint24(imm24)); - emit(cond | 15*B24 | imm24); -} - - -// Coprocessor instructions. -void Assembler::cdp(Coprocessor coproc, - int opcode_1, - CRegister crd, - CRegister crn, - CRegister crm, - int opcode_2, - Condition cond) { - ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2)); - emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 | - crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code()); -} - - -void Assembler::cdp2(Coprocessor coproc, - int opcode_1, - CRegister crd, - CRegister crn, - CRegister crm, - int opcode_2) { // v5 and above - cdp(coproc, opcode_1, crd, crn, crm, opcode_2, static_cast(nv)); -} - - -void Assembler::mcr(Coprocessor coproc, - int opcode_1, - Register rd, - CRegister crn, - CRegister crm, - int opcode_2, - Condition cond) { - ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2)); - emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 | - rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); -} - - -void Assembler::mcr2(Coprocessor coproc, - int opcode_1, - Register rd, - CRegister crn, - CRegister crm, - int opcode_2) { // v5 and above - mcr(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast(nv)); -} - - -void Assembler::mrc(Coprocessor coproc, - int opcode_1, - Register rd, - CRegister crn, - CRegister crm, - int opcode_2, - Condition cond) { - ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2)); - emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 | - rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); -} - - -void Assembler::mrc2(Coprocessor coproc, - int opcode_1, - Register rd, - CRegister crn, - CRegister crm, - int opcode_2) { // v5 and above - mrc(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast(nv)); -} - - -void Assembler::ldc(Coprocessor coproc, - CRegister crd, - const MemOperand& src, - LFlag l, - Condition cond) { - addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src); -} - - -void Assembler::ldc(Coprocessor coproc, - CRegister crd, - Register rn, - int option, - LFlag l, - Condition cond) { - // Unindexed addressing. - ASSERT(is_uint8(option)); - emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 | - coproc*B8 | (option & 255)); -} - - -void Assembler::ldc2(Coprocessor coproc, - CRegister crd, - const MemOperand& src, - LFlag l) { // v5 and above - ldc(coproc, crd, src, l, static_cast(nv)); -} - - -void Assembler::ldc2(Coprocessor coproc, - CRegister crd, - Register rn, - int option, - LFlag l) { // v5 and above - ldc(coproc, crd, rn, option, l, static_cast(nv)); -} - - -void Assembler::stc(Coprocessor coproc, - CRegister crd, - const MemOperand& dst, - LFlag l, - Condition cond) { - addrmod5(cond | B27 | B26 | l | coproc*B8, crd, dst); -} - - -void Assembler::stc(Coprocessor coproc, - CRegister crd, - Register rn, - int option, - LFlag l, - Condition cond) { - // Unindexed addressing. - ASSERT(is_uint8(option)); - emit(cond | B27 | B26 | U | l | rn.code()*B16 | crd.code()*B12 | - coproc*B8 | (option & 255)); -} - - -void Assembler::stc2(Coprocessor - coproc, CRegister crd, - const MemOperand& dst, - LFlag l) { // v5 and above - stc(coproc, crd, dst, l, static_cast(nv)); -} - - -void Assembler::stc2(Coprocessor coproc, - CRegister crd, - Register rn, - int option, - LFlag l) { // v5 and above - stc(coproc, crd, rn, option, l, static_cast(nv)); -} - - -// Support for VFP. -void Assembler::vldr(const DwVfpRegister dst, - const Register base, - int offset, - const Condition cond) { - // Ddst = MEM(Rbase + offset). - // Instruction details available in ARM DDI 0406A, A8-628. - // cond(31-28) | 1101(27-24)| 1001(23-20) | Rbase(19-16) | - // Vdst(15-12) | 1011(11-8) | offset - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(offset % 4 == 0); - emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 | - 0xB*B8 | ((offset / 4) & 255)); -} - - -void Assembler::vstr(const DwVfpRegister src, - const Register base, - int offset, - const Condition cond) { - // MEM(Rbase + offset) = Dsrc. - // Instruction details available in ARM DDI 0406A, A8-786. - // cond(31-28) | 1101(27-24)| 1000(23-20) | | Rbase(19-16) | - // Vsrc(15-12) | 1011(11-8) | (offset/4) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(offset % 4 == 0); - emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 | - 0xB*B8 | ((offset / 4) & 255)); -} - - -void Assembler::vmov(const DwVfpRegister dst, - const Register src1, - const Register src2, - const Condition cond) { - // Dm = . - // Instruction details available in ARM DDI 0406A, A8-646. - // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) | - // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(!src1.is(pc) && !src2.is(pc)); - emit(cond | 0xC*B24 | B22 | src2.code()*B16 | - src1.code()*B12 | 0xB*B8 | B4 | dst.code()); -} - - -void Assembler::vmov(const Register dst1, - const Register dst2, - const DwVfpRegister src, - const Condition cond) { - // = Dm. - // Instruction details available in ARM DDI 0406A, A8-646. - // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) | - // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(!dst1.is(pc) && !dst2.is(pc)); - emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 | - dst1.code()*B12 | 0xB*B8 | B4 | src.code()); -} - - -void Assembler::vmov(const SwVfpRegister dst, - const Register src, - const Condition cond) { - // Sn = Rt. - // Instruction details available in ARM DDI 0406A, A8-642. - // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) | - // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(!src.is(pc)); - emit(cond | 0xE*B24 | (dst.code() >> 1)*B16 | - src.code()*B12 | 0xA*B8 | (0x1 & dst.code())*B7 | B4); -} - - -void Assembler::vmov(const Register dst, - const SwVfpRegister src, - const Condition cond) { - // Rt = Sn. - // Instruction details available in ARM DDI 0406A, A8-642. - // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) | - // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - ASSERT(!dst.is(pc)); - emit(cond | 0xE*B24 | B20 | (src.code() >> 1)*B16 | - dst.code()*B12 | 0xA*B8 | (0x1 & src.code())*B7 | B4); -} - - -void Assembler::vcvt(const DwVfpRegister dst, - const SwVfpRegister src, - const Condition cond) { - // Dd = Sm (integer in Sm converted to IEEE 64-bit doubles in Dd). - // Instruction details available in ARM DDI 0406A, A8-576. - // cond(31-28) | 11101(27-23)| D=?(22) | 11(21-20) | 1(19) | opc2=000(18-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | op(7)=1 | 1(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | B23 | 0x3*B20 | B19 | - dst.code()*B12 | 0x5*B9 | B8 | B7 | B6 | - (0x1 & src.code())*B5 | (src.code() >> 1)); -} - - -void Assembler::vcvt(const SwVfpRegister dst, - const DwVfpRegister src, - const Condition cond) { - // Sd = Dm (IEEE 64-bit doubles in Dm converted to 32 bit integer in Sd). - // Instruction details available in ARM DDI 0406A, A8-576. - // cond(31-28) | 11101(27-23)| D=?(22) | 11(21-20) | 1(19) | opc2=101(18-16)| - // Vd(15-12) | 101(11-9) | sz(8)=1 | op(7)=? | 1(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | B23 |(0x1 & dst.code())*B22 | - 0x3*B20 | B19 | 0x5*B16 | (dst.code() >> 1)*B12 | - 0x5*B9 | B8 | B7 | B6 | src.code()); -} - - -void Assembler::vadd(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond) { - // Dd = vadd(Dn, Dm) double precision floating point addition. - // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. - // Instruction details available in ARM DDI 0406A, A8-536. - // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 | - dst.code()*B12 | 0x5*B9 | B8 | src2.code()); -} - - -void Assembler::vsub(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond) { - // Dd = vsub(Dn, Dm) double precision floating point subtraction. - // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. - // Instruction details available in ARM DDI 0406A, A8-784. - // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 | - dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code()); -} - - -void Assembler::vmul(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond) { - // Dd = vmul(Dn, Dm) double precision floating point multiplication. - // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. - // Instruction details available in ARM DDI 0406A, A8-784. - // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 | - dst.code()*B12 | 0x5*B9 | B8 | src2.code()); -} - - -void Assembler::vdiv(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond) { - // Dd = vdiv(Dn, Dm) double precision floating point division. - // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. - // Instruction details available in ARM DDI 0406A, A8-584. - // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | B23 | src1.code()*B16 | - dst.code()*B12 | 0x5*B9 | B8 | src2.code()); -} - - -void Assembler::vcmp(const DwVfpRegister src1, - const DwVfpRegister src2, - const SBit s, - const Condition cond) { - // vcmp(Dd, Dm) double precision floating point comparison. - // Instruction details available in ARM DDI 0406A, A8-570. - // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) | - // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | Vm(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | - src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code()); -} - - -void Assembler::vmrs(Register dst, Condition cond) { - // Instruction details available in ARM DDI 0406A, A8-652. - // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) | - // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) - ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | 0xF*B20 | B16 | - dst.code()*B12 | 0xA*B8 | B4); -} - - -bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { - uint32_t dummy1; - uint32_t dummy2; - return fits_shifter(imm32, &dummy1, &dummy2, NULL); -} - - -void Assembler::BlockConstPoolFor(int instructions) { - BlockConstPoolBefore(pc_offset() + instructions * kInstrSize); -} - - -// Debugging. -void Assembler::RecordJSReturn() { - WriteRecordedPositions(); - CheckBuffer(); - RecordRelocInfo(RelocInfo::JS_RETURN); -} - - -void Assembler::RecordComment(const char* msg) { - if (FLAG_debug_code) { - CheckBuffer(); - RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast(msg)); - } -} - - -void Assembler::RecordPosition(int pos) { - if (pos == RelocInfo::kNoPosition) return; - ASSERT(pos >= 0); - current_position_ = pos; -} - - -void Assembler::RecordStatementPosition(int pos) { - if (pos == RelocInfo::kNoPosition) return; - ASSERT(pos >= 0); - current_statement_position_ = pos; -} - - -void Assembler::WriteRecordedPositions() { - // Write the statement position if it is different from what was written last - // time. - if (current_statement_position_ != written_statement_position_) { - CheckBuffer(); - RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_); - written_statement_position_ = current_statement_position_; - } - - // Write the position if it is different from what was written last time and - // also different from the written statement position. - if (current_position_ != written_position_ && - current_position_ != written_statement_position_) { - CheckBuffer(); - RecordRelocInfo(RelocInfo::POSITION, current_position_); - written_position_ = current_position_; - } -} - - -void Assembler::GrowBuffer() { - if (!own_buffer_) FATAL("external code buffer is too small"); - - // Compute new buffer size. - CodeDesc desc; // the new buffer - if (buffer_size_ < 4*KB) { - desc.buffer_size = 4*KB; - } else if (buffer_size_ < 1*MB) { - desc.buffer_size = 2*buffer_size_; - } else { - desc.buffer_size = buffer_size_ + 1*MB; - } - CHECK_GT(desc.buffer_size, 0); // no overflow - - // Setup new buffer. - desc.buffer = NewArray(desc.buffer_size); - - desc.instr_size = pc_offset(); - desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); - - // Copy the data. - int pc_delta = desc.buffer - buffer_; - int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); - memmove(desc.buffer, buffer_, desc.instr_size); - memmove(reloc_info_writer.pos() + rc_delta, - reloc_info_writer.pos(), desc.reloc_size); - - // Switch buffers. - DeleteArray(buffer_); - buffer_ = desc.buffer; - buffer_size_ = desc.buffer_size; - pc_ += pc_delta; - reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, - reloc_info_writer.last_pc() + pc_delta); - - // None of our relocation types are pc relative pointing outside the code - // buffer nor pc absolute pointing inside the code buffer, so there is no need - // to relocate any emitted relocation entries. - - // Relocate pending relocation entries. - for (int i = 0; i < num_prinfo_; i++) { - RelocInfo& rinfo = prinfo_[i]; - ASSERT(rinfo.rmode() != RelocInfo::COMMENT && - rinfo.rmode() != RelocInfo::POSITION); - if (rinfo.rmode() != RelocInfo::JS_RETURN) { - rinfo.set_pc(rinfo.pc() + pc_delta); - } - } -} - - -void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { - RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants - if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::STATEMENT_POSITION) { - // Adjust code for new modes. - ASSERT(RelocInfo::IsJSReturn(rmode) - || RelocInfo::IsComment(rmode) - || RelocInfo::IsPosition(rmode)); - // These modes do not need an entry in the constant pool. - } else { - ASSERT(num_prinfo_ < kMaxNumPRInfo); - prinfo_[num_prinfo_++] = rinfo; - // Make sure the constant pool is not emitted in place of the next - // instruction for which we just recorded relocation info. - BlockConstPoolBefore(pc_offset() + kInstrSize); - } - if (rinfo.rmode() != RelocInfo::NONE) { - // Don't record external references unless the heap will be serialized. - if (rmode == RelocInfo::EXTERNAL_REFERENCE) { -#ifdef DEBUG - if (!Serializer::enabled()) { - Serializer::TooLateToEnableNow(); - } -#endif - if (!Serializer::enabled() && !FLAG_debug_code) { - return; - } - } - ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here - reloc_info_writer.Write(&rinfo); - } -} - - -void Assembler::CheckConstPool(bool force_emit, bool require_jump) { - // Calculate the offset of the next check. It will be overwritten - // when a const pool is generated or when const pools are being - // blocked for a specific range. - next_buffer_check_ = pc_offset() + kCheckConstInterval; - - // There is nothing to do if there are no pending relocation info entries. - if (num_prinfo_ == 0) return; - - // We emit a constant pool at regular intervals of about kDistBetweenPools - // or when requested by parameter force_emit (e.g. after each function). - // We prefer not to emit a jump unless the max distance is reached or if we - // are running low on slots, which can happen if a lot of constants are being - // emitted (e.g. --debug-code and many static references). - int dist = pc_offset() - last_const_pool_end_; - if (!force_emit && dist < kMaxDistBetweenPools && - (require_jump || dist < kDistBetweenPools) && - // TODO(1236125): Cleanup the "magic" number below. We know that - // the code generation will test every kCheckConstIntervalInst. - // Thus we are safe as long as we generate less than 7 constant - // entries per instruction. - (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) { - return; - } - - // If we did not return by now, we need to emit the constant pool soon. - - // However, some small sequences of instructions must not be broken up by the - // insertion of a constant pool; such sequences are protected by setting - // no_const_pool_before_, which is checked here. Also, recursive calls to - // CheckConstPool are blocked by no_const_pool_before_. - if (pc_offset() < no_const_pool_before_) { - // Emission is currently blocked; make sure we try again as soon as - // possible. - next_buffer_check_ = no_const_pool_before_; - - // Something is wrong if emission is forced and blocked at the same time. - ASSERT(!force_emit); - return; - } - - int jump_instr = require_jump ? kInstrSize : 0; - - // Check that the code buffer is large enough before emitting the constant - // pool and relocation information (include the jump over the pool and the - // constant pool marker). - int max_needed_space = - jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize); - while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer(); - - // Block recursive calls to CheckConstPool. - BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize + - num_prinfo_*kInstrSize); - // Don't bother to check for the emit calls below. - next_buffer_check_ = no_const_pool_before_; - - // Emit jump over constant pool if necessary. - Label after_pool; - if (require_jump) b(&after_pool); - - RecordComment("[ Constant Pool"); - - // Put down constant pool marker "Undefined instruction" as specified by - // A3.1 Instruction set encoding. - emit(0x03000000 | num_prinfo_); - - // Emit constant pool entries. - for (int i = 0; i < num_prinfo_; i++) { - RelocInfo& rinfo = prinfo_[i]; - ASSERT(rinfo.rmode() != RelocInfo::COMMENT && - rinfo.rmode() != RelocInfo::POSITION && - rinfo.rmode() != RelocInfo::STATEMENT_POSITION); - Instr instr = instr_at(rinfo.pc()); - - // Instruction to patch must be a ldr/str [pc, #offset]. - // P and U set, B and W clear, Rn == pc, offset12 still 0. - ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | Off12Mask)) == - (2*B25 | P | U | pc.code()*B16)); - int delta = pc_ - rinfo.pc() - 8; - ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32 - if (delta < 0) { - instr &= ~U; - delta = -delta; - } - ASSERT(is_uint12(delta)); - instr_at_put(rinfo.pc(), instr + delta); - emit(rinfo.data()); - } - num_prinfo_ = 0; - last_const_pool_end_ = pc_offset(); - - RecordComment("]"); - - if (after_pool.is_linked()) { - bind(&after_pool); - } - - // Since a constant pool was just emitted, move the check offset forward by - // the standard interval. - next_buffer_check_ = pc_offset() + kCheckConstInterval; -} - - -} } // namespace v8::internal - -#endif // V8_TARGET_ARCH_ARM && V8_ARM_VARIANT_THUMB diff --git a/src/arm/assembler-thumb2.h b/src/arm/assembler-thumb2.h deleted file mode 100644 index c3bc4a8..0000000 --- a/src/arm/assembler-thumb2.h +++ /dev/null @@ -1,1028 +0,0 @@ -// Copyright (c) 1994-2006 Sun Microsystems 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: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// - Redistribution 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. -// -// - Neither the name of Sun Microsystems or the names of contributors may -// be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE -// COPYRIGHT OWNER 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. - -// The original source code covered by the above license above has been -// modified significantly by Google Inc. -// Copyright 2010 the V8 project authors. All rights reserved. - -// A light-weight ARM Assembler -// Generates user mode instructions for the ARM architecture up to version 5 - -#ifndef V8_ARM_ASSEMBLER_THUMB2_H_ -#define V8_ARM_ASSEMBLER_THUMB2_H_ -#include -#include "assembler.h" -#include "serialize.h" - -namespace v8 { -namespace internal { - -// CPU Registers. -// -// 1) We would prefer to use an enum, but enum values are assignment- -// compatible with int, which has caused code-generation bugs. -// -// 2) We would prefer to use a class instead of a struct but we don't like -// the register initialization to depend on the particular initialization -// order (which appears to be different on OS X, Linux, and Windows for the -// installed versions of C++ we tried). Using a struct permits C-style -// "initialization". Also, the Register objects cannot be const as this -// forces initialization stubs in MSVC, making us dependent on initialization -// order. -// -// 3) By not using an enum, we are possibly preventing the compiler from -// doing certain constant folds, which may significantly reduce the -// code generated for some assembly instructions (because they boil down -// to a few constants). If this is a problem, we could change the code -// such that we use an enum in optimized mode, and the struct in debug -// mode. This way we get the compile-time error checking in debug mode -// and best performance in optimized code. -// -// Core register -struct Register { - bool is_valid() const { return 0 <= code_ && code_ < 16; } - bool is(Register reg) const { return code_ == reg.code_; } - int code() const { - ASSERT(is_valid()); - return code_; - } - int bit() const { - ASSERT(is_valid()); - return 1 << code_; - } - - // Unfortunately we can't make this private in a struct. - int code_; -}; - - -extern Register no_reg; -extern Register r0; -extern Register r1; -extern Register r2; -extern Register r3; -extern Register r4; -extern Register r5; -extern Register r6; -extern Register r7; -extern Register r8; -extern Register r9; -extern Register r10; -extern Register fp; -extern Register ip; -extern Register sp; -extern Register lr; -extern Register pc; - - -// Single word VFP register. -struct SwVfpRegister { - bool is_valid() const { return 0 <= code_ && code_ < 32; } - bool is(SwVfpRegister reg) const { return code_ == reg.code_; } - int code() const { - ASSERT(is_valid()); - return code_; - } - int bit() const { - ASSERT(is_valid()); - return 1 << code_; - } - - int code_; -}; - - -// Double word VFP register. -struct DwVfpRegister { - // Supporting d0 to d15, can be later extended to d31. - bool is_valid() const { return 0 <= code_ && code_ < 16; } - bool is(DwVfpRegister reg) const { return code_ == reg.code_; } - int code() const { - ASSERT(is_valid()); - return code_; - } - int bit() const { - ASSERT(is_valid()); - return 1 << code_; - } - - int code_; -}; - - -// Support for VFP registers s0 to s31 (d0 to d15). -// Note that "s(N):s(N+1)" is the same as "d(N/2)". -extern SwVfpRegister s0; -extern SwVfpRegister s1; -extern SwVfpRegister s2; -extern SwVfpRegister s3; -extern SwVfpRegister s4; -extern SwVfpRegister s5; -extern SwVfpRegister s6; -extern SwVfpRegister s7; -extern SwVfpRegister s8; -extern SwVfpRegister s9; -extern SwVfpRegister s10; -extern SwVfpRegister s11; -extern SwVfpRegister s12; -extern SwVfpRegister s13; -extern SwVfpRegister s14; -extern SwVfpRegister s15; -extern SwVfpRegister s16; -extern SwVfpRegister s17; -extern SwVfpRegister s18; -extern SwVfpRegister s19; -extern SwVfpRegister s20; -extern SwVfpRegister s21; -extern SwVfpRegister s22; -extern SwVfpRegister s23; -extern SwVfpRegister s24; -extern SwVfpRegister s25; -extern SwVfpRegister s26; -extern SwVfpRegister s27; -extern SwVfpRegister s28; -extern SwVfpRegister s29; -extern SwVfpRegister s30; -extern SwVfpRegister s31; - -extern DwVfpRegister d0; -extern DwVfpRegister d1; -extern DwVfpRegister d2; -extern DwVfpRegister d3; -extern DwVfpRegister d4; -extern DwVfpRegister d5; -extern DwVfpRegister d6; -extern DwVfpRegister d7; -extern DwVfpRegister d8; -extern DwVfpRegister d9; -extern DwVfpRegister d10; -extern DwVfpRegister d11; -extern DwVfpRegister d12; -extern DwVfpRegister d13; -extern DwVfpRegister d14; -extern DwVfpRegister d15; - - -// Coprocessor register -struct CRegister { - bool is_valid() const { return 0 <= code_ && code_ < 16; } - bool is(CRegister creg) const { return code_ == creg.code_; } - int code() const { - ASSERT(is_valid()); - return code_; - } - int bit() const { - ASSERT(is_valid()); - return 1 << code_; - } - - // Unfortunately we can't make this private in a struct. - int code_; -}; - - -extern CRegister no_creg; -extern CRegister cr0; -extern CRegister cr1; -extern CRegister cr2; -extern CRegister cr3; -extern CRegister cr4; -extern CRegister cr5; -extern CRegister cr6; -extern CRegister cr7; -extern CRegister cr8; -extern CRegister cr9; -extern CRegister cr10; -extern CRegister cr11; -extern CRegister cr12; -extern CRegister cr13; -extern CRegister cr14; -extern CRegister cr15; - - -// Coprocessor number -enum Coprocessor { - p0 = 0, - p1 = 1, - p2 = 2, - p3 = 3, - p4 = 4, - p5 = 5, - p6 = 6, - p7 = 7, - p8 = 8, - p9 = 9, - p10 = 10, - p11 = 11, - p12 = 12, - p13 = 13, - p14 = 14, - p15 = 15 -}; - - -// Condition field in instructions. -enum Condition { - eq = 0 << 28, // Z set equal. - ne = 1 << 28, // Z clear not equal. - nz = 1 << 28, // Z clear not zero. - cs = 2 << 28, // C set carry set. - hs = 2 << 28, // C set unsigned higher or same. - cc = 3 << 28, // C clear carry clear. - lo = 3 << 28, // C clear unsigned lower. - mi = 4 << 28, // N set negative. - pl = 5 << 28, // N clear positive or zero. - vs = 6 << 28, // V set overflow. - vc = 7 << 28, // V clear no overflow. - hi = 8 << 28, // C set, Z clear unsigned higher. - ls = 9 << 28, // C clear or Z set unsigned lower or same. - ge = 10 << 28, // N == V greater or equal. - lt = 11 << 28, // N != V less than. - gt = 12 << 28, // Z clear, N == V greater than. - le = 13 << 28, // Z set or N != V less then or equal - al = 14 << 28 // always. -}; - - -// Returns the equivalent of !cc. -INLINE(Condition NegateCondition(Condition cc)); - - -// Corresponds to transposing the operands of a comparison. -inline Condition ReverseCondition(Condition cc) { - switch (cc) { - case lo: - return hi; - case hi: - return lo; - case hs: - return ls; - case ls: - return hs; - case lt: - return gt; - case gt: - return lt; - case ge: - return le; - case le: - return ge; - default: - return cc; - }; -} - - -// Branch hints are not used on the ARM. They are defined so that they can -// appear in shared function signatures, but will be ignored in ARM -// implementations. -enum Hint { no_hint }; - -// Hints are not used on the arm. Negating is trivial. -inline Hint NegateHint(Hint ignored) { return no_hint; } - - -// ----------------------------------------------------------------------------- -// Addressing modes and instruction variants - -// Shifter operand shift operation -enum ShiftOp { - LSL = 0 << 5, - LSR = 1 << 5, - ASR = 2 << 5, - ROR = 3 << 5, - RRX = -1 -}; - - -// Condition code updating mode -enum SBit { - SetCC = 1 << 20, // set condition code - LeaveCC = 0 << 20 // leave condition code unchanged -}; - - -// Status register selection -enum SRegister { - CPSR = 0 << 22, - SPSR = 1 << 22 -}; - - -// Status register fields -enum SRegisterField { - CPSR_c = CPSR | 1 << 16, - CPSR_x = CPSR | 1 << 17, - CPSR_s = CPSR | 1 << 18, - CPSR_f = CPSR | 1 << 19, - SPSR_c = SPSR | 1 << 16, - SPSR_x = SPSR | 1 << 17, - SPSR_s = SPSR | 1 << 18, - SPSR_f = SPSR | 1 << 19 -}; - -// Status register field mask (or'ed SRegisterField enum values) -typedef uint32_t SRegisterFieldMask; - - -// Memory operand addressing mode -enum AddrMode { - // bit encoding P U W - Offset = (8|4|0) << 21, // offset (without writeback to base) - PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback - PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback - NegOffset = (8|0|0) << 21, // negative offset (without writeback to base) - NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback - NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback -}; - - -// Load/store multiple addressing mode -enum BlockAddrMode { - // bit encoding P U W - da = (0|0|0) << 21, // decrement after - ia = (0|4|0) << 21, // increment after - db = (8|0|0) << 21, // decrement before - ib = (8|4|0) << 21, // increment before - da_w = (0|0|1) << 21, // decrement after with writeback to base - ia_w = (0|4|1) << 21, // increment after with writeback to base - db_w = (8|0|1) << 21, // decrement before with writeback to base - ib_w = (8|4|1) << 21 // increment before with writeback to base -}; - - -// Coprocessor load/store operand size -enum LFlag { - Long = 1 << 22, // long load/store coprocessor - Short = 0 << 22 // short load/store coprocessor -}; - - -// ----------------------------------------------------------------------------- -// Machine instruction Operands - -// Class Operand represents a shifter operand in data processing instructions -class Operand BASE_EMBEDDED { - public: - // immediate - INLINE(explicit Operand(int32_t immediate, - RelocInfo::Mode rmode = RelocInfo::NONE)); - INLINE(explicit Operand(const ExternalReference& f)); - INLINE(explicit Operand(const char* s)); - explicit Operand(Handle handle); - INLINE(explicit Operand(Smi* value)); - - // rm - INLINE(explicit Operand(Register rm)); - - // rm shift_imm - explicit Operand(Register rm, ShiftOp shift_op, int shift_imm); - - // rm rs - explicit Operand(Register rm, ShiftOp shift_op, Register rs); - - // Return true if this is a register operand. - INLINE(bool is_reg() const); - - Register rm() const { return rm_; } - - private: - Register rm_; - Register rs_; - ShiftOp shift_op_; - int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg - int32_t imm32_; // valid if rm_ == no_reg - RelocInfo::Mode rmode_; - - friend class Assembler; -}; - - -// Class MemOperand represents a memory operand in load and store instructions -class MemOperand BASE_EMBEDDED { - public: - // [rn +/- offset] Offset/NegOffset - // [rn +/- offset]! PreIndex/NegPreIndex - // [rn], +/- offset PostIndex/NegPostIndex - // offset is any signed 32-bit value; offset is first loaded to register ip if - // it does not fit the addressing mode (12-bit unsigned and sign bit) - explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset); - - // [rn +/- rm] Offset/NegOffset - // [rn +/- rm]! PreIndex/NegPreIndex - // [rn], +/- rm PostIndex/NegPostIndex - explicit MemOperand(Register rn, Register rm, AddrMode am = Offset); - - // [rn +/- rm shift_imm] Offset/NegOffset - // [rn +/- rm shift_imm]! PreIndex/NegPreIndex - // [rn], +/- rm shift_imm PostIndex/NegPostIndex - explicit MemOperand(Register rn, Register rm, - ShiftOp shift_op, int shift_imm, AddrMode am = Offset); - - private: - Register rn_; // base - Register rm_; // register offset - int32_t offset_; // valid if rm_ == no_reg - ShiftOp shift_op_; - int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg - AddrMode am_; // bits P, U, and W - - friend class Assembler; -}; - -// CpuFeatures keeps track of which features are supported by the target CPU. -// Supported features must be enabled by a Scope before use. -class CpuFeatures : public AllStatic { - public: - // Detect features of the target CPU. Set safe defaults if the serializer - // is enabled (snapshots must be portable). - static void Probe(); - - // Check whether a feature is supported by the target CPU. - static bool IsSupported(CpuFeature f) { - if (f == VFP3 && !FLAG_enable_vfp3) return false; - return (supported_ & (1u << f)) != 0; - } - - // Check whether a feature is currently enabled. - static bool IsEnabled(CpuFeature f) { - return (enabled_ & (1u << f)) != 0; - } - - // Enable a specified feature within a scope. - class Scope BASE_EMBEDDED { -#ifdef DEBUG - public: - explicit Scope(CpuFeature f) { - ASSERT(CpuFeatures::IsSupported(f)); - ASSERT(!Serializer::enabled() || - (found_by_runtime_probing_ & (1u << f)) == 0); - old_enabled_ = CpuFeatures::enabled_; - CpuFeatures::enabled_ |= 1u << f; - } - ~Scope() { CpuFeatures::enabled_ = old_enabled_; } - private: - unsigned old_enabled_; -#else - public: - explicit Scope(CpuFeature f) {} -#endif - }; - - private: - static unsigned supported_; - static unsigned enabled_; - static unsigned found_by_runtime_probing_; -}; - - -typedef int32_t Instr; - - -extern const Instr kMovLrPc; -extern const Instr kLdrPCPattern; - - -class Assembler : public Malloced { - public: - // Create an assembler. Instructions and relocation information are emitted - // into a buffer, with the instructions starting from the beginning and the - // relocation information starting from the end of the buffer. See CodeDesc - // for a detailed comment on the layout (globals.h). - // - // If the provided buffer is NULL, the assembler allocates and grows its own - // buffer, and buffer_size determines the initial buffer size. The buffer is - // owned by the assembler and deallocated upon destruction of the assembler. - // - // If the provided buffer is not NULL, the assembler uses the provided buffer - // for code generation and assumes its size to be buffer_size. If the buffer - // is too small, a fatal error occurs. No deallocation of the buffer is done - // upon destruction of the assembler. - Assembler(void* buffer, int buffer_size); - ~Assembler(); - - // GetCode emits any pending (non-emitted) code and fills the descriptor - // desc. GetCode() is idempotent; it returns the same result if no other - // Assembler functions are invoked in between GetCode() calls. - void GetCode(CodeDesc* desc); - - // Label operations & relative jumps (PPUM Appendix D) - // - // Takes a branch opcode (cc) and a label (L) and generates - // either a backward branch or a forward branch and links it - // to the label fixup chain. Usage: - // - // Label L; // unbound label - // j(cc, &L); // forward branch to unbound label - // bind(&L); // bind label to the current pc - // j(cc, &L); // backward branch to bound label - // bind(&L); // illegal: a label may be bound only once - // - // Note: The same Label can be used for forward and backward branches - // but it may be bound only once. - - void bind(Label* L); // binds an unbound label L to the current code position - - // Returns the branch offset to the given label from the current code position - // Links the label to the current position if it is still unbound - // Manages the jump elimination optimization if the second parameter is true. - int branch_offset(Label* L, bool jump_elimination_allowed); - - // Puts a labels target address at the given position. - // The high 8 bits are set to zero. - void label_at_put(Label* L, int at_offset); - - // Return the address in the constant pool of the code target address used by - // the branch/call instruction at pc. - INLINE(static Address target_address_address_at(Address pc)); - - // Read/Modify the code target address in the branch/call instruction at pc. - INLINE(static Address target_address_at(Address pc)); - INLINE(static void set_target_address_at(Address pc, Address target)); - - // This sets the branch destination (which is in the constant pool on ARM). - // This is for calls and branches within generated code. - inline static void set_target_at(Address constant_pool_entry, Address target); - - // This sets the branch destination (which is in the constant pool on ARM). - // This is for calls and branches to runtime code. - inline static void set_external_target_at(Address constant_pool_entry, - Address target) { - set_target_at(constant_pool_entry, target); - } - - // Here we are patching the address in the constant pool, not the actual call - // instruction. The address in the constant pool is the same size as a - // pointer. - static const int kCallTargetSize = kPointerSize; - static const int kExternalTargetSize = kPointerSize; - - // Size of an instruction. - static const int kInstrSize = sizeof(Instr); - - // Distance between the instruction referring to the address of the call - // target (ldr pc, [target addr in const pool]) and the return address - static const int kCallTargetAddressOffset = kInstrSize; - - // Distance between start of patched return sequence and the emitted address - // to jump to. - static const int kPatchReturnSequenceAddressOffset = kInstrSize; - - // Difference between address of current opcode and value read from pc - // register. - static const int kPcLoadDelta = 8; - - static const int kJSReturnSequenceLength = 4; - - // --------------------------------------------------------------------------- - // Code generation - - // Insert the smallest number of nop instructions - // possible to align the pc offset to a multiple - // of m. m must be a power of 2 (>= 4). - void Align(int m); - - // Branch instructions - void b(int branch_offset, Condition cond = al); - void bl(int branch_offset, Condition cond = al); - void blx(int branch_offset); // v5 and above - void blx(Register target, Condition cond = al); // v5 and above - void bx(Register target, Condition cond = al); // v5 and above, plus v4t - - // Convenience branch instructions using labels - void b(Label* L, Condition cond = al) { - b(branch_offset(L, cond == al), cond); - } - void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); } - void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); } - void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); } - void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above - - // Data-processing instructions - void ubfx(Register dst, Register src1, const Operand& src2, - const Operand& src3, Condition cond = al); - - void and_(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void eor(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void sub(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - void sub(Register dst, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al) { - sub(dst, src1, Operand(src2), s, cond); - } - - void rsb(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void add(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void adc(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void sbc(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void rsc(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void tst(Register src1, const Operand& src2, Condition cond = al); - void tst(Register src1, Register src2, Condition cond = al) { - tst(src1, Operand(src2), cond); - } - - void teq(Register src1, const Operand& src2, Condition cond = al); - - void cmp(Register src1, const Operand& src2, Condition cond = al); - void cmp(Register src1, Register src2, Condition cond = al) { - cmp(src1, Operand(src2), cond); - } - - void cmn(Register src1, const Operand& src2, Condition cond = al); - - void orr(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - void orr(Register dst, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al) { - orr(dst, src1, Operand(src2), s, cond); - } - - void mov(Register dst, const Operand& src, - SBit s = LeaveCC, Condition cond = al); - void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) { - mov(dst, Operand(src), s, cond); - } - - void bic(Register dst, Register src1, const Operand& src2, - SBit s = LeaveCC, Condition cond = al); - - void mvn(Register dst, const Operand& src, - SBit s = LeaveCC, Condition cond = al); - - // Multiply instructions - - void mla(Register dst, Register src1, Register src2, Register srcA, - SBit s = LeaveCC, Condition cond = al); - - void mul(Register dst, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al); - - void smlal(Register dstL, Register dstH, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al); - - void smull(Register dstL, Register dstH, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al); - - void umlal(Register dstL, Register dstH, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al); - - void umull(Register dstL, Register dstH, Register src1, Register src2, - SBit s = LeaveCC, Condition cond = al); - - // Miscellaneous arithmetic instructions - - void clz(Register dst, Register src, Condition cond = al); // v5 and above - - // Status register access instructions - - void mrs(Register dst, SRegister s, Condition cond = al); - void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al); - - // Load/Store instructions - void ldr(Register dst, const MemOperand& src, Condition cond = al); - void str(Register src, const MemOperand& dst, Condition cond = al); - void ldrb(Register dst, const MemOperand& src, Condition cond = al); - void strb(Register src, const MemOperand& dst, Condition cond = al); - void ldrh(Register dst, const MemOperand& src, Condition cond = al); - void strh(Register src, const MemOperand& dst, Condition cond = al); - void ldrsb(Register dst, const MemOperand& src, Condition cond = al); - void ldrsh(Register dst, const MemOperand& src, Condition cond = al); - - // Load/Store multiple instructions - void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al); - void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); - - // Exception-generating instructions and debugging support - void stop(const char* msg); - - void bkpt(uint32_t imm16); // v5 and above - void swi(uint32_t imm24, Condition cond = al); - - // Coprocessor instructions - - void cdp(Coprocessor coproc, int opcode_1, - CRegister crd, CRegister crn, CRegister crm, - int opcode_2, Condition cond = al); - - void cdp2(Coprocessor coproc, int opcode_1, - CRegister crd, CRegister crn, CRegister crm, - int opcode_2); // v5 and above - - void mcr(Coprocessor coproc, int opcode_1, - Register rd, CRegister crn, CRegister crm, - int opcode_2 = 0, Condition cond = al); - - void mcr2(Coprocessor coproc, int opcode_1, - Register rd, CRegister crn, CRegister crm, - int opcode_2 = 0); // v5 and above - - void mrc(Coprocessor coproc, int opcode_1, - Register rd, CRegister crn, CRegister crm, - int opcode_2 = 0, Condition cond = al); - - void mrc2(Coprocessor coproc, int opcode_1, - Register rd, CRegister crn, CRegister crm, - int opcode_2 = 0); // v5 and above - - void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src, - LFlag l = Short, Condition cond = al); - void ldc(Coprocessor coproc, CRegister crd, Register base, int option, - LFlag l = Short, Condition cond = al); - - void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, - LFlag l = Short); // v5 and above - void ldc2(Coprocessor coproc, CRegister crd, Register base, int option, - LFlag l = Short); // v5 and above - - void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst, - LFlag l = Short, Condition cond = al); - void stc(Coprocessor coproc, CRegister crd, Register base, int option, - LFlag l = Short, Condition cond = al); - - void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst, - LFlag l = Short); // v5 and above - void stc2(Coprocessor coproc, CRegister crd, Register base, int option, - LFlag l = Short); // v5 and above - - // Support for VFP. - // All these APIs support S0 to S31 and D0 to D15. - // Currently these APIs do not support extended D registers, i.e, D16 to D31. - // However, some simple modifications can allow - // these APIs to support D16 to D31. - - void vldr(const DwVfpRegister dst, - const Register base, - int offset, // Offset must be a multiple of 4. - const Condition cond = al); - void vstr(const DwVfpRegister src, - const Register base, - int offset, // Offset must be a multiple of 4. - const Condition cond = al); - void vmov(const DwVfpRegister dst, - const Register src1, - const Register src2, - const Condition cond = al); - void vmov(const Register dst1, - const Register dst2, - const DwVfpRegister src, - const Condition cond = al); - void vmov(const SwVfpRegister dst, - const Register src, - const Condition cond = al); - void vmov(const Register dst, - const SwVfpRegister src, - const Condition cond = al); - void vcvt(const DwVfpRegister dst, - const SwVfpRegister src, - const Condition cond = al); - void vcvt(const SwVfpRegister dst, - const DwVfpRegister src, - const Condition cond = al); - - void vadd(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond = al); - void vsub(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond = al); - void vmul(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond = al); - void vdiv(const DwVfpRegister dst, - const DwVfpRegister src1, - const DwVfpRegister src2, - const Condition cond = al); - void vcmp(const DwVfpRegister src1, - const DwVfpRegister src2, - const SBit s = LeaveCC, - const Condition cond = al); - void vmrs(const Register dst, - const Condition cond = al); - - // Pseudo instructions - void nop() { mov(r0, Operand(r0)); } - - void push(Register src, Condition cond = al) { - str(src, MemOperand(sp, 4, NegPreIndex), cond); - } - - void pop(Register dst, Condition cond = al) { - ldr(dst, MemOperand(sp, 4, PostIndex), cond); - } - - void pop() { - add(sp, sp, Operand(kPointerSize)); - } - - // Jump unconditionally to given label. - void jmp(Label* L) { b(L, al); } - - // Check the code size generated from label to here. - int InstructionsGeneratedSince(Label* l) { - return (pc_offset() - l->pos()) / kInstrSize; - } - - // Check whether an immediate fits an addressing mode 1 instruction. - bool ImmediateFitsAddrMode1Instruction(int32_t imm32); - - // Postpone the generation of the constant pool for the specified number of - // instructions. - void BlockConstPoolFor(int instructions); - - // Debugging - - // Mark address of the ExitJSFrame code. - void RecordJSReturn(); - - // Record a comment relocation entry that can be used by a disassembler. - // Use --debug_code to enable. - void RecordComment(const char* msg); - - void RecordPosition(int pos); - void RecordStatementPosition(int pos); - void WriteRecordedPositions(); - - int pc_offset() const { return pc_ - buffer_; } - int current_position() const { return current_position_; } - int current_statement_position() const { return current_statement_position_; } - - protected: - int buffer_space() const { return reloc_info_writer.pos() - pc_; } - - // Read/patch instructions - static Instr instr_at(byte* pc) { return *reinterpret_cast(pc); } - void instr_at_put(byte* pc, Instr instr) { - *reinterpret_cast(pc) = instr; - } - Instr instr_at(int pos) { return *reinterpret_cast(buffer_ + pos); } - void instr_at_put(int pos, Instr instr) { - *reinterpret_cast(buffer_ + pos) = instr; - } - - // Decode branch instruction at pos and return branch target pos - int target_at(int pos); - - // Patch branch instruction at pos to branch to given branch target pos - void target_at_put(int pos, int target_pos); - - // Check if is time to emit a constant pool for pending reloc info entries - void CheckConstPool(bool force_emit, bool require_jump); - - // Block the emission of the constant pool before pc_offset - void BlockConstPoolBefore(int pc_offset) { - if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset; - } - - private: - // Code buffer: - // The buffer into which code and relocation info are generated. - byte* buffer_; - int buffer_size_; - // True if the assembler owns the buffer, false if buffer is external. - bool own_buffer_; - - // Buffer size and constant pool distance are checked together at regular - // intervals of kBufferCheckInterval emitted bytes - static const int kBufferCheckInterval = 1*KB/2; - int next_buffer_check_; // pc offset of next buffer check - - // Code generation - // The relocation writer's position is at least kGap bytes below the end of - // the generated instructions. This is so that multi-instruction sequences do - // not have to check for overflow. The same is true for writes of large - // relocation info entries. - static const int kGap = 32; - byte* pc_; // the program counter; moves forward - - // Constant pool generation - // Pools are emitted in the instruction stream, preferably after unconditional - // jumps or after returns from functions (in dead code locations). - // If a long code sequence does not contain unconditional jumps, it is - // necessary to emit the constant pool before the pool gets too far from the - // location it is accessed from. In this case, we emit a jump over the emitted - // constant pool. - // Constants in the pool may be addresses of functions that gets relocated; - // if so, a relocation info entry is associated to the constant pool entry. - - // Repeated checking whether the constant pool should be emitted is rather - // expensive. By default we only check again once a number of instructions - // has been generated. That also means that the sizing of the buffers is not - // an exact science, and that we rely on some slop to not overrun buffers. - static const int kCheckConstIntervalInst = 32; - static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize; - - - // Pools are emitted after function return and in dead code at (more or less) - // regular intervals of kDistBetweenPools bytes - static const int kDistBetweenPools = 1*KB; - - // Constants in pools are accessed via pc relative addressing, which can - // reach +/-4KB thereby defining a maximum distance between the instruction - // and the accessed constant. We satisfy this constraint by limiting the - // distance between pools. - static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval; - - // Emission of the constant pool may be blocked in some code sequences - int no_const_pool_before_; // block emission before this pc offset - - // Keep track of the last emitted pool to guarantee a maximal distance - int last_const_pool_end_; // pc offset following the last constant pool - - // Relocation info generation - // Each relocation is encoded as a variable size value - static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; - RelocInfoWriter reloc_info_writer; - // Relocation info records are also used during code generation as temporary - // containers for constants and code target addresses until they are emitted - // to the constant pool. These pending relocation info records are temporarily - // stored in a separate buffer until a constant pool is emitted. - // If every instruction in a long sequence is accessing the pool, we need one - // pending relocation entry per instruction. - static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize; - RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info - int num_prinfo_; // number of pending reloc info entries in the buffer - - // The bound position, before this we cannot do instruction elimination. - int last_bound_pos_; - - // source position information - int current_position_; - int current_statement_position_; - int written_position_; - int written_statement_position_; - - // Code emission - inline void CheckBuffer(); - void GrowBuffer(); - inline void emit(Instr x); - - // Instruction generation - void addrmod1(Instr instr, Register rn, Register rd, const Operand& x); - void addrmod2(Instr instr, Register rd, const MemOperand& x); - void addrmod3(Instr instr, Register rd, const MemOperand& x); - void addrmod4(Instr instr, Register rn, RegList rl); - void addrmod5(Instr instr, CRegister crd, const MemOperand& x); - - // Labels - void print(Label* L); - void bind_to(Label* L, int pos); - void link_to(Label* L, Label* appendix); - void next(Label* L); - - // Record reloc info for current pc_ - void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); - - friend class RegExpMacroAssemblerARM; - friend class RelocInfo; - friend class CodePatcher; -}; - -} } // namespace v8::internal - -#endif // V8_ARM_ASSEMBLER_THUMB2_H_ diff --git a/src/arm/frames-arm.cc b/src/arm/frames-arm.cc index e564e83..271e4a6 100644 --- a/src/arm/frames-arm.cc +++ b/src/arm/frames-arm.cc @@ -30,11 +30,7 @@ #if defined(V8_TARGET_ARCH_ARM) #include "frames-inl.h" -#ifdef V8_ARM_VARIANT_THUMB -#include "arm/assembler-thumb2-inl.h" -#else #include "arm/assembler-arm-inl.h" -#endif namespace v8 { diff --git a/src/macro-assembler.h b/src/macro-assembler.h index a21e960..686a61c 100644 --- a/src/macro-assembler.h +++ b/src/macro-assembler.h @@ -68,13 +68,8 @@ const int kInvalidProtoDepth = -1; #elif V8_TARGET_ARCH_ARM #include "arm/constants-arm.h" #include "assembler.h" -#ifdef V8_ARM_VARIANT_THUMB -#include "arm/assembler-thumb2.h" -#include "arm/assembler-thumb2-inl.h" -#else #include "arm/assembler-arm.h" #include "arm/assembler-arm-inl.h" -#endif #include "code.h" // must be after assembler_*.h #include "arm/macro-assembler-arm.h" #elif V8_TARGET_ARCH_MIPS diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj index 1e9d1e7..46aba8d 100644 --- a/tools/v8.xcodeproj/project.pbxproj +++ b/tools/v8.xcodeproj/project.pbxproj @@ -237,7 +237,6 @@ 9FA38BC51175B2E500C4CD55 /* full-codegen-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BC21175B2E500C4CD55 /* full-codegen-ia32.cc */; }; 9FA38BC61175B2E500C4CD55 /* jump-target-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BC31175B2E500C4CD55 /* jump-target-ia32.cc */; }; 9FA38BC71175B2E500C4CD55 /* virtual-frame-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BC41175B2E500C4CD55 /* virtual-frame-ia32.cc */; }; - 9FA38BCE1175B30400C4CD55 /* assembler-thumb2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BC91175B30400C4CD55 /* assembler-thumb2.cc */; }; 9FA38BCF1175B30400C4CD55 /* full-codegen-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */; }; 9FA38BD01175B30400C4CD55 /* jump-target-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */; }; 9FA38BD11175B30400C4CD55 /* virtual-frame-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */; }; @@ -619,9 +618,6 @@ 9FA38BC21175B2E500C4CD55 /* full-codegen-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "full-codegen-ia32.cc"; path = "ia32/full-codegen-ia32.cc"; sourceTree = ""; }; 9FA38BC31175B2E500C4CD55 /* jump-target-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "jump-target-ia32.cc"; path = "ia32/jump-target-ia32.cc"; sourceTree = ""; }; 9FA38BC41175B2E500C4CD55 /* virtual-frame-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "virtual-frame-ia32.cc"; path = "ia32/virtual-frame-ia32.cc"; sourceTree = ""; }; - 9FA38BC81175B30400C4CD55 /* assembler-thumb2-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-thumb2-inl.h"; path = "arm/assembler-thumb2-inl.h"; sourceTree = ""; }; - 9FA38BC91175B30400C4CD55 /* assembler-thumb2.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "assembler-thumb2.cc"; path = "arm/assembler-thumb2.cc"; sourceTree = ""; }; - 9FA38BCA1175B30400C4CD55 /* assembler-thumb2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-thumb2.h"; path = "arm/assembler-thumb2.h"; sourceTree = ""; }; 9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "full-codegen-arm.cc"; path = "arm/full-codegen-arm.cc"; sourceTree = ""; }; 9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "jump-target-arm.cc"; path = "arm/jump-target-arm.cc"; sourceTree = ""; }; 9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "virtual-frame-arm.cc"; path = "arm/virtual-frame-arm.cc"; sourceTree = ""; }; @@ -734,9 +730,6 @@ 897FF1000E719B8F00D62E90 /* assembler-ia32-inl.h */, 897FF1010E719B8F00D62E90 /* assembler-ia32.cc */, 897FF1020E719B8F00D62E90 /* assembler-ia32.h */, - 9FA38BC81175B30400C4CD55 /* assembler-thumb2-inl.h */, - 9FA38BC91175B30400C4CD55 /* assembler-thumb2.cc */, - 9FA38BCA1175B30400C4CD55 /* assembler-thumb2.h */, 897FF1030E719B8F00D62E90 /* assembler.cc */, 897FF1040E719B8F00D62E90 /* assembler.h */, 897FF1050E719B8F00D62E90 /* ast.cc */, @@ -1394,7 +1387,6 @@ 89F23C400E78D5B2006B2466 /* allocation.cc in Sources */, 89F23C410E78D5B2006B2466 /* api.cc in Sources */, 89F23C970E78D5E3006B2466 /* assembler-arm.cc in Sources */, - 9FA38BCE1175B30400C4CD55 /* assembler-thumb2.cc in Sources */, 89F23C430E78D5B2006B2466 /* assembler.cc in Sources */, 89F23C440E78D5B2006B2466 /* ast.cc in Sources */, 89F23C450E78D5B2006B2466 /* bootstrapper.cc in Sources */,