X64 implementation: Add high_bit() and low_bits() to register methods.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Jun 2009 08:17:44 +0000 (08:17 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Jun 2009 08:17:44 +0000 (08:17 +0000)
Review URL: http://codereview.chromium.org/141032

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

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

index 60c66e69132033bd0ddf53942f2c6fbcbcc48a41..934e3c299437a4c1e90f25da1acc5fb3f56abe64 100644 (file)
@@ -70,18 +70,18 @@ void Assembler::emitw(uint16_t x) {
 
 
 void Assembler::emit_rex_64(Register reg, Register rm_reg) {
-  emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
+  emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
 }
 
 
 void Assembler::emit_rex_64(Register reg, const Operand& op) {
-  emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_);
+  emit(0x48 | reg.high_bit() << 2 | op.rex_);
 }
 
 
 void Assembler::emit_rex_64(Register rm_reg) {
   ASSERT_EQ(rm_reg.code() & 0xf, rm_reg.code());
-  emit(0x48 | (rm_reg.code() >> 3));
+  emit(0x48 | rm_reg.high_bit());
 }
 
 
@@ -91,17 +91,17 @@ void Assembler::emit_rex_64(const Operand& op) {
 
 
 void Assembler::emit_rex_32(Register reg, Register rm_reg) {
-  emit(0x40 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
+  emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit());
 }
 
 
 void Assembler::emit_rex_32(Register reg, const Operand& op) {
-  emit(0x40 | (reg.code() & 0x8) >> 1 | op.rex_);
+  emit(0x40 | reg.high_bit() << 2  | op.rex_);
 }
 
 
 void Assembler::emit_rex_32(Register rm_reg) {
-  emit(0x40 | (rm_reg.code() & 0x8) >> 3);
+  emit(0x40 | rm_reg.high_bit());
 }
 
 
@@ -111,19 +111,19 @@ void Assembler::emit_rex_32(const Operand& op) {
 
 
 void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) {
-  byte rex_bits = (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3;
+  byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit();
   if (rex_bits != 0) emit(0x40 | rex_bits);
 }
 
 
 void Assembler::emit_optional_rex_32(Register reg, const Operand& op) {
-  byte rex_bits =  (reg.code() & 0x8) >> 1 | op.rex_;
+  byte rex_bits =  reg.high_bit() << 2 | op.rex_;
   if (rex_bits != 0) emit(0x40 | rex_bits);
 }
 
 
 void Assembler::emit_optional_rex_32(Register rm_reg) {
-  if (rm_reg.code() > 0x7) emit(0x41);
+  if (rm_reg.high_bit()) emit(0x41);
 }
 
 
@@ -244,11 +244,11 @@ Object** RelocInfo::call_object_address() {
 // -----------------------------------------------------------------------------
 // Implementation of Operand
 
-void Operand::set_modrm(int mod, Register rm) {
-  ASSERT((mod & -4) == 0);
-  buf_[0] = (mod << 6) | (rm.code() & 0x7);
+void Operand::set_modrm(int mod, Register rm_reg) {
+  ASSERT(is_uint2(mod));
+  buf_[0] = mod << 6 | rm_reg.low_bits();
   // Set REX.B to the high bit of rm.code().
-  rex_ |= (rm.code() >> 3);
+  rex_ |= rm_reg.high_bit();
 }
 
 
@@ -258,8 +258,8 @@ void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
   // Use SIB with no index register only for base rsp or r12. Otherwise we
   // would skip the SIB byte entirely.
   ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
-  buf_[1] = scale << 6 | (index.code() & 0x7) << 3 | (base.code() & 0x7);
-  rex_ |= (index.code() >> 3) << 1 | base.code() >> 3;
+  buf_[1] = scale << 6 | index.low_bits() << 3 | base.low_bits();
+  rex_ |= index.high_bit() << 1 | base.high_bit();
   len_ = 2;
 }
 
index d4ffb20b123961e5cc6ed6063d5e5a832bfb9d6f..fffbd81b28dba5cc1de91f2fb456b78a87f69b2d 100644 (file)
@@ -380,13 +380,14 @@ void Assembler::GrowBuffer() {
 }
 
 
-void Assembler::emit_operand(int rm, const Operand& adr) {
-  ASSERT_EQ(rm & 0x07, rm);
+void Assembler::emit_operand(int code, const Operand& adr) {
+  ASSERT(is_uint3(code));
   const unsigned length = adr.len_;
   ASSERT(length > 0);
 
   // Emit updated ModR/M byte containing the given register.
-  pc_[0] = (adr.buf_[0] & ~0x38) | (rm << 3);
+  ASSERT((adr.buf_[0] & 0x38) == 0);
+  pc_[0] = adr.buf_[0] | code << 3;
 
   // Emit the rest of the encoded operand.
   for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
@@ -593,7 +594,7 @@ void Assembler::call(Register adr) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   // Opcode: FF /2 r64
-  if (adr.code() > 7) {
+  if (adr.high_bit()) {
     emit_rex_64(adr);
   }
   emit(0xFF);
@@ -763,7 +764,7 @@ void Assembler::int3() {
 void Assembler::j(Condition cc, Label* L) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  ASSERT(0 <= cc && cc < 16);
+  ASSERT(is_uint4(cc));
   if (L->is_bound()) {
     const int short_size = 2;
     const int long_size  = 6;
@@ -831,7 +832,7 @@ void Assembler::jmp(Register target) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   // Opcode FF/4 r64
-  if (target.code() > 7) {
+  if (target.high_bit()) {
     emit_rex_64(target);
   }
   emit(0xFF);
@@ -982,7 +983,7 @@ void Assembler::movq(Register dst, void* value, RelocInfo::Mode rmode) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   emit_rex_64(dst);
-  emit(0xB8 | (dst.code() & 0x7));
+  emit(0xB8 | dst.low_bits());
   emitq(reinterpret_cast<uintptr_t>(value), rmode);
 }
 
@@ -991,7 +992,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));  // Not a ModR/M byte.
+  emit(0xB8 | dst.low_bits());
   emitq(value, rmode);
 }
 
@@ -1000,7 +1001,7 @@ void Assembler::movq(Register dst, ExternalReference ref) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   emit_rex_64(dst);
-  emit(0xB8 | (dst.code() & 0x7));
+  emit(0xB8 | dst.low_bits());
   emitq(reinterpret_cast<uintptr_t>(ref.address()),
         RelocInfo::EXTERNAL_REFERENCE);
 }
@@ -1021,7 +1022,7 @@ void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
   last_pc_ = pc_;
   ASSERT(!Heap::InNewSpace(*value));
   emit_rex_64(dst);
-  emit(0xB8 | (dst.code() & 0x7));
+  emit(0xB8 | dst.low_bits());
   if (value->IsHeapObject()) {
     emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
   } else {
@@ -1192,10 +1193,10 @@ void Assembler::nop(int n) {
 void Assembler::pop(Register dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  if (dst.code() > 7) {
+  if (dst.high_bit()) {
     emit_rex_64(dst);
   }
-  emit(0x58 | (dst.code() & 0x7));
+  emit(0x58 | dst.low_bits());
 }
 
 
@@ -1218,10 +1219,10 @@ void Assembler::popfq() {
 void Assembler::push(Register src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  if (src.code() > 7) {
+  if (src.high_bit()) {
     emit_rex_64(src);
   }
-  emit(0x50 | (src.code() & 0x7));
+  emit(0x50 | src.low_bits());
 }
 
 
@@ -1295,7 +1296,7 @@ void Assembler::ret(int imm16) {
 void Assembler::setcc(Condition cc, Register reg) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  ASSERT(0 <= cc && cc < 16);
+  ASSERT(is_uint4(cc));
   if (reg.code() > 3) {  // Use x64 byte registers, where different.
     emit_rex_32(reg);
   }
@@ -1331,7 +1332,7 @@ void Assembler::xchg(Register dst, Register src) {
   if (src.is(rax) || dst.is(rax)) {  // Single-byte encoding
     Register other = src.is(rax) ? dst : src;
     emit_rex_64(other);
-    emit(0x90 | (other.code() & 0x7));
+    emit(0x90 | other.low_bits());
   } else {
     emit_rex_64(src, dst);
     emit(0x87);
@@ -1755,7 +1756,7 @@ void Assembler::fnclex() {
 
 void Assembler::emit_farith(int b1, int b2, int i) {
   ASSERT(is_uint8(b1) && is_uint8(b2));  // wrong opcode
-  ASSERT(0 <= i &&  i < 8);  // illegal stack offset
+  ASSERT(is_uint3(i));  // illegal stack offset
   emit(b1);
   emit(b2 + i);
 }
index 44a03ad0b0c5c9bf73ca5db3a8f41fa4848c553e..2399491b768497df4170df203e3b33a62418af59 100644 (file)
@@ -92,6 +92,17 @@ struct Register {
     return 1 << code_;
   }
 
+  // Return the high bit of the register code as a 0 or 1.  Used often
+  // when constructing the REX prefix byte.
+  int high_bit() const {
+    return code_ >> 3;
+  }
+  // Return the 3 low bits of the register code.  Used when encoding registers
+  // in modR/M, SIB, and opcode bytes.
+  int low_bits() const {
+    return code_ & 0x7;
+  }
+
   // (unfortunately we can't make this private in a struct when initializing
   // by assignment.)
   int code_;
@@ -983,7 +994,7 @@ class Assembler : public Malloced {
   // the second operand of the operation, a register or operation
   // 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_operand(reg.low_bits(), adr);
   }
 
   // Emit the ModR/M byte, and optionally the SIB byte and
@@ -993,14 +1004,14 @@ class Assembler : public Malloced {
 
   // 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(0xC0 | reg.low_bits() << 3 | rm_reg.low_bits());
   }
 
   // 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));
+    ASSERT(is_uint3(code));
+    emit(0xC0 | code << 3 | rm_reg.low_bits());
   }
 
   // Emit the code-object-relative offset of the label's position