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_uint4(int x) { return is_uintn(x, 4); }
static inline bool is_uint5(int x) { return is_uintn(x, 5); }
}
+// 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.
-// 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) {
emit(0x40 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
}
len_ = 1;
if (base.is(rsp) || base.is(r12)) {
// 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)) {
void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
ASSERT(len_ == 1);
- ASSERT((scale & -4) == 0);
+ ASSERT(is_uint2(scale));
// Use SIB with no index register only for base rsp or r12.
ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
buf_[1] = scale << 6 | (index.code() & 0x7) << 3 | (base.code() & 0x7);
}
-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_;
ASSERT(length > 0);
// 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.
for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
}
+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) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+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) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+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) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// Machine instruction Operands
enum ScaleFactor {
- times_1 = 0,
- times_2 = 1,
- times_4 = 2,
- times_8 = 3
+ kTimes1 = 0,
+ kTimes2 = 1,
+ kTimes4 = 2,
+ kTimes8 = 3,
+ kTimesIntSize = kTimes4,
+ kTimesPointerSize = kTimes8
};
void hlt();
void int3();
void nop();
+ void nop(int n);
void rdtsc();
void ret(int imm16);
void bind(Label* L); // binds an unbound label L to the current code position
// Calls
+ // Call near relative 32-bit displacement, relative to next instruction.
void call(Label* L);
- void call(byte* entry, RelocInfo::Mode rmode);
- void call(const Operand& adr);
- void call(Handle<Code> code, RelocInfo::Mode rmode);
+
+ // Call near absolute indirect, address in register
+ void call(Register adr);
// Jumps
+ // Jump short or near relative.
void jmp(Label* L); // unconditional jump to L
- void jmp(byte* entry, RelocInfo::Mode rmode);
- void jmp(const Operand& adr);
- void jmp(Handle<Code> code, RelocInfo::Mode rmode);
+
+ // Jump near absolute indirect (r64)
+ void jmp(Register adr);
// Conditional jumps
void j(Condition cc, Label* L);
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
// REX.W is set.
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
// the top bit of the destination, index, and base register codes.
// register is used for REX.B, and the high bit of op's index register
// is used for REX.X. REX.W is set.
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.
- // REX.W is set.
+ // REX.W is clear.
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
// 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.
- void emit_operand(Register reg, const Operand& adr);
- void emit_operand(int op_subcode, const Operand& adr) {
- emit_operand(Register::toRegister(op_subcode), adr);
+ 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
+ // 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
inline void emit_code_relative_offset(Label* label);