Add multiplication and division to x64 assembler. Add emit_modrm() function.
Review URL: http://codereview.chromium.org/119078 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2098 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
92c17c34de
commit
34de62698c
@ -342,7 +342,7 @@ void Assembler::emit_operand(int rm, const Operand& adr) {
|
||||
const unsigned length = adr.len_;
|
||||
ASSERT(length > 0);
|
||||
|
||||
// Emit updated ModRM byte containing the given register.
|
||||
// Emit updated ModR/M byte containing the given register.
|
||||
pc_[0] = (adr.buf_[0] & ~0x38) | (rm << 3);
|
||||
|
||||
// Emit the rest of the encoded operand.
|
||||
@ -367,7 +367,7 @@ void Assembler::arithmetic_op(byte opcode, Register dst, Register src) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
emit(opcode);
|
||||
emit(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
|
||||
emit_modrm(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::immediate_arithmetic_op(byte subcode,
|
||||
@ -378,14 +378,14 @@ void Assembler::immediate_arithmetic_op(byte subcode,
|
||||
emit_rex_64(dst);
|
||||
if (is_int8(src.value_)) {
|
||||
emit(0x83);
|
||||
emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(subcode, dst);
|
||||
emit(src.value_);
|
||||
} else if (dst.is(rax)) {
|
||||
emit(0x05 | (subcode << 3));
|
||||
emitl(src.value_);
|
||||
} else {
|
||||
emit(0x81);
|
||||
emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(subcode, dst);
|
||||
emitl(src.value_);
|
||||
}
|
||||
}
|
||||
@ -415,11 +415,11 @@ void Assembler::shift(Register dst, Immediate shift_amount, int subcode) {
|
||||
if (shift_amount.value_ == 1) {
|
||||
emit_rex_64(dst);
|
||||
emit(0xD1);
|
||||
emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(subcode, dst);
|
||||
} else {
|
||||
emit_rex_64(dst);
|
||||
emit(0xC1);
|
||||
emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(subcode, dst);
|
||||
emit(shift_amount.value_);
|
||||
}
|
||||
}
|
||||
@ -430,7 +430,7 @@ void Assembler::shift(Register dst, int subcode) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xD3);
|
||||
emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(subcode, dst);
|
||||
}
|
||||
|
||||
|
||||
@ -479,11 +479,11 @@ void Assembler::call(Register adr) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
// Opcode: FF /2 r64
|
||||
if (!is_uint3(adr.code())) {
|
||||
if (adr.code() > 7) {
|
||||
emit_rex_64(adr);
|
||||
}
|
||||
emit(0xFF);
|
||||
emit(0xD0 | (adr.code() & 0x07));
|
||||
emit_modrm(0x2, adr);
|
||||
}
|
||||
|
||||
|
||||
@ -509,7 +509,7 @@ void Assembler::dec(Register dst) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xFF);
|
||||
emit(0xC8 | (dst.code() & 0x7));
|
||||
emit_modrm(0x1, dst);
|
||||
}
|
||||
|
||||
|
||||
@ -538,12 +538,47 @@ void Assembler::hlt() {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::idiv(Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src);
|
||||
emit(0xF7);
|
||||
emit_modrm(0x7, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::imul(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
emit(0x0F);
|
||||
emit(0xAF);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::imul(Register dst, Register src, Immediate imm) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
if (is_int8(imm.value_)) {
|
||||
emit(0x6B);
|
||||
emit_modrm(dst, src);
|
||||
emit(imm.value_);
|
||||
} else {
|
||||
emit(0x69);
|
||||
emit_modrm(dst, src);
|
||||
emitl(imm.value_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::inc(Register dst) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xFF);
|
||||
emit(0xC0 | (dst.code() & 0x7));
|
||||
emit_modrm(0x0, dst);
|
||||
}
|
||||
|
||||
|
||||
@ -634,11 +669,11 @@ void Assembler::jmp(Register target) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
// Opcode FF/4 r64
|
||||
if (!is_uint3(target.code())) {
|
||||
if (target.code() > 7) {
|
||||
emit_rex_64(target);
|
||||
}
|
||||
emit(0xFF);
|
||||
emit(0xE0 | target.code() & 0x07);
|
||||
emit_modrm(0x4, target);
|
||||
}
|
||||
|
||||
|
||||
@ -658,6 +693,31 @@ void Assembler::leave() {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movb(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_32(dst, src);
|
||||
emit(0x8A);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::movb(Register dst, Immediate imm) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_32(dst);
|
||||
emit(0xC6);
|
||||
emit_modrm(0x0, dst);
|
||||
emit(imm.value_);
|
||||
}
|
||||
|
||||
void Assembler::movb(const Operand& dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_32(src, dst);
|
||||
emit(0x88);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
void Assembler::movl(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -672,7 +732,7 @@ void Assembler::movl(Register dst, Register src) {
|
||||
last_pc_ = pc_;
|
||||
emit_optional_rex_32(dst, src);
|
||||
emit(0x8B);
|
||||
emit(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
|
||||
emit_modrm(dst, src);
|
||||
}
|
||||
|
||||
|
||||
@ -690,7 +750,7 @@ void Assembler::movl(Register dst, Immediate value) {
|
||||
last_pc_ = pc_;
|
||||
emit_optional_rex_32(dst);
|
||||
emit(0xC7);
|
||||
emit(0xC0 | (dst.code() & 0x7));
|
||||
emit_modrm(0x0, dst);
|
||||
emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
|
||||
}
|
||||
|
||||
@ -709,7 +769,7 @@ void Assembler::movq(Register dst, Register src) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
emit(0x8B);
|
||||
emit(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
|
||||
emit_modrm(dst, src);
|
||||
}
|
||||
|
||||
|
||||
@ -718,7 +778,7 @@ void Assembler::movq(Register dst, Immediate value) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xC7);
|
||||
emit(0xC0 | (dst.code() & 0x7));
|
||||
emit_modrm(0x0, dst);
|
||||
emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
|
||||
}
|
||||
|
||||
@ -727,7 +787,7 @@ void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xB8 | (dst.code() & 0x7));
|
||||
emit(0xB8 | (dst.code() & 0x7)); // Not a ModR/M byte.
|
||||
emitq(value, rmode);
|
||||
}
|
||||
|
||||
@ -741,12 +801,21 @@ void Assembler::movq(const Operand& dst, Register src) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::mul(Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src);
|
||||
emit(0xF7);
|
||||
emit_modrm(0x4, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::neg(Register dst) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xF7);
|
||||
emit(0xC0 | (0x3 << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(0x3, dst);
|
||||
}
|
||||
|
||||
|
||||
@ -771,7 +840,7 @@ void Assembler::not_(Register dst) {
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst);
|
||||
emit(0xF7);
|
||||
emit(0xC0 | (0x2 << 3) | (dst.code() & 0x7));
|
||||
emit_modrm(0x2, dst);
|
||||
}
|
||||
|
||||
|
||||
@ -874,7 +943,7 @@ void Assembler::nop(int n) {
|
||||
void Assembler::pop(Register dst) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
if (dst.code() & 0x8) {
|
||||
if (dst.code() > 7) {
|
||||
emit_rex_64(dst);
|
||||
}
|
||||
emit(0x58 | (dst.code() & 0x7));
|
||||
@ -900,7 +969,7 @@ void Assembler::popfq() {
|
||||
void Assembler::push(Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
if (src.code() & 0x8) {
|
||||
if (src.code() > 7) {
|
||||
emit_rex_64(src);
|
||||
}
|
||||
emit(0x50 | (src.code() & 0x7));
|
||||
@ -943,11 +1012,11 @@ void Assembler::rcl(Register dst, uint8_t imm8) {
|
||||
if (imm8 == 1) {
|
||||
emit_rex_64(dst);
|
||||
emit(0xD1);
|
||||
emit(0xD0 | (dst.code() & 0x7));
|
||||
emit_modrm(0x2, dst);
|
||||
} else {
|
||||
emit_rex_64(dst);
|
||||
emit(0xC1);
|
||||
emit(0xD0 | (dst.code() & 0x7));
|
||||
emit_modrm(0x2, dst);
|
||||
emit(imm8);
|
||||
}
|
||||
}
|
||||
@ -967,6 +1036,26 @@ void Assembler::ret(int imm16) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::shld(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x0F);
|
||||
emit(0xA5);
|
||||
emit_modrm(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::shrd(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x0F);
|
||||
emit(0xAD);
|
||||
emit_modrm(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::xchg(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -977,7 +1066,7 @@ void Assembler::xchg(Register dst, Register src) {
|
||||
} else {
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x87);
|
||||
emit(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
|
||||
emit_modrm(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -989,11 +1078,12 @@ void Assembler::testb(Register reg, Immediate mask) {
|
||||
emit(0xA8);
|
||||
emit(mask);
|
||||
} else {
|
||||
if (reg.code() & 0x8) {
|
||||
emit_rex_32(rax, reg);
|
||||
if (reg.code() > 3) {
|
||||
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
|
||||
emit_rex_32(reg);
|
||||
}
|
||||
emit(0xF6);
|
||||
emit(0xC0 | (reg.code() & 0x3));
|
||||
emit_modrm(0x0, reg);
|
||||
emit(mask.value_); // Low byte emitted.
|
||||
}
|
||||
}
|
||||
@ -1018,7 +1108,7 @@ void Assembler::testl(Register reg, Immediate mask) {
|
||||
} else {
|
||||
emit_optional_rex_32(rax, reg);
|
||||
emit(0xF7);
|
||||
emit(0xC0 | (reg.code() & 0x3));
|
||||
emit_modrm(0x0, reg);
|
||||
emit(mask);
|
||||
}
|
||||
}
|
||||
@ -1034,6 +1124,24 @@ void Assembler::testl(const Operand& op, Immediate mask) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::testq(const Operand& op, Register reg) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(reg, op);
|
||||
emit(0x85);
|
||||
emit_operand(reg, op);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::testq(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
emit(0x85);
|
||||
emit_modrm(dst, src);
|
||||
}
|
||||
|
||||
|
||||
// Relocation information implementations
|
||||
|
||||
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
|
||||
|
@ -270,7 +270,7 @@ class Operand BASE_EMBEDDED {
|
||||
unsigned int len_;
|
||||
RelocInfo::Mode rmode_;
|
||||
|
||||
// Set the ModRM byte without an encoded 'reg' register. The
|
||||
// Set the ModR/M byte without an encoded 'reg' register. The
|
||||
// register is encoded later as part of the emit_operand operation.
|
||||
// set_modrm can be called before or after set_sib and set_disp*.
|
||||
inline void set_modrm(int mod, Register rm);
|
||||
@ -417,7 +417,7 @@ class Assembler : public Malloced {
|
||||
|
||||
// Moves
|
||||
void movb(Register dst, const Operand& src);
|
||||
void movb(const Operand& dst, int8_t imm8);
|
||||
void movb(Register dst, Immediate imm);
|
||||
void movb(const Operand& dst, Register src);
|
||||
|
||||
void movl(Register dst, Register src);
|
||||
@ -538,16 +538,20 @@ class Assembler : public Malloced {
|
||||
// Sign-extends rax into rdx:rax.
|
||||
void cqo();
|
||||
|
||||
// Divide rdx:rax by src. Quotient in rax, remainder in rdx.
|
||||
void idiv(Register src);
|
||||
|
||||
void imul(Register dst, Register src);
|
||||
void imul(Register dst, const Operand& src);
|
||||
void imul(Register dst, Register src, int32_t imm32);
|
||||
// Performs the operation dst = src * imm.
|
||||
void imul(Register dst, Register src, Immediate imm);
|
||||
|
||||
void inc(Register dst);
|
||||
void inc(const Operand& dst);
|
||||
|
||||
void lea(Register dst, const Operand& src);
|
||||
|
||||
// Multiply rax by src, put the result in rdx:rax.
|
||||
void mul(Register src);
|
||||
|
||||
void neg(Register dst);
|
||||
@ -579,11 +583,11 @@ class Assembler : public Malloced {
|
||||
|
||||
void rcl(Register dst, uint8_t imm8);
|
||||
|
||||
void sbb(Register dst, const Operand& src);
|
||||
// Shifts dst:src left by cl bits, affecting only dst.
|
||||
void shld(Register dst, Register src);
|
||||
|
||||
void shld(Register dst, const Operand& src);
|
||||
|
||||
void shrd(Register dst, const Operand& src);
|
||||
// Shifts src:dst right by cl bits, affecting only dst.
|
||||
void shrd(Register dst, Register src);
|
||||
|
||||
// Shifts dst right, duplicating sign bit, by shift_amount bits.
|
||||
// Shifting by 1 is handled efficiently.
|
||||
@ -636,6 +640,8 @@ class Assembler : public Malloced {
|
||||
void testb(const Operand& op, Immediate mask);
|
||||
void testl(Register reg, Immediate mask);
|
||||
void testl(const Operand& op, Immediate mask);
|
||||
void testq(const Operand& op, Register reg);
|
||||
void testq(Register dst, Register src);
|
||||
|
||||
void xor_(Register dst, Register src) {
|
||||
arithmetic_op(0x33, dst, src);
|
||||
@ -898,7 +904,7 @@ class Assembler : public Malloced {
|
||||
|
||||
// High bit of base goes to REX.B and high bit of index to REX.X.
|
||||
// REX.W and REX.R are clear.
|
||||
inline void emit_rex_32(const Operand &);
|
||||
inline void emit_rex_32(const Operand& op);
|
||||
|
||||
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
|
||||
// REX.W is cleared. If no REX bits are set, no byte is emitted.
|
||||
@ -919,26 +925,38 @@ class Assembler : public Malloced {
|
||||
inline void emit_optional_rex_32(const Operand& op);
|
||||
|
||||
|
||||
// Emit the Mod/RM byte, and optionally the SIB byte and
|
||||
// Emit the ModR/M byte, and optionally the SIB byte and
|
||||
// 1- or 4-byte offset for a memory operand. Also encodes
|
||||
// the second operand of the operation, a register or operation
|
||||
// subcode, into the Mod/RM byte.
|
||||
// subcode, into the reg field of the ModR/M byte.
|
||||
void emit_operand(Register reg, const Operand& adr) {
|
||||
emit_operand(reg.code() & 0x07, adr);
|
||||
}
|
||||
|
||||
// Emit the Mod/RM byte, and optionally the SIB byte and
|
||||
// Emit the ModR/M byte, and optionally the SIB byte and
|
||||
// 1- or 4-byte offset for a memory operand. Also used to encode
|
||||
// a three-byte opcode extension into the Mod/RM byte.
|
||||
// a three-bit opcode extension into the ModR/M byte.
|
||||
void emit_operand(int rm, const Operand& adr);
|
||||
|
||||
// Emit a ModR/M byte with registers coded in the reg and rm_reg fields.
|
||||
void emit_modrm(Register reg, Register rm_reg) {
|
||||
emit(0xC0 | (reg.code() & 0x7) << 3 | (rm_reg.code() & 0x7));
|
||||
}
|
||||
|
||||
// Emit a ModR/M byte with an operation subcode in the reg field and
|
||||
// a register in the rm_reg field.
|
||||
void emit_modrm(int code, Register rm_reg) {
|
||||
ASSERT((code & ~0x7) == 0);
|
||||
emit(0xC0 | (code & 0x7) << 3 | (rm_reg.code() & 0x7));
|
||||
}
|
||||
|
||||
// Emit the code-object-relative offset of the label's position
|
||||
inline void emit_code_relative_offset(Label* label);
|
||||
|
||||
// Emit machine code for one of the operations ADD, ADC, SUB, SBC,
|
||||
// AND, OR, XOR, or CMP. The encodings of these operations are all
|
||||
// similar, differing just in the opcode or in the reg field of the
|
||||
// Mod/RM byte.
|
||||
// ModR/M byte.
|
||||
void arithmetic_op(byte opcode, Register dst, Register src);
|
||||
void arithmetic_op(byte opcode, Register reg, const Operand& op);
|
||||
void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
|
||||
|
Loading…
Reference in New Issue
Block a user