Add test, neg, and not instructions to x64 assembler
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 29 May 2009 08:56:31 +0000 (08:56 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 29 May 2009 08:56:31 +0000 (08:56 +0000)
Review URL: http://codereview.chromium.org/112066

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

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

index 94e3ec0..6d3ed15 100644 (file)
@@ -56,7 +56,7 @@ void Assembler::emitq(uint64_t x, RelocInfo::Mode rmode) {
 
 
 // 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.  REX.X is cleared.
 void Assembler::emit_rex_64(Register reg, Register rm_reg) {
   emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
 }
@@ -70,6 +70,39 @@ void Assembler::emit_rex_64(Register reg, 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.X is cleared.
+void Assembler::emit_rex_32(Register reg, Register rm_reg) {
+  emit(0x40 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
+}
+
+
+// The high bit of reg is used for REX.R, 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 cleared.
+void Assembler::emit_rex_32(Register reg, const Operand& op) {
+  emit(0x40 | (reg.code() & 0x8) >> 1 | op.rex_);
+}
+
+
+// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
+// REX.W and REX.X are cleared.  If no REX bits are set, no byte is emitted.
+void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) {
+  byte rex_bits = (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3;
+  if (rex_bits) emit(0x40 | rex_bits);
+}
+
+
+// The high bit of reg is used for REX.R, 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 cleared.  If no REX bits are set, nothing
+// is emitted.
+void Assembler::emit_optional_rex_32(Register reg, const Operand& op) {
+  byte rex_bits =  (reg.code() & 0x8) >> 1 | op.rex_;
+  if (rex_bits) emit(0x40 | rex_bits);
+}
+
+
 void Assembler::set_target_address_at(byte* location, byte* value) {
   UNIMPLEMENTED();
 }
index a8b1b8e..acea713 100644 (file)
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "macro-assembler.h"
+#include "serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -173,18 +174,6 @@ void Assembler::Align(int m) {
   }
 }
 
-void Assembler::RecordComment(char const* a) {
-  UNIMPLEMENTED();
-}
-
-void Assembler::RecordPosition(int a) {
-  UNIMPLEMENTED();
-}
-
-void Assembler::RecordStatementPosition(int a) {
-  UNIMPLEMENTED();
-}
-
 
 void Assembler::bind_to(Label* L, int pos) {
   ASSERT(!L->is_bound());  // Label may only be bound once.
@@ -319,11 +308,14 @@ void Assembler::immediate_arithmetic_op(byte subcode,
                                         Immediate src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   if (is_int8(src.value_)) {
     emit(0x83);
     emit(0xC0 | (subcode << 3) | (dst.code() & 0x7));
     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));
@@ -336,7 +328,7 @@ void Assembler::immediate_arithmetic_op(byte subcode,
                                         Immediate src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   if (is_int8(src.value_)) {
     emit(0x83);
     emit_operand(Register::toRegister(subcode), dst);
@@ -373,7 +365,7 @@ void Assembler::call(Label* L) {
 void Assembler::dec(Register dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rcx, dst);
+  emit_rex_64(dst);
   emit(0xFF);
   emit(0xC8 | (dst.code() & 0x7));
 }
@@ -382,9 +374,9 @@ void Assembler::dec(Register dst) {
 void Assembler::dec(const Operand& dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   emit(0xFF);
-  emit_operand(rcx, dst);
+  emit_operand(1, dst);
 }
 
 
@@ -398,7 +390,7 @@ void Assembler::hlt() {
 void Assembler::inc(Register dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   emit(0xFF);
   emit(0xC0 | (dst.code() & 0x7));
 }
@@ -407,9 +399,9 @@ void Assembler::inc(Register dst) {
 void Assembler::inc(const Operand& dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   emit(0xFF);
-  emit_operand(rax, dst);
+  emit_operand(0, dst);
 }
 
 
@@ -508,7 +500,7 @@ void Assembler::movq(Register dst, Register src) {
 void Assembler::movq(Register dst, Immediate value) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   emit(0xC7);
   emit(0xC0 | (dst.code() & 0x7));
   emit(value);  // Only 32-bit immediates are possible, not 8-bit immediates.
@@ -518,12 +510,30 @@ void Assembler::movq(Register dst, Immediate value) {
 void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);
+  emit_rex_64(dst);
   emit(0xB8 | (dst.code() & 0x7));
   emitq(value, rmode);
 }
 
 
+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));
+}
+
+
+void Assembler::neg(const Operand& dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_rex_64(dst);
+  emit(0xF7);
+  emit_operand(3, dst);
+}
+
+
 void Assembler::nop() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -531,11 +541,29 @@ void Assembler::nop() {
 }
 
 
+void Assembler::not_(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_rex_64(dst);
+  emit(0xF7);
+  emit(0xC0 | (0x2 << 3) | (dst.code() & 0x7));
+}
+
+
+void Assembler::not_(const Operand& dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_rex_64(dst);
+  emit(0xF7);
+  emit_operand(2, dst);
+}
+
+
 void Assembler::pop(Register dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   if (dst.code() & 0x8) {
-    emit_rex_64(rax, dst);
+    emit_rex_64(dst);
   }
   emit(0x58 | (dst.code() & 0x7));
 }
@@ -544,9 +572,9 @@ void Assembler::pop(Register dst) {
 void Assembler::pop(const Operand& dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rax, dst);  // Could be omitted in some cases.
+  emit_rex_64(dst);  // Could be omitted in some cases.
   emit(0x8F);
-  emit_operand(rax, dst);
+  emit_operand(0, dst);
 }
 
 
@@ -554,7 +582,7 @@ void Assembler::push(Register src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   if (src.code() & 0x8) {
-    emit_rex_64(rax, src);
+    emit_rex_64(src);
   }
   emit(0x50 | (src.code() & 0x7));
 }
@@ -563,9 +591,9 @@ void Assembler::push(Register src) {
 void Assembler::push(const Operand& src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_rex_64(rsi, src);  // Could be omitted in some cases.
+  emit_rex_64(src);  // Could be omitted in some cases.
   emit(0xFF);
-  emit_operand(rsi, src);
+  emit_operand(6, src);
 }
 
 
@@ -582,6 +610,127 @@ void Assembler::ret(int imm16) {
   }
 }
 
+
+void Assembler::testb(Register reg, Immediate mask) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (reg.is(rax)) {
+    emit(0xA8);
+    emit(mask);
+  } else {
+    if (reg.code() & 0x8) {
+      emit_rex_32(rax, reg);
+    }
+    emit(0xF6);
+    emit(0xC0 | (reg.code() & 0x3));
+    emit(mask.value_);  // Low byte emitted.
+  }
+}
+
+
+void Assembler::testb(const Operand& op, Immediate mask) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_optional_rex_32(rax, op);
+  emit(0xF6);
+  emit_operand(rax, op);  // Operation code 0
+  emit(mask.value_);  // Low byte emitted.
+}
+
+
+void Assembler::testl(Register reg, Immediate mask) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (reg.is(rax)) {
+    emit(0xA9);
+    emit(mask);
+  } else {
+    emit_optional_rex_32(rax, reg);
+    emit(0xF7);
+    emit(0xC0 | (reg.code() & 0x3));
+    emit(mask);
+  }
+}
+
+
+void Assembler::testl(const Operand& op, Immediate mask) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_optional_rex_32(rax, op);
+  emit(0xF7);
+  emit_operand(rax, op);  // Operation code 0
+  emit(mask);
+}
+
+
+// Relocation information implementations
+
+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
+  ASSERT(rmode != RelocInfo::NONE);
+  // Don't record external references unless the heap will be serialized.
+  if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
+      !Serializer::enabled() &&
+      !FLAG_debug_code) {
+    return;
+  }
+  RelocInfo rinfo(pc_, rmode, data);
+  reloc_info_writer.Write(&rinfo);
+}
+
+void Assembler::RecordJSReturn() {
+  WriteRecordedPositions();
+  EnsureSpace ensure_space(this);
+  RecordRelocInfo(RelocInfo::JS_RETURN);
+}
+
+
+void Assembler::RecordComment(const char* msg) {
+  if (FLAG_debug_code) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
+  }
+}
+
+
+void Assembler::RecordPosition(int pos) {
+  ASSERT(pos != RelocInfo::kNoPosition);
+  ASSERT(pos >= 0);
+  current_position_ = pos;
+}
+
+
+void Assembler::RecordStatementPosition(int pos) {
+  ASSERT(pos != RelocInfo::kNoPosition);
+  ASSERT(pos >= 0);
+  current_statement_position_ = pos;
+}
+
+
+void Assembler::WriteRecordedPositions() {
+  // Write the statement position if it is different from what was written last
+  // time.
+  if (current_statement_position_ != written_statement_position_) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
+    written_statement_position_ = current_statement_position_;
+  }
+
+  // Write the position if it is different from what was written last time and
+  // also different from the written statement position.
+  if (current_position_ != written_position_ &&
+      current_position_ != written_statement_position_) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::POSITION, current_position_);
+    written_position_ = current_position_;
+  }
+}
+
+
+const int RelocInfo::kApplyMask =
+  RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY |
+    1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE;
+
+
 } }  // namespace v8::internal
 
 
@@ -732,8 +881,6 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
   return NULL;
 }
 
-const int RelocInfo::kApplyMask = -1;
-
 StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) {
   UNIMPLEMENTED();
   return NONE;
index 2a205b7..06a7c40 100644 (file)
@@ -528,8 +528,10 @@ class Assembler : public Malloced {
   void mul(Register src);
 
   void neg(Register dst);
+  void neg(const Operand& dst);
 
   void not_(Register dst);
+  void not_(const Operand& dst);
 
   void or_(Register dst, Register src) {
     arithmetic_op(0x0B, dst, src);
@@ -590,10 +592,10 @@ class Assembler : public Malloced {
     immediate_arithmetic_op(0x5, dst, src);
   }
 
-
-  void test(Register reg, const Immediate& imm);
-  void test(Register reg, const Operand& op);
-  void test(const Operand& op, const Immediate& imm);
+  void testb(Register reg, Immediate mask);
+  void testb(const Operand& op, Immediate mask);
+  void testl(Register reg, Immediate mask);
+  void testl(const Operand& op, Immediate mask);
 
   void xor_(Register dst, Register src) {
     arithmetic_op(0x33, dst, src);
@@ -752,9 +754,13 @@ class Assembler : public Malloced {
   void RecordStatementPosition(int pos);
   void WriteRecordedPositions();
 
-  // Writes a single word of data in the code stream.
+  // Writes a doubleword of data in the code stream.
+  // Used for inline tables, e.g., jump-tables.
+  void dd(uint32_t data);
+
+  // Writes a quadword of data in the code stream.
   // Used for inline tables, e.g., jump-tables.
-  void dd(uint32_t data, RelocInfo::Mode reloc_info);
+  void dd(uint64_t data, RelocInfo::Mode reloc_info);
 
   // Writes the absolute address of a bound label at the given position in
   // the generated code. That positions should have the relocation mode
@@ -809,6 +815,7 @@ 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.
@@ -816,11 +823,35 @@ 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); }
+
+  // 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_32(Register reg, Register rm_reg);
+
+  // The high bit of reg is used for REX.R, 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 cleared.
+  inline void emit_rex_32(Register reg, 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.
+  inline void emit_optional_rex_32(Register reg, Register rm_reg);
+
+  // The high bit of reg is used for REX.R, 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 cleared.  If no REX bits are set, nothing
+  // is emitted.
+  inline void emit_optional_rex_32(Register reg, const Operand& op);
 
   // Emit the Mod/RM 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, into the Mod/RM byte.
+  // 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);
+  }
 
   // Emit the code-object-relative offset of the label's position
   inline void emit_code_relative_offset(Label* label);
@@ -842,9 +873,7 @@ class Assembler : public Malloced {
   void link_to(Label* L, Label* appendix);
 
   // record reloc info for current pc_
-  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0) {
-    UNIMPLEMENTED();
-  }
+  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
 
   friend class CodePatcher;
   friend class EnsureSpace;