Commit 734f1fd1 authored by lrn@chromium.org's avatar lrn@chromium.org

X64: Added jmp and call and nop(n) to X64 assembler.

Review URL: http://codereview.chromium.org/115920


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2085 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ce988f32
...@@ -437,6 +437,7 @@ static inline bool is_uintn(int x, int n) { ...@@ -437,6 +437,7 @@ static inline bool is_uintn(int x, int n) {
return (x & -(1 << n)) == 0; return (x & -(1 << n)) == 0;
} }
static inline bool is_uint2(int x) { return is_uintn(x, 2); }
static inline bool is_uint3(int x) { return is_uintn(x, 3); } static inline bool is_uint3(int x) { return is_uintn(x, 3); }
static inline bool is_uint4(int x) { return is_uintn(x, 4); } static inline bool is_uint4(int x) { return is_uintn(x, 4); }
static inline bool is_uint5(int x) { return is_uintn(x, 5); } static inline bool is_uint5(int x) { return is_uintn(x, 5); }
......
...@@ -70,8 +70,23 @@ void Assembler::emit_rex_64(Register reg, const Operand& op) { ...@@ -70,8 +70,23 @@ void Assembler::emit_rex_64(Register reg, const Operand& op) {
} }
// The high bit of the register is used for REX.B.
// REX.W is set and REX.R and REX.X are clear.
void Assembler::emit_rex_64(Register rm_reg) {
ASSERT_EQ(rm_reg.code() & 0x0f, rm_reg.code());
emit(0x48 | (rm_reg.code() >> 3));
}
// The high bit of op's base register is used for REX.B, and the high
// bit of op's index register is used for REX.X. REX.W is set and REX.R clear.
void Assembler::emit_rex_64(const Operand& op) {
emit(0x48 | op.rex_);
}
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B. // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
// REX.W is set. REX.X is cleared. // REX.W and REX.X are clear.
void Assembler::emit_rex_32(Register reg, Register rm_reg) { void Assembler::emit_rex_32(Register reg, Register rm_reg) {
emit(0x40 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3); emit(0x40 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
} }
...@@ -222,7 +237,7 @@ Operand::Operand(Register base, int32_t disp) { ...@@ -222,7 +237,7 @@ Operand::Operand(Register base, int32_t disp) {
len_ = 1; len_ = 1;
if (base.is(rsp) || base.is(r12)) { if (base.is(rsp) || base.is(r12)) {
// SIB byte is needed to encode (rsp + offset) or (r12 + offset). // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
set_sib(times_1, rsp, base); set_sib(kTimes1, rsp, base);
} }
if (disp == 0 && !base.is(rbp) && !base.is(r13)) { if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
...@@ -246,7 +261,7 @@ void Operand::set_modrm(int mod, Register rm) { ...@@ -246,7 +261,7 @@ void Operand::set_modrm(int mod, Register rm) {
void Operand::set_sib(ScaleFactor scale, Register index, Register base) { void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
ASSERT(len_ == 1); ASSERT(len_ == 1);
ASSERT((scale & -4) == 0); ASSERT(is_uint2(scale));
// Use SIB with no index register only for base rsp or r12. // Use SIB with no index register only for base rsp or r12.
ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12)); ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
buf_[1] = scale << 6 | (index.code() & 0x7) << 3 | (base.code() & 0x7); buf_[1] = scale << 6 | (index.code() & 0x7) << 3 | (base.code() & 0x7);
......
...@@ -271,12 +271,13 @@ void Assembler::GrowBuffer() { ...@@ -271,12 +271,13 @@ void Assembler::GrowBuffer() {
} }
void Assembler::emit_operand(Register reg, const Operand& adr) { void Assembler::emit_operand(int rm, const Operand& adr) {
ASSERT_EQ(rm & 0x07, rm);
const unsigned length = adr.len_; const unsigned length = adr.len_;
ASSERT(length > 0); ASSERT(length > 0);
// Emit updated ModRM byte containing the given register. // Emit updated ModRM byte containing the given register.
pc_[0] = (adr.buf_[0] & ~0x38) | ((reg.code() && 0x7) << 3); pc_[0] = (adr.buf_[0] & ~0x38) | (rm << 3);
// Emit the rest of the encoded operand. // Emit the rest of the encoded operand.
for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i]; for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
...@@ -362,6 +363,18 @@ void Assembler::call(Label* L) { ...@@ -362,6 +363,18 @@ void Assembler::call(Label* L) {
} }
void Assembler::call(Register adr) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// Opcode: FF /2 r64
if (!is_uint3(adr.code())) {
emit_rex_64(adr);
}
emit(0xFF);
emit(0xD0 | (adr.code() & 0x07));
}
void Assembler::dec(Register dst) { void Assembler::dec(Register dst) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -479,6 +492,18 @@ void Assembler::jmp(Label* L) { ...@@ -479,6 +492,18 @@ void Assembler::jmp(Label* L) {
} }
void Assembler::jmp(Register target) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// Opcode FF/4 r64
if (!is_uint3(target.code())) {
emit_rex_64(target);
}
emit(0xFF);
emit(0xE0 | target.code() & 0x07);
}
void Assembler::movq(Register dst, const Operand& src) { void Assembler::movq(Register dst, const Operand& src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -559,6 +584,93 @@ void Assembler::not_(const Operand& dst) { ...@@ -559,6 +584,93 @@ void Assembler::not_(const Operand& dst) {
} }
void Assembler::nop(int n) {
// The recommended muti-byte sequences of NOP instructions from the Intel 64
// and IA-32 Architectures Software Developer's Manual.
//
// Length Assembly Byte Sequence
// 2 bytes 66 NOP 66 90H
// 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
// 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
// 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
// 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
// 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
// 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
// 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 66 0F 1F 84 00 00 00 00
// 00000000H] 00H
ASSERT(1 <= n);
ASSERT(n <= 9);
EnsureSpace ensure_space(this);
last_pc_ = pc_;
switch (n) {
case 1:
emit(0x90);
return;
case 2:
emit(0x66);
emit(0x90);
return;
case 3:
emit(0x0f);
emit(0x1f);
emit(0x00);
return;
case 4:
emit(0x0f);
emit(0x1f);
emit(0x40);
emit(0x00);
return;
case 5:
emit(0x0f);
emit(0x1f);
emit(0x44);
emit(0x00);
emit(0x00);
return;
case 6:
emit(0x66);
emit(0x0f);
emit(0x1f);
emit(0x44);
emit(0x00);
emit(0x00);
return;
case 7:
emit(0x0f);
emit(0x1f);
emit(0x80);
emit(0x00);
emit(0x00);
emit(0x00);
emit(0x00);
return;
case 8:
emit(0x0f);
emit(0x1f);
emit(0x84);
emit(0x00);
emit(0x00);
emit(0x00);
emit(0x00);
emit(0x00);
return;
case 9:
emit(0x66);
emit(0x0f);
emit(0x1f);
emit(0x84);
emit(0x00);
emit(0x00);
emit(0x00);
emit(0x00);
emit(0x00);
return;
}
}
void Assembler::pop(Register dst) { void Assembler::pop(Register dst) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
......
...@@ -225,10 +225,12 @@ class Immediate BASE_EMBEDDED { ...@@ -225,10 +225,12 @@ class Immediate BASE_EMBEDDED {
// Machine instruction Operands // Machine instruction Operands
enum ScaleFactor { enum ScaleFactor {
times_1 = 0, kTimes1 = 0,
times_2 = 1, kTimes2 = 1,
times_4 = 2, kTimes4 = 2,
times_8 = 3 kTimes8 = 3,
kTimesIntSize = kTimes4,
kTimesPointerSize = kTimes8
}; };
...@@ -626,6 +628,7 @@ class Assembler : public Malloced { ...@@ -626,6 +628,7 @@ class Assembler : public Malloced {
void hlt(); void hlt();
void int3(); void int3();
void nop(); void nop();
void nop(int n);
void rdtsc(); void rdtsc();
void ret(int imm16); void ret(int imm16);
...@@ -647,16 +650,18 @@ class Assembler : public Malloced { ...@@ -647,16 +650,18 @@ class Assembler : public Malloced {
void bind(Label* L); // binds an unbound label L to the current code position void bind(Label* L); // binds an unbound label L to the current code position
// Calls // Calls
// Call near relative 32-bit displacement, relative to next instruction.
void call(Label* L); void call(Label* L);
void call(byte* entry, RelocInfo::Mode rmode);
void call(const Operand& adr); // Call near absolute indirect, address in register
void call(Handle<Code> code, RelocInfo::Mode rmode); void call(Register adr);
// Jumps // Jumps
// Jump short or near relative.
void jmp(Label* L); // unconditional jump to L void jmp(Label* L); // unconditional jump to L
void jmp(byte* entry, RelocInfo::Mode rmode);
void jmp(const Operand& adr); // Jump near absolute indirect (r64)
void jmp(Handle<Code> code, RelocInfo::Mode rmode); void jmp(Register adr);
// Conditional jumps // Conditional jumps
void j(Condition cc, Label* L); void j(Condition cc, Label* L);
...@@ -815,7 +820,6 @@ class Assembler : public Malloced { ...@@ -815,7 +820,6 @@ class Assembler : public Malloced {
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B. // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
// REX.W is set. // REX.W is set.
inline void emit_rex_64(Register reg, Register rm_reg); inline void emit_rex_64(Register reg, Register rm_reg);
void emit_rex_64(Register rm_reg) { emit_rex_64(rax, rm_reg); }
// Emits a REX prefix that encodes a 64-bit operand size and // Emits a REX prefix that encodes a 64-bit operand size and
// the top bit of the destination, index, and base register codes. // the top bit of the destination, index, and base register codes.
...@@ -823,10 +827,22 @@ class Assembler : public Malloced { ...@@ -823,10 +827,22 @@ class Assembler : public Malloced {
// register is used for REX.B, and the high bit of op's index register // register is used for REX.B, and the high bit of op's index register
// is used for REX.X. REX.W is set. // is used for REX.X. REX.W is set.
inline void emit_rex_64(Register reg, const Operand& op); inline void emit_rex_64(Register reg, const Operand& op);
void emit_rex_64(const Operand& op) { emit_rex_64(rax, op); }
// Emits a REX prefix that encodes a 64-bit operand size and
// the top bit of the register code.
// The high bit of register is used for REX.B.
// REX.W is set and REX.R and REX.X are clear.
inline void emit_rex_64(Register rm_reg);
// Emits a REX prefix that encodes a 64-bit operand size and
// the top bit of the index and base register codes.
// The high bit of op's base register is used for REX.B, and the high
// bit of op's index register is used for REX.X.
// REX.W is set and REX.R clear.
inline void emit_rex_64(const Operand& op);
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B. // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
// REX.W is set. // REX.W is clear.
inline void emit_rex_32(Register reg, Register rm_reg); inline void emit_rex_32(Register reg, Register rm_reg);
// The high bit of reg is used for REX.R, the high bit of op's base // The high bit of reg is used for REX.R, the high bit of op's base
...@@ -848,11 +864,15 @@ class Assembler : public Malloced { ...@@ -848,11 +864,15 @@ class Assembler : public Malloced {
// 1- or 4-byte offset for a memory operand. Also encodes // 1- or 4-byte offset for a memory operand. Also encodes
// the second operand of the operation, a register or operation // the second operand of the operation, a register or operation
// subcode, into the Mod/RM byte. // subcode, into the Mod/RM byte.
void emit_operand(Register reg, const Operand& adr); void emit_operand(Register reg, const Operand& adr) {
void emit_operand(int op_subcode, const Operand& adr) { emit_operand(reg.code() & 0x07, adr);
emit_operand(Register::toRegister(op_subcode), adr);
} }
// Emit the Mod/RM 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.
void emit_operand(int rm, const Operand& adr);
// Emit the code-object-relative offset of the label's position // Emit the code-object-relative offset of the label's position
inline void emit_code_relative_offset(Label* label); inline void emit_code_relative_offset(Label* label);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment