5675b85979
RFC: First draft showing how generated ARM code accesses GC'ed objects and accesses patched call targets. Review URL: https://codereview.chromium.org//12224024 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18200 260f80e4-7a28-3924-810f-c04153c831b5
645 lines
22 KiB
C++
645 lines
22 KiB
C++
// 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.
|
|
|
|
#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"
|
|
|
|
namespace dart {
|
|
|
|
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.
|
|
int 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:
|
|
int position_;
|
|
|
|
void Reinitialize() {
|
|
position_ = 0;
|
|
}
|
|
|
|
void BindTo(int position) {
|
|
ASSERT(!IsBound());
|
|
position_ = -position - kWordSize;
|
|
ASSERT(IsBound());
|
|
}
|
|
|
|
void LinkTo(int position) {
|
|
ASSERT(!IsBound());
|
|
position_ = position + kWordSize;
|
|
ASSERT(IsLinked());
|
|
}
|
|
|
|
friend class Assembler;
|
|
DISALLOW_COPY_AND_ASSIGN(Label);
|
|
};
|
|
|
|
|
|
class CPUFeatures : public AllStatic {
|
|
public:
|
|
static void InitOnce() { }
|
|
static bool double_truncate_round_supported() {
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
// Encodes Addressing Mode 1 - Data-processing operands.
|
|
class ShifterOperand : public ValueObject {
|
|
public:
|
|
// Data-processing operands - Uninitialized.
|
|
ShifterOperand() : type_(-1) { }
|
|
|
|
// Data-processing operands - Copy constructor.
|
|
ShifterOperand(const ShifterOperand& other)
|
|
: ValueObject(), type_(other.type_), encoding_(other.encoding_) { }
|
|
|
|
// Data-processing operands - Assignment operator.
|
|
ShifterOperand& operator=(const ShifterOperand& other) {
|
|
type_ = other.type_;
|
|
encoding_ = other.encoding_;
|
|
return *this;
|
|
}
|
|
|
|
// Data-processing operands - Immediate.
|
|
explicit ShifterOperand(uint32_t immediate) {
|
|
ASSERT(immediate < (1 << kImmed8Bits));
|
|
type_ = 1;
|
|
encoding_ = immediate;
|
|
}
|
|
|
|
// Data-processing operands - Rotated immediate.
|
|
ShifterOperand(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 ShifterOperand(Register rm) {
|
|
type_ = 0;
|
|
encoding_ = static_cast<uint32_t>(rm);
|
|
}
|
|
|
|
// Data-processing operands - Logical shift/rotate by immediate.
|
|
ShifterOperand(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.
|
|
ShifterOperand(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, ShifterOperand* shifter_op) {
|
|
// Avoid the more expensive test for frequent small immediate values.
|
|
if (immediate < (1 << kImmed8Bits)) {
|
|
shifter_op->type_ = 1;
|
|
shifter_op->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)) {
|
|
shifter_op->type_ = 1;
|
|
shifter_op->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;
|
|
};
|
|
|
|
|
|
enum LoadOperandType {
|
|
kLoadSignedByte,
|
|
kLoadUnsignedByte,
|
|
kLoadSignedHalfword,
|
|
kLoadUnsignedHalfword,
|
|
kLoadWord,
|
|
kLoadWordPair,
|
|
kLoadSWord,
|
|
kLoadDWord
|
|
};
|
|
|
|
|
|
enum StoreOperandType {
|
|
kStoreByte,
|
|
kStoreHalfword,
|
|
kStoreWord,
|
|
kStoreWordPair,
|
|
kStoreSWord,
|
|
kStoreDWord
|
|
};
|
|
|
|
|
|
// 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:
|
|
// Memory operand addressing mode
|
|
enum Mode {
|
|
// 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_) { }
|
|
|
|
Address& operator=(const Address& other) {
|
|
encoding_ = other.encoding_;
|
|
return *this;
|
|
}
|
|
|
|
explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) {
|
|
ASSERT(Utils::IsAbsoluteUint(12, offset));
|
|
if (offset < 0) {
|
|
encoding_ = (am ^ (1 << kUShift)) | -offset; // Flip U to adjust sign.
|
|
} else {
|
|
encoding_ = am | offset;
|
|
}
|
|
encoding_ |= static_cast<uint32_t>(rn) << kRnShift;
|
|
}
|
|
|
|
static bool CanHoldLoadOffset(LoadOperandType type, int offset);
|
|
static bool CanHoldStoreOffset(StoreOperandType type, int offset);
|
|
|
|
private:
|
|
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;
|
|
|
|
uint32_t encoding_;
|
|
|
|
friend class Assembler;
|
|
};
|
|
|
|
|
|
class FieldAddress : public Address {
|
|
public:
|
|
FieldAddress(Register base, int32_t disp)
|
|
: Address(base, disp - kHeapObjectTag) { }
|
|
|
|
FieldAddress(const FieldAddress& other) : Address(other) { }
|
|
|
|
FieldAddress& operator=(const FieldAddress& other) {
|
|
Address::operator=(other);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
class Assembler : public ValueObject {
|
|
public:
|
|
Assembler()
|
|
: buffer_(),
|
|
object_pool_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
|
|
prologue_offset_(-1),
|
|
comments_() { }
|
|
~Assembler() { }
|
|
|
|
void PopRegister(Register r) { Pop(r); }
|
|
|
|
void Bind(Label* label);
|
|
|
|
// Misc. functionality
|
|
int CodeSize() const { return buffer_.Size(); }
|
|
int prologue_offset() const { return prologue_offset_; }
|
|
const ZoneGrowableArray<int>& GetPointerOffsets() const {
|
|
ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code.
|
|
return buffer_.pointer_offsets();
|
|
}
|
|
const GrowableObjectArray& object_pool() const {
|
|
return object_pool_;
|
|
}
|
|
|
|
void FinalizeInstructions(const MemoryRegion& region) {
|
|
buffer_.FinalizeInstructions(region);
|
|
ASSERT(object_pool_.Length() == 0); // TODO(regis): Otherwise, more work.
|
|
}
|
|
|
|
// 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, int length);
|
|
|
|
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
|
|
|
|
const Code::Comments& GetCodeComments() const;
|
|
|
|
static const char* RegisterName(Register reg) {
|
|
UNIMPLEMENTED();
|
|
return NULL;
|
|
}
|
|
|
|
static const char* FpuRegisterName(FpuRegister reg) {
|
|
UNIMPLEMENTED();
|
|
return NULL;
|
|
}
|
|
|
|
// Data-processing instructions.
|
|
void and_(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void eor(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void sub(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
void subs(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void rsb(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
void rsbs(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void add(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void adds(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void adc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void sbc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void rsc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void tst(Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void teq(Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void cmp(Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void cmn(Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void orr(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
void orrs(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void mov(Register rd, ShifterOperand so, Condition cond = AL);
|
|
void movs(Register rd, ShifterOperand so, Condition cond = AL);
|
|
|
|
void bic(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
|
|
|
|
void mvn(Register rd, ShifterOperand so, Condition cond = AL);
|
|
void mvns(Register rd, ShifterOperand so, Condition cond = AL);
|
|
|
|
// Miscellaneous data-processing instructions.
|
|
void clz(Register rd, Register rm, Condition cond = AL);
|
|
void movw(Register rd, uint16_t imm16, Condition cond = AL);
|
|
void movt(Register rd, uint16_t imm16, Condition cond = AL);
|
|
|
|
// Multiply instructions.
|
|
void mul(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 umull(Register rd_lo, Register rd_hi, 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);
|
|
|
|
void ldrd(Register rd, Address ad, Condition cond = AL);
|
|
void strd(Register rd, Address ad, 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);
|
|
void svc(uint32_t imm24);
|
|
|
|
// 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 vmovs(SRegister sd, SRegister sm, Condition cond = AL);
|
|
void vmovd(DRegister dd, DRegister dm, Condition cond = AL);
|
|
|
|
// 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 vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
|
|
void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
|
|
void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
|
|
void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
|
|
void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
|
|
void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
|
|
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 vabss(SRegister sd, SRegister sm, Condition cond = AL);
|
|
void vabsd(DRegister dd, DRegister dm, Condition cond = AL);
|
|
void vnegs(SRegister sd, SRegister sm, Condition cond = AL);
|
|
void vnegd(DRegister dd, DRegister dm, Condition cond = AL);
|
|
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 vmstat(Condition cond = AL); // VMRS APSR_nzcv, FPSCR
|
|
|
|
// Branch instructions.
|
|
void b(Label* label, Condition cond = AL);
|
|
void bl(Label* label, Condition cond = AL);
|
|
void blx(Register rm, Condition cond = AL);
|
|
|
|
// Macros.
|
|
// Branch to an entry address that can be patched at runtime.
|
|
void Branch(const ExternalLabel* label);
|
|
void BranchLink(const ExternalLabel* label);
|
|
|
|
// Branch to entry after setting LR and storing LR at ad.
|
|
void BranchLinkStore(const ExternalLabel* label, Address ad);
|
|
|
|
// Branch to [base + offset] after setting LR.
|
|
void BranchLinkOffset(Register base, int offset);
|
|
|
|
// Add signed constant value to rd. May clobber IP.
|
|
void AddConstant(Register rd, int32_t value, Condition cond = AL);
|
|
void AddConstant(Register rd, Register rn, int32_t value,
|
|
Condition cond = AL);
|
|
void AddConstantSetFlags(Register rd, Register rn, int32_t value,
|
|
Condition cond = AL);
|
|
void AddConstantWithCarry(Register rd, Register rn, int32_t value,
|
|
Condition cond = AL);
|
|
|
|
// Load and Store. May clobber IP.
|
|
void LoadImmediate(Register rd, int32_t value, Condition cond = AL);
|
|
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 LoadObject(Register rd, const Object& object);
|
|
void LoadFromOffset(LoadOperandType type,
|
|
Register reg,
|
|
Register base,
|
|
int32_t offset,
|
|
Condition cond = AL);
|
|
void StoreToOffset(StoreOperandType 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 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 Mov(Register rd, Register rm, Condition cond = AL);
|
|
|
|
// Convenience shift instructions. Use mov instruction with shifter operand
|
|
// for variants setting the status flags or using a register shift count.
|
|
void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
|
|
void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
|
|
void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
|
|
void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
|
|
void Rrx(Register rd, Register rm, Condition cond = AL);
|
|
|
|
// Emit data (e.g encoded instruction or immediate) in instruction stream.
|
|
void Emit(int32_t value);
|
|
|
|
private:
|
|
AssemblerBuffer buffer_; // Contains position independent code.
|
|
const GrowableObjectArray& object_pool_; // Objects and jump targets.
|
|
int32_t prologue_offset_;
|
|
|
|
int32_t AddObject(const Object& obj);
|
|
int32_t AddExternalLabel(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_;
|
|
|
|
void EmitType01(Condition cond,
|
|
int type,
|
|
Opcode opcode,
|
|
int set_cc,
|
|
Register rn,
|
|
Register rd,
|
|
ShifterOperand so);
|
|
|
|
void EmitType5(Condition cond, int 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,
|
|
ShifterOperand so);
|
|
|
|
void EmitShiftRegister(Condition cond,
|
|
Shift opcode,
|
|
Register rd,
|
|
Register rm,
|
|
ShifterOperand so);
|
|
|
|
void EmitMulOp(Condition cond,
|
|
int32_t opcode,
|
|
Register rd,
|
|
Register rn,
|
|
Register rm,
|
|
Register rs);
|
|
|
|
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 EmitBranch(Condition cond, Label* label, bool link);
|
|
static int32_t EncodeBranchOffset(int offset, int32_t inst);
|
|
static int DecodeBranchOffset(int32_t inst);
|
|
int32_t EncodeTstOffset(int offset, int32_t inst);
|
|
int DecodeTstOffset(int32_t inst);
|
|
|
|
// Returns whether or not the given register is used for passing parameters.
|
|
static int RegisterCompare(const Register* reg1, const Register* reg2) {
|
|
return *reg1 - *reg2;
|
|
}
|
|
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_COPY_AND_ASSIGN(Assembler);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // VM_ASSEMBLER_ARM_H_
|