X64: Added jmp and call and nop(n) to X64 assembler.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Jun 2009 07:21:05 +0000 (07:21 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Jun 2009 07:21:05 +0000 (07:21 +0000)
Review URL: http://codereview.chromium.org/115920

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2085 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/assembler.h
src/x64/assembler-x64-inl.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h

index 16e81477a9fa5e6428be8a90bc08caf65b2219c0..570524e06dc4f923c32c62fdb49d863c6d4cf960 100644 (file)
@@ -437,6 +437,7 @@ static inline bool is_uintn(int x, int n) {
   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); }
index 6d3ed1544219e155575dfec96573edc9e6a4dcc9..ad349345a413d2dfd3a14a886b7bcc2645f2eaf8 100644 (file)
@@ -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.
-// 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);
 }
@@ -222,7 +237,7 @@ Operand::Operand(Register base, int32_t disp) {
   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)) {
@@ -246,7 +261,7 @@ void Operand::set_modrm(int mod, Register rm) {
 
 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);
index acea713198a17f41d959484b2c992097b2dab05d..86e11653383ca2266c5a2dfaf3f95ea71ebed995 100644 (file)
@@ -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_;
   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];
@@ -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) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -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) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -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) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
index 06a7c4070c2ece5254f40754e30baa1d301d3b12..170e6d67572471ddb7e198e1be1ad0420b2b21f3 100644 (file)
@@ -225,10 +225,12 @@ class Immediate BASE_EMBEDDED {
 // 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
 };
 
 
@@ -626,6 +628,7 @@ class Assembler : public Malloced {
   void hlt();
   void int3();
   void nop();
+  void nop(int n);
   void rdtsc();
   void ret(int imm16);
 
@@ -647,16 +650,18 @@ class Assembler : public Malloced {
   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);
@@ -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.
   // 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.
@@ -823,10 +827,22 @@ class Assembler : public Malloced {
   // 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
@@ -848,11 +864,15 @@ class Assembler : public Malloced {
   // 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);