Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Unified Diff: src/DartARM32/assembler_arm.h

Issue 1394613002: Create local copy of Dart assembler code. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Blacklist ARM32 Dart files. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Makefile.standalone ('k') | src/DartARM32/assembler_arm.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/DartARM32/assembler_arm.h
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
new file mode 100644
index 0000000000000000000000000000000000000000..c686d600433ad1b79e716436ae46a5172d5cf2e7
--- /dev/null
+++ b/src/DartARM32/assembler_arm.h
@@ -0,0 +1,1214 @@
+// 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;
+
+
+// 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,
+};
+
+
+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;
+ }
+
+ // Data-processing operands - Immediate.
+ explicit Operand(uint32_t immediate) {
+ ASSERT(immediate < (1 << kImmed8Bits));
+ type_ = 1;
+ encoding_ = immediate;
+ }
+
+ // 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);
+ }
+
+ // Data-processing operands - Register.
+ explicit Operand(Register rm) {
+ type_ = 0;
+ encoding_ = static_cast<uint32_t>(rm);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ 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;
+ }
+
+ 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 {
+ // 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
+};
+
+
+class Address : public ValueObject {
+ public:
+ enum OffsetKind {
+ Immediate,
+ IndexRegister,
+ ScaledIndexRegister,
+ };
+
+ // Memory operand addressing mode
+ enum Mode {
+ 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
+ };
+
+ 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_);
+ }
+
+ 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;
+ }
+
+ // 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_; }
+
+ // Encoding for addressing mode 3.
+ uint32_t encoding3() const;
+
+ // 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& region) {
+ 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);
+
+ // Data-processing instructions.
+ void and_(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void eor(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void sub(Register rd, Register rn, Operand o, Condition cond = AL);
+ void subs(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void rsb(Register rd, Register rn, Operand o, Condition cond = AL);
+ void rsbs(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void add(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void adds(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void adc(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void adcs(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void sbc(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void sbcs(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void rsc(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void tst(Register rn, Operand o, Condition cond = AL);
+
+ void teq(Register rn, Operand o, Condition cond = AL);
+
+ void cmp(Register rn, Operand o, Condition cond = AL);
+
+ void cmn(Register rn, Operand o, Condition cond = AL);
+
+ void orr(Register rd, Register rn, Operand o, Condition cond = AL);
+ void orrs(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void mov(Register rd, Operand o, Condition cond = AL);
+ void movs(Register rd, Operand o, Condition cond = AL);
+
+ void bic(Register rd, Register rn, Operand o, Condition cond = AL);
+ void bics(Register rd, Register rn, Operand o, Condition cond = AL);
+
+ void mvn(Register rd, Operand o, Condition cond = AL);
+ void mvns(Register rd, Operand o, Condition cond = AL);
+
+ // Miscellaneous data-processing instructions.
+ void clz(Register rd, Register rm, Condition cond = AL);
+
+ // Multiply instructions.
+ void mul(Register rd, Register rn, Register rm, Condition cond = AL);
+ void muls(Register rd, Register rn, Register rm, Condition cond = AL);
+ void mla(Register rd, Register rn, Register rm, Register ra,
+ Condition cond = AL);
+ void mls(Register rd, Register rn, Register rm, Register ra,
+ Condition cond = AL);
+ void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL);
+ void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL);
+ 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.
+ void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
+ void udiv(Register rd, Register rn, Register rm, Condition cond = AL);
+
+ // Load/store instructions.
+ void ldr(Register rd, Address ad, Condition cond = AL);
+ void str(Register rd, Address ad, Condition cond = AL);
+
+ void ldrb(Register rd, Address ad, Condition cond = AL);
+ void strb(Register rd, Address ad, Condition cond = AL);
+
+ void ldrh(Register rd, Address ad, Condition cond = AL);
+ void strh(Register rd, Address ad, Condition cond = AL);
+
+ 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);
+
+ void ldm(BlockAddressMode am, Register base,
+ RegList regs, Condition cond = AL);
+ void stm(BlockAddressMode am, Register base,
+ RegList regs, Condition cond = AL);
+
+ void ldrex(Register rd, Register rn, Condition cond = AL);
+ void strex(Register rd, Register rt, Register rn, Condition cond = AL);
+
+ // Miscellaneous instructions.
+ void clrex();
+ void nop(Condition cond = AL);
+
+ // 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);
+ }
+
+ static uword GetBreakInstructionFiller() {
+ return BkptEncoding(0);
+ }
+
+ // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
+ void vmovsr(SRegister sn, Register rt, Condition cond = AL);
+ void vmovrs(Register rt, SRegister sn, Condition cond = AL);
+ void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL);
+ void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL);
+ void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL);
+ void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL);
+ void vmovdr(DRegister dd, int i, Register rt, Condition cond = AL);
+ void vmovs(SRegister sd, SRegister sm, Condition cond = AL);
+ void vmovd(DRegister dd, DRegister dm, Condition cond = AL);
+ void vmovq(QRegister qd, QRegister qm);
+
+ // Returns false if the immediate cannot be encoded.
+ bool vmovs(SRegister sd, float s_imm, Condition cond = AL);
+ bool vmovd(DRegister dd, double d_imm, Condition cond = AL);
+
+ void vldrs(SRegister sd, Address ad, Condition cond = AL);
+ void vstrs(SRegister sd, Address ad, Condition cond = AL);
+ void vldrd(DRegister dd, Address ad, Condition cond = AL);
+ void vstrd(DRegister dd, Address ad, Condition cond = AL);
+
+ 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);
+
+ void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vaddqs(QRegister qd, QRegister qn, QRegister qm);
+ void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vsubqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vsubqs(QRegister qd, QRegister qn, QRegister qm);
+ void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vmulqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vmulqs(QRegister qd, QRegister qn, QRegister qm);
+ void vshlqi(OperandSize sz, QRegister qd, QRegister qm, QRegister qn);
+ void vshlqu(OperandSize sz, QRegister qd, QRegister qm, QRegister qn);
+ void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+ void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ 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);
+
+ void veorq(QRegister qd, QRegister qn, QRegister qm);
+ void vorrq(QRegister qd, QRegister qn, QRegister qm);
+ void vornq(QRegister qd, QRegister qn, QRegister qm);
+ void vandq(QRegister qd, QRegister qn, QRegister qm);
+ void vmvnq(QRegister qd, QRegister qm);
+
+ void vceqqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vceqqs(QRegister qd, QRegister qn, QRegister qm);
+ void vcgeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vcugeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vcgeqs(QRegister qd, QRegister qn, QRegister qm);
+ void vcgtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vcugtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vcgtqs(QRegister qd, QRegister qn, QRegister qm);
+
+ void vabss(SRegister sd, SRegister sm, Condition cond = AL);
+ void vabsd(DRegister dd, DRegister dm, Condition cond = AL);
+ void vabsqs(QRegister qd, QRegister qm);
+ void vnegs(SRegister sd, SRegister sm, Condition cond = AL);
+ void vnegd(DRegister dd, DRegister dm, Condition cond = AL);
+ void vnegqs(QRegister qd, QRegister qm);
+ void vsqrts(SRegister sd, SRegister sm, Condition cond = AL);
+ void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL);
+
+ void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL);
+ void vcvtds(DRegister dd, SRegister sm, Condition cond = AL);
+ void vcvtis(SRegister sd, SRegister sm, Condition cond = AL);
+ void vcvtid(SRegister sd, DRegister dm, Condition cond = AL);
+ void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL);
+ void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL);
+ void vcvtus(SRegister sd, SRegister sm, Condition cond = AL);
+ void vcvtud(SRegister sd, DRegister dm, Condition cond = AL);
+ void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL);
+ void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL);
+
+ void vcmps(SRegister sd, SRegister sm, Condition cond = AL);
+ void vcmpd(DRegister dd, DRegister dm, Condition cond = AL);
+ void vcmpsz(SRegister sd, Condition cond = AL);
+ void vcmpdz(DRegister dd, Condition cond = AL);
+ void vmrs(Register rd, Condition cond = AL);
+ 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.
+ void b(Label* label, Condition cond = AL);
+ void bl(Label* label, Condition cond = AL);
+ void bx(Register rm, Condition cond = AL);
+ void blx(Register rm, Condition cond = AL);
+
+ 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);
+
+ void Push(Register rd, Condition cond = AL);
+ void Pop(Register rd, Condition cond = AL);
+
+ void PushList(RegList regs, Condition cond = AL);
+ void PopList(RegList regs, Condition cond = AL);
+
+ void MoveRegister(Register rd, Register rm, Condition cond = AL);
+
+ // Convenience shift instructions. Use mov instruction with shifter operand
+ // for variants setting the status flags.
+ void Lsl(Register rd, Register rm, const Operand& shift_imm,
+ Condition cond = AL);
+ void Lsl(Register rd, Register rm, Register rs, Condition cond = AL);
+ void Lsr(Register rd, Register rm, const Operand& shift_imm,
+ Condition cond = AL);
+ void Lsr(Register rd, Register rm, Register rs, Condition cond = AL);
+ void Asr(Register rd, Register rm, const Operand& shift_imm,
+ Condition cond = AL);
+ void Asr(Register rd, Register rm, Register rs, Condition cond = AL);
+ 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 you are thinking of using one or both of these instructions directly,
+ // instead LoadImmediate should probably be used.
+ void movw(Register rd, uint16_t imm16, Condition cond = AL);
+ void movt(Register rd, uint16_t imm16, Condition cond = AL);
+
+ 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);
+
+ void EmitType01(Condition cond,
+ int type,
+ Opcode opcode,
+ int set_cc,
+ Register rn,
+ Register rd,
+ Operand o);
+
+ void EmitType5(Condition cond, int32_t offset, bool link);
+
+ void EmitMemOp(Condition cond,
+ bool load,
+ bool byte,
+ Register rd,
+ Address ad);
+
+ void EmitMemOpAddressMode3(Condition cond,
+ int32_t mode,
+ Register rd,
+ Address ad);
+
+ void EmitMultiMemOp(Condition cond,
+ BlockAddressMode am,
+ bool load,
+ Register base,
+ RegList regs);
+
+ void EmitShiftImmediate(Condition cond,
+ Shift opcode,
+ Register rd,
+ Register rm,
+ Operand o);
+
+ void EmitShiftRegister(Condition cond,
+ Shift opcode,
+ Register rd,
+ Register rm,
+ Operand o);
+
+ void EmitMulOp(Condition cond,
+ int32_t opcode,
+ Register rd,
+ Register rn,
+ Register rm,
+ Register rs);
+
+ void EmitDivOp(Condition cond,
+ int32_t opcode,
+ Register rd,
+ Register rn,
+ Register rm);
+
+ 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);
+
+ void EmitVFPsss(Condition cond,
+ int32_t opcode,
+ SRegister sd,
+ SRegister sn,
+ SRegister sm);
+
+ void EmitVFPddd(Condition cond,
+ int32_t opcode,
+ DRegister dd,
+ DRegister dn,
+ DRegister dm);
+
+ void EmitVFPsd(Condition cond,
+ int32_t opcode,
+ SRegister sd,
+ DRegister dm);
+
+ void EmitVFPds(Condition cond,
+ int32_t opcode,
+ DRegister dd,
+ SRegister sm);
+
+ void EmitSIMDqqq(int32_t opcode, OperandSize sz,
+ QRegister qd, QRegister qn, QRegister qm);
+
+ void EmitSIMDddd(int32_t opcode, OperandSize sz,
+ DRegister dd, DRegister dn, DRegister dm);
+
+ void EmitFarBranch(Condition cond, int32_t offset, bool link);
+ void EmitBranch(Condition cond, Label* label, bool link);
+ int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
+ static int32_t DecodeBranchOffset(int32_t inst);
+ 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);
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(Assembler);
+};
+
+} // namespace dart
+
+#endif // VM_ASSEMBLER_ARM_H_
« no previous file with comments | « Makefile.standalone ('k') | src/DartARM32/assembler_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698