| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| // | |
| // This is forked from Dart revision df52deea9f25690eb8b66c5995da92b70f7ac1fe | |
| // Please update the (git) revision if we merge changes from Dart. | |
| // https://code.google.com/p/dart/wiki/GettingTheSource | |
| #ifndef VM_ASSEMBLER_ARM_H_ | |
| #define VM_ASSEMBLER_ARM_H_ | |
| #ifndef VM_ASSEMBLER_H_ | |
| #error Do not include assembler_arm.h directly; use assembler.h instead. | |
| #endif | |
| #include "platform/assert.h" | |
| #include "platform/utils.h" | |
| #include "vm/constants_arm.h" | |
| #include "vm/cpu.h" | |
| #include "vm/hash_map.h" | |
| #include "vm/object.h" | |
| #include "vm/simulator.h" | |
| namespace dart { | |
| // Forward declarations. | |
| class RuntimeEntry; | |
| class StubEntry; | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32 as needed | |
| // Instruction encoding bits. | |
| enum { | |
| H = 1 << 5, // halfword (or byte) | |
| 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) | |
| D = 1 << 22, // high/lo bit of start of s/d register range | |
| 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) | |
| B0 = 1, | |
| B1 = 1 << 1, | |
| B2 = 1 << 2, | |
| B3 = 1 << 3, | |
| B4 = 1 << 4, | |
| B5 = 1 << 5, | |
| B6 = 1 << 6, | |
| B7 = 1 << 7, | |
| B8 = 1 << 8, | |
| B9 = 1 << 9, | |
| B10 = 1 << 10, | |
| B11 = 1 << 11, | |
| B12 = 1 << 12, | |
| B16 = 1 << 16, | |
| B17 = 1 << 17, | |
| 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, | |
| }; | |
| #endif | |
| class Label : public ValueObject { | |
| public: | |
| Label() : position_(0) {} | |
| ~Label() { | |
| // Assert if label is being destroyed with unresolved branches pending. | |
| ASSERT(!IsLinked()); | |
| } | |
| // Returns the position for bound and linked labels. Cannot be used | |
| // for unused labels. | |
| intptr_t Position() const { | |
| ASSERT(!IsUnused()); | |
| return IsBound() ? -position_ - kWordSize : position_ - kWordSize; | |
| } | |
| bool IsBound() const { return position_ < 0; } | |
| bool IsUnused() const { return position_ == 0; } | |
| bool IsLinked() const { return position_ > 0; } | |
| private: | |
| intptr_t position_; | |
| void Reinitialize() { position_ = 0; } | |
| void BindTo(intptr_t position) { | |
| ASSERT(!IsBound()); | |
| position_ = -position - kWordSize; | |
| ASSERT(IsBound()); | |
| } | |
| void LinkTo(intptr_t position) { | |
| ASSERT(!IsBound()); | |
| position_ = position + kWordSize; | |
| ASSERT(IsLinked()); | |
| } | |
| friend class Assembler; | |
| DISALLOW_COPY_AND_ASSIGN(Label); | |
| }; | |
| // Encodes Addressing Mode 1 - Data-processing operands. | |
| class Operand : public ValueObject { | |
| public: | |
| // Data-processing operands - Uninitialized. | |
| Operand() : type_(-1), encoding_(-1) {} | |
| // Data-processing operands - Copy constructor. | |
| Operand(const Operand &other) | |
| : ValueObject(), type_(other.type_), encoding_(other.encoding_) {} | |
| // Data-processing operands - Assignment operator. | |
| Operand &operator=(const Operand &other) { | |
| type_ = other.type_; | |
| encoding_ = other.encoding_; | |
| return *this; | |
| } | |
| #if 0 | |
| // Moved to encodeRotatedImm8() in IceAssemblerARM32.cpp | |
| // Data-processing operands - Immediate. | |
| explicit Operand(uint32_t immediate) { | |
| ASSERT(immediate < (1 << kImmed8Bits)); | |
| type_ = 1; | |
| encoding_ = immediate; | |
| } | |
| // Moved to decodeOperand() and encodeRotatedImm8() in IceAssemblerARM32.cpp | |
| // Data-processing operands - Rotated immediate. | |
| Operand(uint32_t rotate, uint32_t immed8) { | |
| ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits))); | |
| type_ = 1; | |
| encoding_ = (rotate << kRotateShift) | (immed8 << kImmed8Shift); | |
| } | |
| // Moved to decodeOperand() in IceAssemblerARM32.cpp | |
| // Data-processing operands - Register. | |
| explicit Operand(Register rm) { | |
| type_ = 0; | |
| encoding_ = static_cast<uint32_t>(rm); | |
| } | |
| // Moved to encodeShiftRotateImm5() in IceAssemblerARM32.cpp | |
| // Data-processing operands - Logical shift/rotate by immediate. | |
| Operand(Register rm, Shift shift, uint32_t shift_imm) { | |
| ASSERT(shift_imm < (1 << kShiftImmBits)); | |
| type_ = 0; | |
| encoding_ = shift_imm << kShiftImmShift | | |
| static_cast<uint32_t>(shift) << kShiftShift | | |
| static_cast<uint32_t>(rm); | |
| } | |
| // Moved to encodeShiftRotateReg() in IceAssemblerARM32.cpp | |
| // Data-processing operands - Logical shift/rotate by register. | |
| Operand(Register rm, Shift shift, Register rs) { | |
| type_ = 0; | |
| encoding_ = static_cast<uint32_t>(rs) << kShiftRegisterShift | | |
| static_cast<uint32_t>(shift) << kShiftShift | (1 << 4) | | |
| static_cast<uint32_t>(rm); | |
| } | |
| // Already defined as ARM32::OperandARM32FlexImm::canHoldImm(). | |
| static bool CanHold(uint32_t immediate, Operand* o) { | |
| // Avoid the more expensive test for frequent small immediate values. | |
| if (immediate < (1 << kImmed8Bits)) { | |
| o->type_ = 1; | |
| o->encoding_ = (0 << kRotateShift) | (immediate << kImmed8Shift); | |
| return true; | |
| } | |
| // Note that immediate must be unsigned for the test to work correctly. | |
| for (int rot = 0; rot < 16; rot++) { | |
| uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); | |
| if (imm8 < (1 << kImmed8Bits)) { | |
| o->type_ = 1; | |
| o->encoding_ = (rot << kRotateShift) | (imm8 << kImmed8Shift); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| #endif | |
| private: | |
| bool is_valid() const { return (type_ == 0) || (type_ == 1); } | |
| uint32_t type() const { | |
| ASSERT(is_valid()); | |
| return type_; | |
| } | |
| uint32_t encoding() const { | |
| ASSERT(is_valid()); | |
| return encoding_; | |
| } | |
| uint32_t type_; // Encodes the type field (bits 27-25) in the instruction. | |
| uint32_t encoding_; | |
| friend class Assembler; | |
| friend class Address; | |
| }; | |
| enum OperandSize { | |
| kByte, | |
| kUnsignedByte, | |
| kHalfword, | |
| kUnsignedHalfword, | |
| kWord, | |
| kUnsignedWord, | |
| kWordPair, | |
| kSWord, | |
| kDWord, | |
| kRegList, | |
| }; | |
| // Load/store multiple addressing mode. | |
| enum BlockAddressMode { | |
| // clang-format off | |
| // 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 | |
| // clang-format on | |
| }; | |
| class Address : public ValueObject { | |
| public: | |
| enum OffsetKind { | |
| Immediate, | |
| IndexRegister, | |
| ScaledIndexRegister, | |
| }; | |
| // Memory operand addressing mode | |
| enum Mode { | |
| // clang-format off | |
| kModeMask = (8|4|1) << 21, | |
| // bit encoding P U W | |
| Offset = (8|4|0) << 21, // offset (w/o 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 (w/o writeback to base) | |
| NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback | |
| NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback | |
| // clang-format on | |
| }; | |
| Address(const Address &other) | |
| : ValueObject(), encoding_(other.encoding_), kind_(other.kind_) {} | |
| Address &operator=(const Address &other) { | |
| encoding_ = other.encoding_; | |
| kind_ = other.kind_; | |
| return *this; | |
| } | |
| bool Equals(const Address &other) const { | |
| return (encoding_ == other.encoding_) && (kind_ == other.kind_); | |
| } | |
| #if 0 | |
| // Moved to decodeImmRegOffset() in IceAssemblerARM32.cpp. | |
| // Used to model stack offsets. | |
| explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { | |
| ASSERT(Utils::IsAbsoluteUint(12, offset)); | |
| kind_ = Immediate; | |
| if (offset < 0) { | |
| encoding_ = (am ^ (1 << kUShift)) | -offset; // Flip U to adjust sign. | |
| } else { | |
| encoding_ = am | offset; | |
| } | |
| encoding_ |= static_cast<uint32_t>(rn) << kRnShift; | |
| } | |
| #endif | |
| // There is no register offset mode unless Mode is Offset, in which case the | |
| // shifted register case below should be used. | |
| Address(Register rn, Register r, Mode am); | |
| Address(Register rn, Register rm, Shift shift = LSL, uint32_t shift_imm = 0, | |
| Mode am = Offset) { | |
| Operand o(rm, shift, shift_imm); | |
| if ((shift == LSL) && (shift_imm == 0)) { | |
| kind_ = IndexRegister; | |
| } else { | |
| kind_ = ScaledIndexRegister; | |
| } | |
| encoding_ = o.encoding() | am | (static_cast<uint32_t>(rn) << kRnShift); | |
| } | |
| // There is no shifted register mode with a register shift. | |
| Address(Register rn, Register rm, Shift shift, Register r, Mode am = Offset); | |
| static OperandSize OperandSizeFor(intptr_t cid); | |
| static bool CanHoldLoadOffset(OperandSize size, int32_t offset, | |
| int32_t *offset_mask); | |
| static bool CanHoldStoreOffset(OperandSize size, int32_t offset, | |
| int32_t *offset_mask); | |
| static bool CanHoldImmediateOffset(bool is_load, intptr_t cid, | |
| int64_t offset); | |
| private: | |
| Register rn() const { | |
| return Instr::At(reinterpret_cast<uword>(&encoding_))->RnField(); | |
| } | |
| Register rm() const { | |
| return ((kind() == IndexRegister) || (kind() == ScaledIndexRegister)) | |
| ? Instr::At(reinterpret_cast<uword>(&encoding_))->RmField() | |
| : kNoRegister; | |
| } | |
| Mode mode() const { return static_cast<Mode>(encoding() & kModeMask); } | |
| uint32_t encoding() const { return encoding_; } | |
| #if 0 | |
| // Moved to encodeImmRegOffsetEnc3 in IceAssemblerARM32.cpp | |
| // Encoding for addressing mode 3. | |
| uint32_t encoding3() const; | |
| #endif | |
| // Encoding for vfp load/store addressing. | |
| uint32_t vencoding() const; | |
| OffsetKind kind() const { return kind_; } | |
| uint32_t encoding_; | |
| OffsetKind kind_; | |
| friend class Assembler; | |
| }; | |
| class FieldAddress : public Address { | |
| public: | |
| FieldAddress(Register base, int32_t disp) | |
| : Address(base, disp - kHeapObjectTag) {} | |
| // This addressing mode does not exist. | |
| FieldAddress(Register base, Register r); | |
| FieldAddress(const FieldAddress &other) : Address(other) {} | |
| FieldAddress &operator=(const FieldAddress &other) { | |
| Address::operator=(other); | |
| return *this; | |
| } | |
| }; | |
| class Assembler : public ValueObject { | |
| public: | |
| explicit Assembler(bool use_far_branches = false) | |
| : buffer_(), prologue_offset_(-1), use_far_branches_(use_far_branches), | |
| comments_(), constant_pool_allowed_(false) {} | |
| ~Assembler() {} | |
| void PopRegister(Register r) { Pop(r); } | |
| void Bind(Label *label); | |
| void Jump(Label *label) { b(label); } | |
| // Misc. functionality | |
| intptr_t CodeSize() const { return buffer_.Size(); } | |
| intptr_t prologue_offset() const { return prologue_offset_; } | |
| // Count the fixups that produce a pointer offset, without processing | |
| // the fixups. On ARM there are no pointers in code. | |
| intptr_t CountPointerOffsets() const { return 0; } | |
| const ZoneGrowableArray<intptr_t> &GetPointerOffsets() const { | |
| ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code. | |
| return buffer_.pointer_offsets(); | |
| } | |
| ObjectPoolWrapper &object_pool_wrapper() { return object_pool_wrapper_; } | |
| RawObjectPool *MakeObjectPool() { | |
| return object_pool_wrapper_.MakeObjectPool(); | |
| } | |
| bool use_far_branches() const { | |
| return FLAG_use_far_branches || use_far_branches_; | |
| } | |
| #if defined(TESTING) || defined(DEBUG) | |
| // Used in unit tests and to ensure predictable verification code size in | |
| // FlowGraphCompiler::EmitEdgeCounter. | |
| void set_use_far_branches(bool b) { use_far_branches_ = b; } | |
| #endif // TESTING || DEBUG | |
| void FinalizeInstructions(const MemoryRegion ®ion) { | |
| buffer_.FinalizeInstructions(region); | |
| } | |
| // Debugging and bringup support. | |
| void Stop(const char *message); | |
| void Unimplemented(const char *message); | |
| void Untested(const char *message); | |
| void Unreachable(const char *message); | |
| static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); | |
| void Comment(const char *format, ...) PRINTF_ATTRIBUTE(2, 3); | |
| static bool EmittingComments(); | |
| const Code::Comments &GetCodeComments() const; | |
| static const char *RegisterName(Register reg); | |
| static const char *FpuRegisterName(FpuRegister reg); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::and_() | |
| // Data-processing instructions. | |
| void and_(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::eor() | |
| void eor(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemberARM32::sub() | |
| void sub(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void subs(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemberARM32::rsb() | |
| void rsb(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void rsbs(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::add() | |
| void add(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void adds(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::adc() | |
| void adc(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void adcs(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::sbc() | |
| void sbc(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::sbc() | |
| void sbcs(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::rsc() | |
| void rsc(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::tst(); | |
| void tst(Register rn, Operand o, Condition cond = AL); | |
| #endif | |
| void teq(Register rn, Operand o, Condition cond = AL); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::cmp() | |
| void cmp(Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::cmn() | |
| void cmn(Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::IceAssemblerARM32::orr(). | |
| void orr(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void orrs(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::IceAssemblerARM32::mov() | |
| void mov(Register rd, Operand o, Condition cond = AL); | |
| void movs(Register rd, Operand o, Condition cond = AL); | |
| // Moved to ARM32::IceAssemblerARM32::bic() | |
| void bic(Register rd, Register rn, Operand o, Condition cond = AL); | |
| void bics(Register rd, Register rn, Operand o, Condition cond = AL); | |
| // Moved to ARM32::IceAssemblerARM32::mvn() | |
| void mvn(Register rd, Operand o, Condition cond = AL); | |
| void mvns(Register rd, Operand o, Condition cond = AL); | |
| // Miscellaneous data-processing instructions. | |
| // Moved to ARM32::AssemblerARM32::clz() | |
| void clz(Register rd, Register rm, Condition cond = AL); | |
| // Multiply instructions. | |
| // Moved to ARM32::AssemblerARM32::mul() | |
| void mul(Register rd, Register rn, Register rm, Condition cond = AL); | |
| void muls(Register rd, Register rn, Register rm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::mla() | |
| void mla(Register rd, Register rn, Register rm, Register ra, | |
| Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::mls() | |
| void mls(Register rd, Register rn, Register rm, Register ra, | |
| Condition cond = AL); | |
| #endif | |
| void smull(Register rd_lo, Register rd_hi, Register rn, Register rm, | |
| Condition cond = AL); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::umull(); | |
| void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, | |
| Condition cond = AL); | |
| #endif | |
| void smlal(Register rd_lo, Register rd_hi, Register rn, Register rm, | |
| Condition cond = AL); | |
| void umlal(Register rd_lo, Register rd_hi, Register rn, Register rm, | |
| Condition cond = AL); | |
| // Emulation of this instruction uses IP and the condition codes. Therefore, | |
| // none of the registers can be IP, and the instruction can only be used | |
| // unconditionally. | |
| void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm); | |
| // Division instructions. | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::sdiv() | |
| void sdiv(Register rd, Register rn, Register rm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::udiv() | |
| void udiv(Register rd, Register rn, Register rm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::ldr() | |
| // Load/store instructions. | |
| void ldr(Register rd, Address ad, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::str() | |
| void str(Register rd, Address ad, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::ldr() | |
| void ldrb(Register rd, Address ad, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::str() | |
| void strb(Register rd, Address ad, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::ldr() | |
| void ldrh(Register rd, Address ad, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::str() | |
| void strh(Register rd, Address ad, Condition cond = AL); | |
| #endif | |
| void ldrsb(Register rd, Address ad, Condition cond = AL); | |
| void ldrsh(Register rd, Address ad, Condition cond = AL); | |
| // ldrd and strd actually support the full range of addressing modes, but | |
| // we don't use them, and we need to split them up into two instructions for | |
| // ARMv5TE, so we only support the base + offset mode. | |
| void ldrd(Register rd, Register rn, int32_t offset, Condition cond = AL); | |
| void strd(Register rd, Register rn, int32_t offset, Condition cond = AL); | |
| #if 0 | |
| // Folded into ARM32::AssemblerARM32::popList(), since it is its only use (and | |
| // doesn't implement ARM LDM instructions). | |
| void ldm(BlockAddressMode am, Register base, | |
| RegList regs, Condition cond = AL); | |
| // Folded into ARM32::AssemblerARM32::pushList(), since it is its only use | |
| // (and doesn't implement ARM STM instruction). | |
| void stm(BlockAddressMode am, Register base, | |
| RegList regs, Condition cond = AL); | |
| // Moved to ARM::AssemblerARM32::ldrex(); | |
| void ldrex(Register rd, Register rn, Condition cond = AL); | |
| // Moved to ARM::AssemblerARM32::strex(); | |
| void strex(Register rd, Register rt, Register rn, Condition cond = AL); | |
| #endif | |
| // Miscellaneous instructions. | |
| void clrex(); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::nop(). | |
| void nop(Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::bkpt() | |
| // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. | |
| void bkpt(uint16_t imm16); | |
| static int32_t BkptEncoding(uint16_t imm16) { | |
| // bkpt requires that the cond field is AL. | |
| return (AL << kConditionShift) | B24 | B21 | | |
| ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); | |
| } | |
| // Not ported. PNaCl doesn't allow breakpoint instructions. | |
| static uword GetBreakInstructionFiller() { | |
| return BkptEncoding(0); | |
| } | |
| // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). | |
| // Moved to ARM32::AssemblerARM32::vmovsr(). | |
| void vmovsr(SRegister sn, Register rt, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovrs(). | |
| void vmovrs(Register rt, SRegister sn, Condition cond = AL); | |
| #endif | |
| void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL); | |
| void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::vmovdrr(). | |
| void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovrrd(). | |
| void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovqir(). | |
| void vmovdr(DRegister dd, int i, Register rt, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovss(). | |
| void vmovs(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovdd(). | |
| void vmovd(DRegister dd, DRegister dm, Condition cond = AL); | |
| #endif | |
| void vmovq(QRegister qd, QRegister qm); | |
| #if 0 | |
| // Returns false if the immediate cannot be encoded. | |
| // Moved to ARM32::AssemblerARM32::vmovs(); | |
| bool vmovs(SRegister sd, float s_imm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmovs(); | |
| bool vmovd(DRegister dd, double d_imm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vldrs() | |
| void vldrs(SRegister sd, Address ad, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vstrs() | |
| void vstrs(SRegister sd, Address ad, Condition cond = AL); | |
| #endif | |
| // Moved to ARM32::AssemblerARM32::vldrd() | |
| void vldrd(DRegister dd, Address ad, Condition cond = AL); | |
| #if 0 | |
| // Moved to Arm32::AssemblerARM32::vstrd() | |
| void vstrd(DRegister dd, Address ad, Condition cond = AL); | |
| #endif | |
| void vldms(BlockAddressMode am, Register base, SRegister first, | |
| SRegister last, Condition cond = AL); | |
| void vstms(BlockAddressMode am, Register base, SRegister first, | |
| SRegister last, Condition cond = AL); | |
| void vldmd(BlockAddressMode am, Register base, DRegister first, | |
| intptr_t count, Condition cond = AL); | |
| void vstmd(BlockAddressMode am, Register base, DRegister first, | |
| intptr_t count, Condition cond = AL); | |
| #if 0 | |
| // Moved to Arm32::AssemblerARM32::vadds() | |
| void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vaddd() | |
| void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vaddqi(). | |
| void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vaddqf(). | |
| void vaddqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vsubs() | |
| void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vsubd() | |
| void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vsubqi(). | |
| void vsubqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vsubqf(). | |
| void vsubqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vmuls() | |
| void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vmuld() | |
| void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vmulqi(). | |
| void vmulqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vmulqf(). | |
| void vmulqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vshlqi(). | |
| void vshlqi(OperandSize sz, QRegister qd, QRegister qm, QRegister qn); | |
| // Moved to ARM32::AssemblerARM32::vshlqu(). | |
| void vshlqu(OperandSize sz, QRegister qd, QRegister qm, QRegister qn); | |
| // Moved to Arm32::AssemblerARM32::vmlas() | |
| void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vmlad() | |
| void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vmlss() | |
| void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vmlsd() | |
| void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vdivs() | |
| void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vdivd() | |
| void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | |
| #endif | |
| void vminqs(QRegister qd, QRegister qn, QRegister qm); | |
| void vmaxqs(QRegister qd, QRegister qn, QRegister qm); | |
| void vrecpeqs(QRegister qd, QRegister qm); | |
| void vrecpsqs(QRegister qd, QRegister qn, QRegister qm); | |
| void vrsqrteqs(QRegister qd, QRegister qm); | |
| void vrsqrtsqs(QRegister qd, QRegister qn, QRegister qm); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::vorrq() | |
| void veorq(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vorrq() | |
| void vorrq(QRegister qd, QRegister qn, QRegister qm); | |
| #endif | |
| void vornq(QRegister qd, QRegister qn, QRegister qm); | |
| #if 0 | |
| // Moved to Arm32::AssemblerARM32::vandq(). | |
| void vandq(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vandq(). | |
| void vmvnq(QRegister qd, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vceqqi(). | |
| void vceqqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vceqqs(). | |
| void vceqqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcgeqi(). | |
| void vcgeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcugeqi(). | |
| void vcugeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcgeqs(). | |
| void vcgeqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcgtqi(). | |
| void vcgtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcugtqi(). | |
| void vcugtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vcgtqs(). | |
| void vcgtqs(QRegister qd, QRegister qn, QRegister qm); | |
| // Moved to Arm32::AssemblerARM32::vabss(). | |
| void vabss(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vabsd(). | |
| void vabsd(DRegister dd, DRegister dm, Condition cond = AL); | |
| // Moved to Arm32::AssemblerARM32::vabsq(). | |
| void vabsqs(QRegister qd, QRegister qm); | |
| #endif | |
| void vnegs(SRegister sd, SRegister sm, Condition cond = AL); | |
| void vnegd(DRegister dd, DRegister dm, Condition cond = AL); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::vnegqs(). | |
| void vnegqs(QRegister qd, QRegister qm); | |
| // Moved to ARM32::AssemblerARM32::vsqrts(). | |
| void vsqrts(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vsqrts(). | |
| void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtsd(). | |
| void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32:vcvtds(). | |
| void vcvtds(DRegister dd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtis() | |
| void vcvtis(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtid() | |
| void vcvtid(SRegister sd, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtsi() | |
| void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtdi() | |
| void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtus(). | |
| void vcvtus(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtud(). | |
| void vcvtud(SRegister sd, DRegister dm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtsu() | |
| void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::vcvtdu() | |
| void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM23::AssemblerARM32::vcmps(). | |
| void vcmps(SRegister sd, SRegister sm, Condition cond = AL); | |
| // Moved to ARM23::AssemblerARM32::vcmpd(). | |
| void vcmpd(DRegister dd, DRegister dm, Condition cond = AL); | |
| // Moved to ARM23::AssemblerARM32::vcmpsz(). | |
| void vcmpsz(SRegister sd, Condition cond = AL); | |
| // Moved to ARM23::AssemblerARM32::vcmpdz(). | |
| void vcmpdz(DRegister dd, Condition cond = AL); | |
| // APSR_nzcv version moved to ARM32::AssemblerARM32::vmrsAPSR_nzcv() | |
| void vmrs(Register rd, Condition cond = AL); | |
| #endif | |
| void vmstat(Condition cond = AL); | |
| // Duplicates the operand of size sz at index idx from dm to all elements of | |
| // qd. This is a special case of vtbl. | |
| void vdup(OperandSize sz, QRegister qd, DRegister dm, int idx); | |
| // Each byte of dm is an index into the table of bytes formed by concatenating | |
| // a list of 'length' registers starting with dn. The result is placed in dd. | |
| void vtbl(DRegister dd, DRegister dn, int length, DRegister dm); | |
| // The words of qd and qm are interleaved with the low words of the result | |
| // in qd and the high words in qm. | |
| void vzipqw(QRegister qd, QRegister qm); | |
| // Branch instructions. | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::b(); | |
| void b(Label* label, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::bl() | |
| void bl(Label* label, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::bx() | |
| void bx(Register rm, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::blx() | |
| void blx(Register rm, Condition cond = AL); | |
| #endif | |
| void Branch(const StubEntry &stub_entry, | |
| Patchability patchable = kNotPatchable, Register pp = PP, | |
| Condition cond = AL); | |
| void BranchLink(const StubEntry &stub_entry, | |
| Patchability patchable = kNotPatchable); | |
| void BranchLink(const Code &code, Patchability patchable); | |
| // Branch and link to an entry address. Call sequence can be patched. | |
| void BranchLinkPatchable(const StubEntry &stub_entry); | |
| void BranchLinkPatchable(const Code &code); | |
| // Branch and link to [base + offset]. Call sequence is never patched. | |
| void BranchLinkOffset(Register base, int32_t offset); | |
| // Add signed immediate value to rd. May clobber IP. | |
| void AddImmediate(Register rd, int32_t value, Condition cond = AL); | |
| void AddImmediate(Register rd, Register rn, int32_t value, | |
| Condition cond = AL); | |
| void AddImmediateSetFlags(Register rd, Register rn, int32_t value, | |
| Condition cond = AL); | |
| void SubImmediateSetFlags(Register rd, Register rn, int32_t value, | |
| Condition cond = AL); | |
| void AndImmediate(Register rd, Register rs, int32_t imm, Condition cond = AL); | |
| // Test rn and immediate. May clobber IP. | |
| void TestImmediate(Register rn, int32_t imm, Condition cond = AL); | |
| // Compare rn with signed immediate value. May clobber IP. | |
| void CompareImmediate(Register rn, int32_t value, Condition cond = AL); | |
| // Signed integer division of left by right. Checks to see if integer | |
| // division is supported. If not, uses the FPU for division with | |
| // temporary registers tmpl and tmpr. tmpl and tmpr must be different | |
| // registers. | |
| void IntegerDivide(Register result, Register left, Register right, | |
| DRegister tmpl, DRegister tmpr); | |
| // Load and Store. | |
| // These three do not clobber IP. | |
| void LoadPatchableImmediate(Register rd, int32_t value, Condition cond = AL); | |
| void LoadDecodableImmediate(Register rd, int32_t value, Condition cond = AL); | |
| void LoadImmediate(Register rd, int32_t value, Condition cond = AL); | |
| // These two may clobber IP. | |
| void LoadSImmediate(SRegister sd, float value, Condition cond = AL); | |
| void LoadDImmediate(DRegister dd, double value, Register scratch, | |
| Condition cond = AL); | |
| void MarkExceptionHandler(Label *label); | |
| void Drop(intptr_t stack_elements); | |
| void RestoreCodePointer(); | |
| void LoadPoolPointer(Register reg = PP); | |
| void LoadIsolate(Register rd); | |
| void LoadObject(Register rd, const Object &object, Condition cond = AL); | |
| void LoadUniqueObject(Register rd, const Object &object, Condition cond = AL); | |
| void LoadFunctionFromCalleePool(Register dst, const Function &function, | |
| Register new_pp); | |
| void LoadNativeEntry(Register dst, const ExternalLabel *label, | |
| Patchability patchable, Condition cond = AL); | |
| void PushObject(const Object &object); | |
| void CompareObject(Register rn, const Object &object); | |
| // When storing into a heap object field, knowledge of the previous content | |
| // is expressed through these constants. | |
| enum FieldContent { | |
| kEmptyOrSmiOrNull, // Empty = garbage/zapped in release/debug mode. | |
| kHeapObjectOrSmi, | |
| kOnlySmi, | |
| }; | |
| void StoreIntoObject(Register object, // Object we are storing into. | |
| const Address &dest, // Where we are storing into. | |
| Register value, // Value we are storing. | |
| bool can_value_be_smi = true); | |
| void StoreIntoObjectOffset(Register object, int32_t offset, Register value, | |
| bool can_value_be_smi = true); | |
| void StoreIntoObjectNoBarrier(Register object, const Address &dest, | |
| Register value, | |
| FieldContent old_content = kHeapObjectOrSmi); | |
| void InitializeFieldNoBarrier(Register object, const Address &dest, | |
| Register value) { | |
| StoreIntoObjectNoBarrier(object, dest, value, kEmptyOrSmiOrNull); | |
| } | |
| void | |
| StoreIntoObjectNoBarrierOffset(Register object, int32_t offset, | |
| Register value, | |
| FieldContent old_content = kHeapObjectOrSmi); | |
| void StoreIntoObjectNoBarrier(Register object, const Address &dest, | |
| const Object &value, | |
| FieldContent old_content = kHeapObjectOrSmi); | |
| void | |
| StoreIntoObjectNoBarrierOffset(Register object, int32_t offset, | |
| const Object &value, | |
| FieldContent old_content = kHeapObjectOrSmi); | |
| // Store value_even, value_odd, value_even, ... into the words in the address | |
| // range [begin, end), assumed to be uninitialized fields in object (tagged). | |
| // The stores must not need a generational store barrier (e.g., smi/null), | |
| // and (value_even, value_odd) must be a valid register pair. | |
| // Destroys register 'begin'. | |
| void InitializeFieldsNoBarrier(Register object, Register begin, Register end, | |
| Register value_even, Register value_odd); | |
| // Like above, for the range [base+begin_offset, base+end_offset), unrolled. | |
| void InitializeFieldsNoBarrierUnrolled(Register object, Register base, | |
| intptr_t begin_offset, | |
| intptr_t end_offset, | |
| Register value_even, | |
| Register value_odd); | |
| // Stores a Smi value into a heap object field that always contains a Smi. | |
| void StoreIntoSmiField(const Address &dest, Register value); | |
| void LoadClassId(Register result, Register object, Condition cond = AL); | |
| void LoadClassById(Register result, Register class_id); | |
| void LoadClass(Register result, Register object, Register scratch); | |
| void CompareClassId(Register object, intptr_t class_id, Register scratch); | |
| void LoadClassIdMayBeSmi(Register result, Register object); | |
| void LoadTaggedClassIdMayBeSmi(Register result, Register object); | |
| void ComputeRange(Register result, Register value, Register scratch, | |
| Label *miss); | |
| void UpdateRangeFeedback(Register value, intptr_t idx, Register ic_data, | |
| Register scratch1, Register scratch2, Label *miss); | |
| intptr_t FindImmediate(int32_t imm); | |
| bool CanLoadFromObjectPool(const Object &object) const; | |
| void LoadFromOffset(OperandSize type, Register reg, Register base, | |
| int32_t offset, Condition cond = AL); | |
| void LoadFieldFromOffset(OperandSize type, Register reg, Register base, | |
| int32_t offset, Condition cond = AL) { | |
| LoadFromOffset(type, reg, base, offset - kHeapObjectTag, cond); | |
| } | |
| void StoreToOffset(OperandSize type, Register reg, Register base, | |
| int32_t offset, Condition cond = AL); | |
| void LoadSFromOffset(SRegister reg, Register base, int32_t offset, | |
| Condition cond = AL); | |
| void StoreSToOffset(SRegister reg, Register base, int32_t offset, | |
| Condition cond = AL); | |
| void LoadDFromOffset(DRegister reg, Register base, int32_t offset, | |
| Condition cond = AL); | |
| void StoreDToOffset(DRegister reg, Register base, int32_t offset, | |
| Condition cond = AL); | |
| void LoadMultipleDFromOffset(DRegister first, intptr_t count, Register base, | |
| int32_t offset); | |
| void StoreMultipleDToOffset(DRegister first, intptr_t count, Register base, | |
| int32_t offset); | |
| void CopyDoubleField(Register dst, Register src, Register tmp1, Register tmp2, | |
| DRegister dtmp); | |
| void CopyFloat32x4Field(Register dst, Register src, Register tmp1, | |
| Register tmp2, DRegister dtmp); | |
| void CopyFloat64x2Field(Register dst, Register src, Register tmp1, | |
| Register tmp2, DRegister dtmp); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::push(). | |
| void Push(Register rd, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::pop(). | |
| void Pop(Register rd, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::pushList(). | |
| void PushList(RegList regs, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::popList(). | |
| void PopList(RegList regs, Condition cond = AL); | |
| #endif | |
| void MoveRegister(Register rd, Register rm, Condition cond = AL); | |
| // Convenience shift instructions. Use mov instruction with shifter operand | |
| // for variants setting the status flags. | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::lsl() | |
| void Lsl(Register rd, Register rm, const Operand& shift_imm, | |
| Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::lsl() | |
| void Lsl(Register rd, Register rm, Register rs, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::lsr() | |
| void Lsr(Register rd, Register rm, const Operand& shift_imm, | |
| Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::lsr() | |
| void Lsr(Register rd, Register rm, Register rs, Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::asr() | |
| void Asr(Register rd, Register rm, const Operand& shift_imm, | |
| Condition cond = AL); | |
| // Moved to ARM32::AssemblerARM32::asr() | |
| void Asr(Register rd, Register rm, Register rs, Condition cond = AL); | |
| #endif | |
| void Asrs(Register rd, Register rm, const Operand &shift_imm, | |
| Condition cond = AL); | |
| void Ror(Register rd, Register rm, const Operand &shift_imm, | |
| Condition cond = AL); | |
| void Ror(Register rd, Register rm, Register rs, Condition cond = AL); | |
| void Rrx(Register rd, Register rm, Condition cond = AL); | |
| // Fill rd with the sign of rm. | |
| void SignFill(Register rd, Register rm, Condition cond = AL); | |
| void Vreciprocalqs(QRegister qd, QRegister qm); | |
| void VreciprocalSqrtqs(QRegister qd, QRegister qm); | |
| // If qm must be preserved, then provide a (non-QTMP) temporary. | |
| void Vsqrtqs(QRegister qd, QRegister qm, QRegister temp); | |
| void Vdivqs(QRegister qd, QRegister qn, QRegister qm); | |
| void SmiTag(Register reg, Condition cond = AL) { | |
| Lsl(reg, reg, Operand(kSmiTagSize), cond); | |
| } | |
| void SmiTag(Register dst, Register src, Condition cond = AL) { | |
| Lsl(dst, src, Operand(kSmiTagSize), cond); | |
| } | |
| void SmiUntag(Register reg, Condition cond = AL) { | |
| Asr(reg, reg, Operand(kSmiTagSize), cond); | |
| } | |
| void SmiUntag(Register dst, Register src, Condition cond = AL) { | |
| Asr(dst, src, Operand(kSmiTagSize), cond); | |
| } | |
| // Untag the value in the register assuming it is a smi. | |
| // Untagging shifts tag bit into the carry flag - if carry is clear | |
| // assumption was correct. In this case jump to the is_smi label. | |
| // Otherwise fall-through. | |
| void SmiUntag(Register dst, Register src, Label *is_smi) { | |
| ASSERT(kSmiTagSize == 1); | |
| Asrs(dst, src, Operand(kSmiTagSize)); | |
| b(is_smi, CC); | |
| } | |
| void CheckCodePointer(); | |
| // Function frame setup and tear down. | |
| void EnterFrame(RegList regs, intptr_t frame_space); | |
| void LeaveFrame(RegList regs); | |
| void Ret(); | |
| void ReserveAlignedFrameSpace(intptr_t frame_space); | |
| // Create a frame for calling into runtime that preserves all volatile | |
| // registers. Frame's SP is guaranteed to be correctly aligned and | |
| // frame_space bytes are reserved under it. | |
| void EnterCallRuntimeFrame(intptr_t frame_space); | |
| void LeaveCallRuntimeFrame(); | |
| void CallRuntime(const RuntimeEntry &entry, intptr_t argument_count); | |
| // Set up a Dart frame on entry with a frame pointer and PC information to | |
| // enable easy access to the RawInstruction object of code corresponding | |
| // to this frame. | |
| void EnterDartFrame(intptr_t frame_size); | |
| void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP); | |
| // Set up a Dart frame for a function compiled for on-stack replacement. | |
| // The frame layout is a normal Dart frame, but the frame is partially set | |
| // up on entry (it is the frame of the unoptimized code). | |
| void EnterOsrFrame(intptr_t extra_size); | |
| // Set up a stub frame so that the stack traversal code can easily identify | |
| // a stub frame. | |
| void EnterStubFrame(); | |
| void LeaveStubFrame(); | |
| // The register into which the allocation stats table is loaded with | |
| // LoadAllocationStatsAddress should be passed to | |
| // IncrementAllocationStats(WithSize) as stats_addr_reg to update the | |
| // allocation stats. These are separate assembler macros so we can | |
| // avoid a dependent load too nearby the load of the table address. | |
| void LoadAllocationStatsAddress(Register dest, intptr_t cid, | |
| bool inline_isolate = true); | |
| void IncrementAllocationStats(Register stats_addr, intptr_t cid, | |
| Heap::Space space); | |
| void IncrementAllocationStatsWithSize(Register stats_addr_reg, | |
| Register size_reg, Heap::Space space); | |
| Address ElementAddressForIntIndex(bool is_load, bool is_external, | |
| intptr_t cid, intptr_t index_scale, | |
| Register array, intptr_t index, | |
| Register temp); | |
| Address ElementAddressForRegIndex(bool is_load, bool is_external, | |
| intptr_t cid, intptr_t index_scale, | |
| Register array, Register index); | |
| // If allocation tracing for |cid| is enabled, will jump to |trace| label, | |
| // which will allocate in the runtime where tracing occurs. | |
| void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label *trace, | |
| bool inline_isolate = true); | |
| // Inlined allocation of an instance of class 'cls', code has no runtime | |
| // calls. Jump to 'failure' if the instance cannot be allocated here. | |
| // Allocated instance is returned in 'instance_reg'. | |
| // Only the tags field of the object is initialized. | |
| void TryAllocate(const Class &cls, Label *failure, Register instance_reg, | |
| Register temp_reg); | |
| void TryAllocateArray(intptr_t cid, intptr_t instance_size, Label *failure, | |
| Register instance, Register end_address, Register temp1, | |
| Register temp2); | |
| // Emit data (e.g encoded instruction or immediate) in instruction stream. | |
| void Emit(int32_t value); | |
| // On some other platforms, we draw a distinction between safe and unsafe | |
| // smis. | |
| static bool IsSafe(const Object &object) { return true; } | |
| static bool IsSafeSmi(const Object &object) { return object.IsSmi(); } | |
| bool constant_pool_allowed() const { return constant_pool_allowed_; } | |
| void set_constant_pool_allowed(bool b) { constant_pool_allowed_ = b; } | |
| private: | |
| AssemblerBuffer buffer_; // Contains position independent code. | |
| ObjectPoolWrapper object_pool_wrapper_; | |
| int32_t prologue_offset_; | |
| bool use_far_branches_; | |
| #if 0 | |
| // If you are thinking of using one or both of these instructions directly, | |
| // instead LoadImmediate should probably be used. | |
| // Moved to ARM::AssemblerARM32::movw | |
| void movw(Register rd, uint16_t imm16, Condition cond = AL); | |
| // Moved to ARM::AssemblerARM32::movt | |
| void movt(Register rd, uint16_t imm16, Condition cond = AL); | |
| #endif | |
| void BindARMv6(Label *label); | |
| void BindARMv7(Label *label); | |
| void LoadWordFromPoolOffset(Register rd, int32_t offset, Register pp, | |
| Condition cond); | |
| void BranchLink(const ExternalLabel *label); | |
| class CodeComment : public ZoneAllocated { | |
| public: | |
| CodeComment(intptr_t pc_offset, const String &comment) | |
| : pc_offset_(pc_offset), comment_(comment) {} | |
| intptr_t pc_offset() const { return pc_offset_; } | |
| const String &comment() const { return comment_; } | |
| private: | |
| intptr_t pc_offset_; | |
| const String &comment_; | |
| DISALLOW_COPY_AND_ASSIGN(CodeComment); | |
| }; | |
| GrowableArray<CodeComment *> comments_; | |
| bool constant_pool_allowed_; | |
| void LoadObjectHelper(Register rd, const Object &object, Condition cond, | |
| bool is_unique, Register pp); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::emitType01() | |
| void EmitType01(Condition cond, | |
| int type, | |
| Opcode opcode, | |
| int set_cc, | |
| Register rn, | |
| Register rd, | |
| Operand o); | |
| // Moved to ARM32::AssemblerARM32::emitType05() | |
| void EmitType5(Condition cond, int32_t offset, bool link); | |
| // Moved to ARM32::AssemberARM32::emitMemOp() | |
| void EmitMemOp(Condition cond, | |
| bool load, | |
| bool byte, | |
| Register rd, | |
| Address ad); | |
| // Moved to AssemblerARM32::emitMemOpEnc3(); | |
| void EmitMemOpAddressMode3(Condition cond, | |
| int32_t mode, | |
| Register rd, | |
| Address ad); | |
| // Moved to ARM32::AssemblerARM32::emitMultiMemOp() | |
| void EmitMultiMemOp(Condition cond, | |
| BlockAddressMode am, | |
| bool load, | |
| Register base, | |
| RegList regs); | |
| #endif | |
| void EmitShiftImmediate(Condition cond, Shift opcode, Register rd, | |
| Register rm, Operand o); | |
| void EmitShiftRegister(Condition cond, Shift opcode, Register rd, Register rm, | |
| Operand o); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::emitMulOp() | |
| void EmitMulOp(Condition cond, | |
| int32_t opcode, | |
| Register rd, | |
| Register rn, | |
| Register rm, | |
| Register rs); | |
| // Moved to ARM32::AssemblerARM32::emitDivOp(); | |
| void EmitDivOp(Condition cond, | |
| int32_t opcode, | |
| Register rd, | |
| Register rn, | |
| Register rm); | |
| #endif | |
| void EmitMultiVSMemOp(Condition cond, BlockAddressMode am, bool load, | |
| Register base, SRegister start, uint32_t count); | |
| void EmitMultiVDMemOp(Condition cond, BlockAddressMode am, bool load, | |
| Register base, DRegister start, int32_t count); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::emitVFPsss | |
| void EmitVFPsss(Condition cond, | |
| int32_t opcode, | |
| SRegister sd, | |
| SRegister sn, | |
| SRegister sm); | |
| // Moved to ARM32::AssemblerARM32::emitVFPddd | |
| void EmitVFPddd(Condition cond, | |
| int32_t opcode, | |
| DRegister dd, | |
| DRegister dn, | |
| DRegister dm); | |
| // Moved to ARM32::AssemblerARM32::emitVFPsd | |
| void EmitVFPsd(Condition cond, | |
| int32_t opcode, | |
| SRegister sd, | |
| DRegister dm); | |
| // Moved to ARM32::AssemblerARM32::emitVFPds | |
| void EmitVFPds(Condition cond, | |
| int32_t opcode, | |
| DRegister dd, | |
| SRegister sm); | |
| // Moved to ARM32::AssemblerARM32::emitSIMDqqq() | |
| void EmitSIMDqqq(int32_t opcode, OperandSize sz, | |
| QRegister qd, QRegister qn, QRegister qm); | |
| #endif | |
| void EmitSIMDddd(int32_t opcode, OperandSize sz, DRegister dd, DRegister dn, | |
| DRegister dm); | |
| void EmitFarBranch(Condition cond, int32_t offset, bool link); | |
| #if 0 | |
| // Moved to ARM32::AssemblerARM32::emitBranch() | |
| void EmitBranch(Condition cond, Label* label, bool link); | |
| // Moved to ARM32::AssemblerARM32::encodeBranchoffset(). | |
| int32_t EncodeBranchOffset(int32_t offset, int32_t inst); | |
| // Moved to ARM32::AssemberARM32::decodeBranchOffset(). | |
| static int32_t DecodeBranchOffset(int32_t inst); | |
| #endif | |
| int32_t EncodeTstOffset(int32_t offset, int32_t inst); | |
| int32_t DecodeTstOffset(int32_t inst); | |
| void StoreIntoObjectFilter(Register object, Register value, Label *no_update); | |
| // Shorter filtering sequence that assumes that value is not a smi. | |
| void StoreIntoObjectFilterNoSmi(Register object, Register value, | |
| Label *no_update); | |
| // Helpers for write-barrier verification. | |
| // Returns VerifiedMemory::offset() as an Operand. | |
| Operand GetVerifiedMemoryShadow(); | |
| // Writes value to [base + offset] and also its shadow location, if enabled. | |
| void WriteShadowedField(Register base, intptr_t offset, Register value, | |
| Condition cond = AL); | |
| void WriteShadowedFieldPair(Register base, intptr_t offset, | |
| Register value_even, Register value_odd, | |
| Condition cond = AL); | |
| // Writes new_value to address and its shadow location, if enabled, after | |
| // verifying that its old value matches its shadow. | |
| void VerifiedWrite(const Address &address, Register new_value, | |
| FieldContent old_content); | |
| #if 0 | |
| // Added the following missing operations: | |
| // | |
| // ARM32::AssemblerARM32::uxt() (uxtb and uxth) | |
| // ARM32::AssemblerARM32::vpop() | |
| // ARM32::AssemblerARM32::vpush() | |
| // ARM32::AssemblerARM32::rbit() | |
| // ARM32::AssemblerARM32::vbslq() | |
| // ARM32::AssemblerARM32::veord() | |
| // ARM32::AssemblerARM32::vld1qr() | |
| // ARM32::AssemblerARM32::vshlqc | |
| // ARM32::AssemblerARM32::vshrqic | |
| // ARM32::AssemblerARM32::vshrquc | |
| // ARM32::AssemblerARM32::vst1qr() | |
| // ARM32::AssemblerARM32::vmorqi() | |
| // ARM32::AssemblerARM32::vmovqc() | |
| #endif | |
| DISALLOW_ALLOCATION(); | |
| DISALLOW_COPY_AND_ASSIGN(Assembler); | |
| }; | |
| } // namespace dart | |
| #endif // VM_ASSEMBLER_ARM_H_ |