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

Unified Diff: runtime/vm/assembler_x64.h

Issue 8747023: Initial revision of assembler for x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month 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 | « no previous file | runtime/vm/assembler_x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/assembler_x64.h
===================================================================
--- runtime/vm/assembler_x64.h (revision 1950)
+++ runtime/vm/assembler_x64.h (working copy)
@@ -11,9 +11,14 @@
#include "vm/assert.h"
#include "vm/constants_x64.h"
+#include "vm/utils.h"
namespace dart {
+// Forward declarations.
+class RuntimeEntry;
+
+
#if defined(TESTING) || defined(DEBUG)
#define CHECK_STACK_ALIGNMENT { \
@@ -27,35 +32,233 @@
#endif
+class Immediate : public ValueObject {
+ public:
+ explicit Immediate(int64_t value) : value_(value) { }
+
+ int64_t value() const { return value_; }
+
+ bool is_int8() const { return Utils::IsInt(8, value_); }
+ bool is_uint8() const { return Utils::IsUint(8, value_); }
+ bool is_uint16() const { return Utils::IsUint(16, value_); }
+ bool is_int32() const { return Utils::IsInt(32, value_); }
+
+ private:
+ const int64_t value_;
+
+ // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac
+ // build issue is resolved.
+};
+
+
+class Operand : public ValueObject {
+ public:
+ uint8_t rex() const {
+ return rex_;
+ }
+
+ uint8_t mod() const {
+ return (encoding_at(0) >> 6) & 3;
+ }
+
+ Register rm() const {
+ int rm_rex = (rex_ & 1) << 3;
+ return static_cast<Register>(rm_rex + (encoding_at(0) & 7));
+ }
+
+ ScaleFactor scale() const {
+ return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
+ }
+
+ Register index() const {
+ int index_rex = (rex_ & 2) << 2;
+ return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7));
+ }
+
+ Register base() const {
+ int base_rex = (rex_ & 1) << 3;
+ return static_cast<Register>(base_rex + (encoding_at(1) & 7));
+ }
+
+ int8_t disp8() const {
+ ASSERT(length_ >= 2);
+ return static_cast<int8_t>(encoding_[length_ - 1]);
+ }
+
+ int32_t disp32() const {
+ ASSERT(length_ >= 5);
+ return bit_copy<int32_t>(encoding_[length_ - 4]);
+ }
+
+ protected:
+ Operand() : length_(0), rex_(0) { }
+
+ void SetModRM(int mod, Register rm) {
+ ASSERT((mod & ~3) == 0);
+ if (rm > 7) rex_ |= 1;
+ encoding_[0] = (mod << 6) | (rm & 7);
+ length_ = 1;
+ }
+
+ void SetSIB(ScaleFactor scale, Register index, Register base) {
+ ASSERT(length_ == 1);
+ ASSERT((scale & ~3) == 0);
+ if (base > 7) {
+ ASSERT((rex_ & 1) == 0); // Must not have REX.B already set.
+ rex_ |= 1;
+ }
+ if (index > 7) rex_ |= 2;
+ encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7);
+ length_ = 2;
+ }
+
+ void SetDisp8(int8_t disp) {
+ ASSERT(length_ == 1 || length_ == 2);
+ encoding_[length_++] = static_cast<uint8_t>(disp);
+ }
+
+ void SetDisp32(int32_t disp) {
+ ASSERT(length_ == 1 || length_ == 2);
+ memmove(&encoding_[length_], &disp, sizeof(disp));
+ length_ += sizeof(disp);
+ }
+
+ private:
+ uint8_t length_;
+ uint8_t rex_;
+ uint8_t encoding_[6];
+
+ explicit Operand(Register reg) : rex_(0) { SetModRM(3, reg); }
+
+ // Get the operand encoding byte at the given index.
+ uint8_t encoding_at(int index) const {
+ ASSERT(index >= 0 && index < length_);
+ return encoding_[index];
+ }
+
+ // Returns whether or not this operand is really the given register in
+ // disguise. Used from the assembler to generate better encodings.
+ bool IsRegister(Register reg) const {
+ return ((reg > 7 ? 1 : 0) == (rex_ & 1)) // REX.B match.
+ && ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register.
+ && ((encoding_at(0) & 0x07) == reg); // Register codes match.
+ }
+
+
+ friend class Assembler;
+
+ // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Operand) once the mac
+ // build issue is resolved.
+};
+
+
+class Address : public Operand {
+ public:
+ Address(Register base, int32_t disp) {
+ if (disp == 0 && base != RBP) {
+ SetModRM(0, base);
+ if (base == RSP) SetSIB(TIMES_1, RSP, base);
+ } else if (Utils::IsInt(8, disp)) {
+ SetModRM(1, base);
+ if (base == RSP) SetSIB(TIMES_1, RSP, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, base);
+ if (base == RSP) SetSIB(TIMES_1, RSP, base);
+ SetDisp32(disp);
+ }
+ }
+
+ Address(Register index, ScaleFactor scale, int32_t disp) {
+ ASSERT(index != RSP); // Illegal addressing mode.
+ SetModRM(0, RSP);
+ SetSIB(scale, index, RBP);
+ SetDisp32(disp);
+ }
+
+ Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
+ ASSERT(index != RSP); // Illegal addressing mode.
+ if (disp == 0 && base != RBP) {
+ SetModRM(0, RSP);
+ SetSIB(scale, index, base);
+ } else if (Utils::IsInt(8, disp)) {
+ SetModRM(1, RSP);
+ SetSIB(scale, index, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, RSP);
+ SetSIB(scale, index, base);
+ SetDisp32(disp);
+ }
+ }
+
+ static Address Absolute(const uword addr) {
+ UNIMPLEMENTED();
+ Address result;
+ result.SetModRM(0, RBP);
+ result.SetDisp32(addr);
+ return result;
+ }
+
+ private:
+ Address() {}
+
+ // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Address) once the mac
+ // build issue is resolved.
+};
+
+
+class FieldAddress : public Address {
+ public:
+ FieldAddress(Register base, int32_t disp)
+ : Address(base, disp - kHeapObjectTag) {}
+ FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp)
+ : Address(base, index, scale, disp - kHeapObjectTag) {}
+};
+
+
class Label : public ValueObject {
public:
- Label() : position_(0) { }
+ Label() : position_(0), unresolved_(0) {
+#ifdef DEBUG
+ for (int i = 0; i < kMaxUnresolvedBranches; i++) {
+ unresolved_near_positions_[i] = -1;
+ }
+#endif // DEBUG
+ }
~Label() {
// Assert if label is being destroyed with unresolved branches pending.
ASSERT(!IsLinked());
+ ASSERT(!HasNear());
}
- // Returns the position for bound and linked labels. Cannot be used
- // for unused labels.
+ // Returns the position for bound labels. Cannot be used for unused or linked
+ // labels.
int Position() const {
- ASSERT(!IsUnused());
- return IsBound() ? -position_ - kWordSize : position_ - kWordSize;
+ ASSERT(IsBound());
+ return -position_ - kWordSize;
}
+ int LinkPosition() const {
+ ASSERT(IsLinked());
+ return position_ - kWordSize;
+ }
+
+ int NearPosition() {
+ ASSERT(HasNear());
+ return unresolved_near_positions_[--unresolved_];
+ }
+
bool IsBound() const { return position_ < 0; }
- bool IsUnused() const { return position_ == 0; }
+ bool IsUnused() const { return (position_ == 0) && (unresolved_ == 0); }
bool IsLinked() const { return position_ > 0; }
+ bool HasNear() const { return unresolved_ != 0; }
private:
- int position_;
-
- void Reinitialize() {
- position_ = 0;
- }
-
void BindTo(int position) {
ASSERT(!IsBound());
+ ASSERT(!HasNear());
position_ = -position - kWordSize;
ASSERT(IsBound());
}
@@ -66,54 +269,349 @@
ASSERT(IsLinked());
}
+ void NearLinkTo(int position) {
+ ASSERT(!IsBound());
+ ASSERT(unresolved_ < kMaxUnresolvedBranches);
+ unresolved_near_positions_[unresolved_++] = position;
+ }
+
+ static const int kMaxUnresolvedBranches = 20;
+
+ int position_;
+ int unresolved_;
+ int unresolved_near_positions_[kMaxUnresolvedBranches];
+
friend class Assembler;
DISALLOW_COPY_AND_ASSIGN(Label);
};
-class Assembler {
+class Assembler : public ValueObject {
public:
- Assembler() { }
+ Assembler() : buffer_(), prolog_offset_(-1) { }
~Assembler() { }
- // Macros for High-level operations.
- void AddConstant(Register reg, int value) {
- UNIMPLEMENTED();
+ static const bool kNearJump = true;
+ static const bool kFarJump = false;
+
+ /*
+ * Emit Machine Instructions.
+ */
+ void call(Register reg);
+ void call(const Address& address);
+ void call(Label* label);
+ void call(const ExternalLabel* label);
+
+ static const intptr_t kCallExternalLabelSize = 5;
+
+ void pushq(Register reg);
+ void pushq(const Address& address);
+
+ void popq(Register reg);
+ void popq(const Address& address);
+
+ void movl(Register dst, Register src);
+ void movl(Register dst, const Immediate& imm);
+ void movl(Register dst, const Address& src);
+ void movl(const Address& dst, Register src);
+
+ void movzxb(Register dst, Register src);
+ void movzxb(Register dst, const Address& src);
+ void movsxb(Register dst, Register src);
+ void movsxb(Register dst, const Address& src);
+ void movb(Register dst, const Address& src);
+ void movb(const Address& dst, Register src);
+ void movb(const Address& dst, const Immediate& imm);
+
+ void movzxw(Register dst, Register src);
+ void movzxw(Register dst, const Address& src);
+ void movsxw(Register dst, Register src);
+ void movsxw(Register dst, const Address& src);
+ void movw(Register dst, const Address& src);
+ void movw(const Address& dst, Register src);
+
+ void movq(Register dst, const Immediate& imm);
+ void movq(Register dst, Register src);
+ void movq(Register dst, const Address& src);
+ void movq(const Address& dst, Register src);
+ void movq(const Address& dst, const Immediate& imm);
+
+ void movsxl(Register dst, const Address& src);
+
+ void leaq(Register dst, const Address& src);
+
+ void movss(XmmRegister dst, const Address& src);
+ void movss(const Address& dst, XmmRegister src);
+ void movss(XmmRegister dst, XmmRegister src);
+
+ void movd(XmmRegister dst, Register src);
+ void movd(Register dst, XmmRegister src);
+
+ void addss(XmmRegister dst, XmmRegister src);
+ void subss(XmmRegister dst, XmmRegister src);
+ void mulss(XmmRegister dst, XmmRegister src);
+ void divss(XmmRegister dst, XmmRegister src);
+
+ void movsd(XmmRegister dst, const Address& src);
+ void movsd(const Address& dst, XmmRegister src);
+ void movsd(XmmRegister dst, XmmRegister src);
+
+ void addsd(XmmRegister dst, XmmRegister src);
+ void subsd(XmmRegister dst, XmmRegister src);
+ void mulsd(XmmRegister dst, XmmRegister src);
+ void divsd(XmmRegister dst, XmmRegister src);
+
+ void xchgl(Register dst, Register src);
+ void xchgq(Register dst, Register src);
+
+ void cmpl(Register reg, const Immediate& imm);
+ void cmpl(Register reg0, Register reg1);
+ void cmpl(Register reg, const Address& address);
+ void cmpl(const Address& address, const Immediate& imm);
+
+ void cmpq(Register reg, const Immediate& imm);
+ void cmpq(const Address& address, const Immediate& imm);
+ void cmpq(Register reg0, Register reg1);
+ void cmpq(Register reg, const Address& address);
+
+ void testl(Register reg1, Register reg2);
+ void testl(Register reg, const Immediate& imm);
+
+ void testq(Register reg1, Register reg2);
+ void testq(Register reg, const Immediate& imm);
+
+ void andl(Register dst, Register src);
+ void andl(Register dst, const Immediate& imm);
+
+ void orl(Register dst, Register src);
+ void orl(Register dst, const Immediate& imm);
+
+ void xorl(Register dst, Register src);
+
+ void andq(Register dst, Register src);
+ void andq(Register dst, const Immediate& imm);
+
+ void orq(Register dst, Register src);
+ void orq(Register dst, const Immediate& imm);
+
+ void xorq(Register dst, Register src);
+
+ void addl(Register dst, Register src);
+ void addl(const Address& address, const Immediate& imm);
+
+ void addq(Register dst, Register src);
+ void addq(Register reg, const Immediate& imm);
+ void addq(const Address& address, const Immediate& imm);
+
+ void subl(Register dst, Register src);
+
+ void cdq();
+ void cqo();
+
+ void idivl(Register reg);
+ void idivq(Register reg);
+
+ void imull(Register dst, Register src);
+ void imull(Register reg, const Immediate& imm);
+
+ void imulq(Register dst, Register src);
+
+ void subq(Register dst, Register src);
+ void subq(Register reg, const Immediate& imm);
+
+ void shll(Register reg, const Immediate& imm);
+ void shll(Register operand, Register shifter);
+ void shrl(Register reg, const Immediate& imm);
+ void shrl(Register operand, Register shifter);
+ void sarl(Register reg, const Immediate& imm);
+ void sarl(Register operand, Register shifter);
+
+ void shlq(Register reg, const Immediate& imm);
+ void shlq(Register operand, Register shifter);
+ void shrq(Register reg, const Immediate& imm);
+ void shrq(Register operand, Register shifter);
+ void sarq(Register reg, const Immediate& imm);
+ void sarq(Register operand, Register shifter);
+
+ void incl(const Address& address);
+ void decl(const Address& address);
+
+ void incq(Register reg);
+ void incq(const Address& address);
+ void decq(Register reg);
+ void decq(const Address& address);
+
+ void negl(Register reg);
+ void negq(Register reg);
+
+ void enter(const Immediate& imm);
+ void leave();
+
+ void ret();
+ void nop();
+ void int3();
+ void hlt();
+
+ void j(Condition condition, Label* label, bool near = kFarJump);
+
+ void jmp(Register reg);
+ void jmp(Label* label, bool near = kFarJump);
+ void jmp(const ExternalLabel* label);
+
+ void lock();
+ void cmpxchgl(const Address& address, Register reg);
+ void lock_cmpxchgl(const Address& address, Register reg) {
+ lock();
+ cmpxchgl(address, reg);
}
- // Misc. functionality
- int CodeSize() const {
- UNIMPLEMENTED();
- return 0;
+ void cmpxchgq(const Address& address, Register reg);
+ void lock_cmpxchgq(const Address& address, Register reg) {
+ lock();
+ cmpxchgq(address, reg);
}
- int prolog_offset() const {
- UNIMPLEMENTED();
- return 0;
+
+ /*
+ * Macros for High-level operations.
+ */
+ void AddImmediate(Register reg, const Immediate& imm);
+
+ void LoadObject(Register dst, const Object& object);
+ void PushObject(const Object& object);
+ void CompareObject(Register reg, const Object& object);
+ void LoadDoubleConstant(XmmRegister dst, double value);
+
+ void StoreIntoObject(Register object, // Object we are storing into.
+ const FieldAddress& dest, // Where we are storing into.
+ Register value); // Value we are storing.
+
+ void DoubleNegate(XmmRegister d);
+ void FloatNegate(XmmRegister f);
+
+ void DoubleAbs(XmmRegister reg);
+
+ void LockCmpxchgl(const Address& address, Register reg) {
+ lock();
+ cmpxchgl(address, reg);
}
+
+ void EnterFrame(intptr_t frame_space);
+ void LeaveFrame();
+
+ void CallRuntimeFromDart(const RuntimeEntry& entry);
+ void CallRuntimeFromStub(const RuntimeEntry& entry);
+
+ /*
+ * Misc. functionality.
+ */
+ void SmiTag(Register reg) {
+ addl(reg, reg);
+ }
+
+ void SmiUntag(Register reg) {
+ sarl(reg, Immediate(kSmiTagSize));
+ }
+
+ int PreferredLoopAlignment() { return 16; }
+ void Align(int alignment, int offset);
+ void Bind(Label* label);
+
+ int CodeSize() const { return buffer_.Size(); }
+ int prolog_offset() const { return prolog_offset_; }
const ZoneGrowableArray<int>& GetPointerOffsets() const {
- UNIMPLEMENTED();
- return *pointer_offsets_;
+ return buffer_.pointer_offsets();
}
+
void FinalizeInstructions(const MemoryRegion& region) {
- UNIMPLEMENTED();
+ buffer_.FinalizeInstructions(region);
}
// Debugging and bringup support.
- void Stop(const char* message) { UNIMPLEMENTED(); }
+ 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) {
- UNIMPLEMENTED();
- }
+ static void InitializeMemoryWithBreakpoints(uword data, int length);
private:
- ZoneGrowableArray<int>* pointer_offsets_;
+ AssemblerBuffer buffer_;
+ int prolog_offset_;
+
+ inline void EmitUint8(uint8_t value);
+ inline void EmitInt32(int32_t value);
+ inline void EmitInt64(int64_t value);
+
+ inline void EmitRegisterREX(Register reg, uint8_t rex);
+ inline void EmitRegisterOperand(int rm, int reg);
+ inline void EmitOperandREX(int rm, const Operand& operand, uint8_t rex);
+ inline void EmitXmmRegisterOperand(int rm, XmmRegister reg);
+ inline void EmitFixup(AssemblerFixup* fixup);
+ inline void EmitOperandSizeOverride();
+
+ void EmitOperand(int rm, const Operand& operand);
+ void EmitImmediate(const Immediate& imm);
+ void EmitComplex(int rm, const Operand& operand, const Immediate& immediate);
+ void EmitLabel(Label* label, int instruction_size);
+ void EmitLabelLink(Label* label);
+ void EmitNearLabelLink(Label* label);
+
+ void EmitGenericShift(bool wide, int rm, Register reg, const Immediate& imm);
+ void EmitGenericShift(bool wide, int rm, Register operand, Register shifter);
+
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
+
+enum {
+ REX_NONE = 0,
+ REX_B = 1 << 0,
+ REX_X = 1 << 1,
+ REX_R = 1 << 2,
+ REX_W = 1 << 3
+};
+
+
+inline void Assembler::EmitUint8(uint8_t value) {
+ buffer_.Emit<uint8_t>(value);
+}
+
+
+inline void Assembler::EmitInt32(int32_t value) {
+ buffer_.Emit<int32_t>(value);
+}
+
+
+inline void Assembler::EmitInt64(int64_t value) {
+ buffer_.Emit<int64_t>(value);
+}
+
+
+inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) {
+ ASSERT(reg != kNoRegister);
+ rex |= (reg > 7 ? REX_B : REX_NONE);
+ if (rex != 0) EmitUint8(0x40 | rex);
+}
+
+
+inline void Assembler::EmitOperandREX(int rm,
+ const Operand& operand,
+ uint8_t rex) {
+ rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex();
+ if (rex != 0) EmitUint8(0x40 | rex);
+}
+
+
+inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
+ buffer_.EmitFixup(fixup);
+}
+
+
+inline void Assembler::EmitOperandSizeOverride() {
+ EmitUint8(0x66);
+}
+
} // namespace dart
#endif // VM_ASSEMBLER_X64_H_
« no previous file with comments | « no previous file | runtime/vm/assembler_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698