| Index: src/arm/assembler-thumb2.h
|
| ===================================================================
|
| --- src/arm/assembler-thumb2.h (revision 4699)
|
| +++ src/arm/assembler-thumb2.h (working copy)
|
| @@ -1,1036 +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 <stdio.h>
|
| -#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<Object> handle);
|
| - INLINE(explicit Operand(Smi* value));
|
| -
|
| - // rm
|
| - INLINE(explicit Operand(Register rm));
|
| -
|
| - // rm <shift_op> shift_imm
|
| - explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
|
| -
|
| - // rm <shift_op> 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_op> shift_imm] Offset/NegOffset
|
| - // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
|
| - // [rn], +/- rm <shift_op> 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);
|
| -
|
| - // Semaphore instructions
|
| - void swp(Register dst, Register src, Register base, Condition cond = al);
|
| - void swpb(Register dst, Register src, Register base, 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));
|
| - }
|
| -
|
| - // Load effective address of memory operand x into register dst
|
| - void lea(Register dst, const MemOperand& x,
|
| - SBit s = LeaveCC, Condition cond = al);
|
| -
|
| - // 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<Instr*>(pc); }
|
| - void instr_at_put(byte* pc, Instr instr) {
|
| - *reinterpret_cast<Instr*>(pc) = instr;
|
| - }
|
| - Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
|
| - void instr_at_put(int pos, Instr instr) {
|
| - *reinterpret_cast<Instr*>(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_
|
|
|