Add basic assembler interface and an x86 backend.
Change-Id: Ia8136bad88f1194c8a247e2af80e486ab88c1e8c
diff --git a/src/assembler_x86.h b/src/assembler_x86.h
new file mode 100644
index 0000000..05dfe31
--- /dev/null
+++ b/src/assembler_x86.h
@@ -0,0 +1,479 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_ASSEMBLER_X86_H_
+#define ART_SRC_ASSEMBLER_X86_H_
+
+#include <stdint.h>
+#include <string.h>
+#include "src/constants_x86.h"
+#include "src/macros.h"
+#include "src/utils.h"
+
+namespace android {
+namespace runtime {
+
+class Immediate {
+ public:
+ explicit Immediate(int32_t value) : value_(value) {}
+
+ int32_t value() const { return value_; }
+
+ bool is_int8() const { return IsInt(8, value_); }
+ bool is_uint8() const { return IsUint(8, value_); }
+ bool is_uint16() const { return IsUint(16, value_); }
+
+ private:
+ const int32_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(Immediate);
+};
+
+
+class Operand {
+ public:
+ uint8_t mod() const {
+ return (encoding_at(0) >> 6) & 3;
+ }
+
+ Register rm() const {
+ return static_cast<Register>(encoding_at(0) & 7);
+ }
+
+ ScaleFactor scale() const {
+ return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
+ }
+
+ Register index() const {
+ return static_cast<Register>((encoding_at(1) >> 3) & 7);
+ }
+
+ Register base() const {
+ return static_cast<Register>(encoding_at(1) & 7);
+ }
+
+ int8_t disp8() const {
+ CHECK_GE(length_, 2);
+ return static_cast<int8_t>(encoding_[length_ - 1]);
+ }
+
+ int32_t disp32() const {
+ CHECK_GE(length_, 5);
+ int32_t value;
+ memcpy(&value, &encoding_[length_ - 4], sizeof(value));
+ return value;
+ }
+
+ bool IsRegister(Register reg) const {
+ return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only.
+ && ((encoding_[0] & 0x07) == reg); // Register codes match.
+ }
+
+ protected:
+ // Operand can be sub classed (e.g: Address).
+ Operand() : length_(0) { }
+
+ void SetModRM(int mod, Register rm) {
+ CHECK_EQ(mod & ~3, 0);
+ encoding_[0] = (mod << 6) | rm;
+ length_ = 1;
+ }
+
+ void SetSIB(ScaleFactor scale, Register index, Register base) {
+ CHECK_EQ(length_, 1);
+ CHECK_EQ(scale & ~3, 0);
+ encoding_[1] = (scale << 6) | (index << 3) | base;
+ length_ = 2;
+ }
+
+ void SetDisp8(int8_t disp) {
+ CHECK(length_ == 1 || length_ == 2);
+ encoding_[length_++] = static_cast<uint8_t>(disp);
+ }
+
+ void SetDisp32(int32_t disp) {
+ CHECK(length_ == 1 || length_ == 2);
+ int disp_size = sizeof(disp);
+ memmove(&encoding_[length_], &disp, disp_size);
+ length_ += disp_size;
+ }
+
+ private:
+ byte length_;
+ byte encoding_[6];
+ byte padding_;
+
+ explicit Operand(Register reg) { SetModRM(3, reg); }
+
+ // Get the operand encoding byte at the given index.
+ uint8_t encoding_at(int index) const {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, length_);
+ return encoding_[index];
+ }
+
+ friend class Assembler;
+
+ DISALLOW_COPY_AND_ASSIGN(Operand);
+};
+
+
+class Address : public Operand {
+ public:
+ Address(Register base, int32_t disp) {
+ if (disp == 0 && base != EBP) {
+ SetModRM(0, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ } else if (disp >= -128 && disp <= 127) {
+ SetModRM(1, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ SetDisp32(disp);
+ }
+ }
+
+ Address(Register index, ScaleFactor scale, int32_t disp) {
+ CHECK_NE(index, ESP); // Illegal addressing mode.
+ SetModRM(0, ESP);
+ SetSIB(scale, index, EBP);
+ SetDisp32(disp);
+ }
+
+ Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
+ CHECK_NE(index, ESP); // Illegal addressing mode.
+ if (disp == 0 && base != EBP) {
+ SetModRM(0, ESP);
+ SetSIB(scale, index, base);
+ } else if (disp >= -128 && disp <= 127) {
+ SetModRM(1, ESP);
+ SetSIB(scale, index, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, ESP);
+ SetSIB(scale, index, base);
+ SetDisp32(disp);
+ }
+ }
+
+ static Address Absolute(const uword addr) {
+ Address result;
+ result.SetModRM(0, EBP);
+ result.SetDisp32(addr);
+ return result;
+ }
+
+ private:
+ Address() {}
+
+ DISALLOW_COPY_AND_ASSIGN(Address);
+};
+
+
+class Assembler {
+ public:
+ Assembler() : buffer_() {}
+ ~Assembler() {}
+
+ /*
+ * Emit Machine Instructions.
+ */
+ void call(Register reg);
+ void call(const Address& address);
+ void call(Label* label);
+
+ void pushl(Register reg);
+ void pushl(const Address& address);
+ void pushl(const Immediate& imm);
+
+ void popl(Register reg);
+ void popl(const Address& address);
+
+ void movl(Register dst, const Immediate& src);
+ void movl(Register dst, Register src);
+
+ void movl(Register dst, const Address& src);
+ void movl(const Address& dst, Register src);
+ void movl(const Address& dst, const Immediate& imm);
+
+ void movzxb(Register dst, ByteRegister src);
+ void movzxb(Register dst, const Address& src);
+ void movsxb(Register dst, ByteRegister src);
+ void movsxb(Register dst, const Address& src);
+ void movb(Register dst, const Address& src);
+ void movb(const Address& dst, ByteRegister 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 leal(Register dst, const Address& src);
+
+ void cmovs(Register dst, Register src);
+ void cmovns(Register dst, Register 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 addss(XmmRegister dst, const Address& src);
+ void subss(XmmRegister dst, XmmRegister src);
+ void subss(XmmRegister dst, const Address& src);
+ void mulss(XmmRegister dst, XmmRegister src);
+ void mulss(XmmRegister dst, const Address& src);
+ void divss(XmmRegister dst, XmmRegister src);
+ void divss(XmmRegister dst, const Address& 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 addsd(XmmRegister dst, const Address& src);
+ void subsd(XmmRegister dst, XmmRegister src);
+ void subsd(XmmRegister dst, const Address& src);
+ void mulsd(XmmRegister dst, XmmRegister src);
+ void mulsd(XmmRegister dst, const Address& src);
+ void divsd(XmmRegister dst, XmmRegister src);
+ void divsd(XmmRegister dst, const Address& src);
+
+ void cvtsi2ss(XmmRegister dst, Register src);
+ void cvtsi2sd(XmmRegister dst, Register src);
+
+ void cvtss2si(Register dst, XmmRegister src);
+ void cvtss2sd(XmmRegister dst, XmmRegister src);
+
+ void cvtsd2si(Register dst, XmmRegister src);
+ void cvtsd2ss(XmmRegister dst, XmmRegister src);
+
+ void cvttss2si(Register dst, XmmRegister src);
+ void cvttsd2si(Register dst, XmmRegister src);
+
+ void cvtdq2pd(XmmRegister dst, XmmRegister src);
+
+ void comiss(XmmRegister a, XmmRegister b);
+ void comisd(XmmRegister a, XmmRegister b);
+
+ void sqrtsd(XmmRegister dst, XmmRegister src);
+ void sqrtss(XmmRegister dst, XmmRegister src);
+
+ void xorpd(XmmRegister dst, const Address& src);
+ void xorpd(XmmRegister dst, XmmRegister src);
+ void xorps(XmmRegister dst, const Address& src);
+ void xorps(XmmRegister dst, XmmRegister src);
+
+ void andpd(XmmRegister dst, const Address& src);
+
+ void flds(const Address& src);
+ void fstps(const Address& dst);
+
+ void fldl(const Address& src);
+ void fstpl(const Address& dst);
+
+ void fnstcw(const Address& dst);
+ void fldcw(const Address& src);
+
+ void fistpl(const Address& dst);
+ void fistps(const Address& dst);
+ void fildl(const Address& src);
+
+ void fincstp();
+ void ffree(const Immediate& index);
+
+ void fsin();
+ void fcos();
+ void fptan();
+
+ void xchgl(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, Register reg);
+ void cmpl(const Address& address, const Immediate& imm);
+
+ void testl(Register reg1, Register reg2);
+ void testl(Register reg, const Immediate& imm);
+
+ void andl(Register dst, const Immediate& imm);
+ void andl(Register dst, Register src);
+
+ void orl(Register dst, const Immediate& imm);
+ void orl(Register dst, Register src);
+
+ void xorl(Register dst, Register src);
+
+ void addl(Register dst, Register src);
+ void addl(Register reg, const Immediate& imm);
+ void addl(Register reg, const Address& address);
+
+ void addl(const Address& address, Register reg);
+ void addl(const Address& address, const Immediate& imm);
+
+ void adcl(Register dst, Register src);
+ void adcl(Register reg, const Immediate& imm);
+ void adcl(Register dst, const Address& address);
+
+ void subl(Register dst, Register src);
+ void subl(Register reg, const Immediate& imm);
+ void subl(Register reg, const Address& address);
+
+ void cdq();
+
+ void idivl(Register reg);
+
+ void imull(Register dst, Register src);
+ void imull(Register reg, const Immediate& imm);
+ void imull(Register reg, const Address& address);
+
+ void imull(Register reg);
+ void imull(const Address& address);
+
+ void mull(Register reg);
+ void mull(const Address& address);
+
+ void sbbl(Register dst, Register src);
+ void sbbl(Register reg, const Immediate& imm);
+ void sbbl(Register reg, const Address& address);
+
+ void incl(Register reg);
+ void incl(const Address& address);
+
+ void decl(Register reg);
+ void decl(const Address& address);
+
+ 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 shld(Register dst, Register src);
+
+ void negl(Register reg);
+ void notl(Register reg);
+
+ void enter(const Immediate& imm);
+ void leave();
+
+ void ret();
+ void ret(const Immediate& imm);
+
+ void nop();
+ void int3();
+ void hlt();
+
+ void j(Condition condition, Label* label);
+
+ void jmp(Register reg);
+ void jmp(Label* label);
+
+ void lock();
+ void cmpxchgl(const Address& address, Register reg);
+
+ /*
+ * Macros for High-level operations.
+ */
+ void AddImmediate(Register reg, const Immediate& imm);
+
+ void LoadDoubleConstant(XmmRegister dst, double value);
+
+ void DoubleNegate(XmmRegister d);
+ void FloatNegate(XmmRegister f);
+
+ void DoubleAbs(XmmRegister reg);
+
+ void LockCmpxchgl(const Address& address, Register reg) {
+ lock();
+ cmpxchgl(address, reg);
+ }
+
+ /*
+ * Misc. functionality
+ */
+ int PreferredLoopAlignment() { return 16; }
+ void Align(int alignment, int offset);
+ void Bind(Label* label);
+
+ int CodeSize() const { return buffer_.Size(); }
+
+ 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(byte* data, size_t length);
+
+ private:
+ AssemblerBuffer buffer_;
+
+ inline void EmitUint8(uint8_t value);
+ inline void EmitInt32(int32_t value);
+ inline void EmitRegisterOperand(int rm, int reg);
+ 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(int rm, Register reg, const Immediate& imm);
+ void EmitGenericShift(int rm, Register operand, Register shifter);
+
+ DISALLOW_COPY_AND_ASSIGN(Assembler);
+};
+
+
+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::EmitRegisterOperand(int rm, int reg) {
+ CHECK_GE(rm, 0);
+ CHECK_LT(rm, 8);
+ buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg);
+}
+
+
+inline void Assembler::EmitXmmRegisterOperand(int rm, XmmRegister reg) {
+ EmitRegisterOperand(rm, static_cast<Register>(reg));
+}
+
+
+inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
+ buffer_.EmitFixup(fixup);
+}
+
+
+inline void Assembler::EmitOperandSizeOverride() {
+ EmitUint8(0x66);
+}
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_ASSEMBLER_X86_H_