Author: [email protected]
Date: Tue May 26 05:32:09 2009
New Revision: 2057

Modified:
    branches/bleeding_edge/src/x64/assembler-x64-inl.h
    branches/bleeding_edge/src/x64/assembler-x64.cc
    branches/bleeding_edge/src/x64/assembler-x64.h
    branches/bleeding_edge/test/cctest/test-assembler-x64.cc

Log:
Add implementation of control flow and label binding to x64 assembler.
Review URL: http://codereview.chromium.org/113832

Modified: branches/bleeding_edge/src/x64/assembler-x64-inl.h
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64-inl.h  (original)
+++ branches/bleeding_edge/src/x64/assembler-x64-inl.h  Tue May 26 05:32:09  
2009
@@ -44,6 +44,10 @@
  #define EMIT(x)                                 \
    *pc_++ = (x)

+void Assembler::emit(uint32_t x) {
+  *reinterpret_cast<uint32_t*>(pc_) = x;
+  pc_ += sizeof(uint32_t);
+}

  void Assembler::emit_rex_64(Register reg, Register rm_reg) {
    EMIT(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);

Modified: branches/bleeding_edge/src/x64/assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64.cc     (original)
+++ branches/bleeding_edge/src/x64/assembler-x64.cc     Tue May 26 05:32:09 2009
@@ -189,10 +189,34 @@
    UNIMPLEMENTED();
  }

-void Assembler::bind(Label* a) {
-  UNIMPLEMENTED();
+
+void Assembler::bind_to(Label* L, int pos) {
+  ASSERT(!L->is_bound());  // Label may only be bound once.
+  last_pc_ = NULL;
+  ASSERT(0 <= pos && pos <= pc_offset());  // Position must be valid.
+  if (L->is_linked()) {
+    int current = L->pos();
+    int next = long_at(current);
+    while (next != current) {
+      // relative address, relative to point after address
+      int imm32 = pos - (current + sizeof(int32_t));
+      long_at_put(current, imm32);
+      current = next;
+      next = long_at(next);
+    }
+    // Fix up last fixup on linked list.
+    int last_imm32 = pos - (current + sizeof(int32_t));
+    long_at_put(current, last_imm32);
+  }
+  L->bind_to(pos);
+}
+
+
+void Assembler::bind(Label* L) {
+  bind_to(L, pc_offset());
  }

+
  void Assembler::GrowBuffer() {
    ASSERT(overflow());  // should not call this otherwise
    if (!own_buffer_) FATAL("external code buffer is too small");
@@ -275,6 +299,8 @@
  }


+// Assembler Instruction implementations
+
  void Assembler::add(Register dst, const Operand& src) {
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
@@ -289,7 +315,28 @@
    last_pc_ = pc_;
    emit_rex_64(dst, src);
    EMIT(0x03);
-  EMIT(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
+  EMIT(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
+}
+
+
+void Assembler::call(Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  // 1110 1000 #32-bit disp
+  EMIT(0xE8);
+  if (L->is_bound()) {
+    int offset = L->pos() - pc_offset() - sizeof(int32_t);
+    ASSERT(offset <= 0);
+    emit(offset);
+  } else if (L->is_linked()) {
+    emit(L->pos());
+    L->link_to(pc_offset() - sizeof(int32_t));
+  } else {
+    ASSERT(L->is_unused());
+    int32_t current = pc_offset();
+    emit(current);
+    L->link_to(current);
+  }
  }


@@ -343,6 +390,73 @@
  }


+void Assembler::j(Condition cc, Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(0 <= cc && cc < 16);
+  if (L->is_bound()) {
+    const int short_size = 2;
+    const int long_size  = 6;
+    int offs = L->pos() - pc_offset();
+    ASSERT(offs <= 0);
+    if (is_int8(offs - short_size)) {
+      // 0111 tttn #8-bit disp
+      EMIT(0x70 | cc);
+      EMIT((offs - short_size) & 0xFF);
+    } else {
+      // 0000 1111 1000 tttn #32-bit disp
+      EMIT(0x0F);
+      EMIT(0x80 | cc);
+      emit(offs - long_size);
+    }
+  } else if (L->is_linked()) {
+    // 0000 1111 1000 tttn #32-bit disp
+    EMIT(0x0F);
+    EMIT(0x80 | cc);
+    emit(L->pos());
+    L->link_to(pc_offset() - sizeof(int32_t));
+  } else {
+    ASSERT(L->is_unused());
+    EMIT(0x0F);
+    EMIT(0x80 | cc);
+    int32_t current = pc_offset();
+    emit(current);
+    L->link_to(current);
+  }
+}
+
+
+void Assembler::jmp(Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (L->is_bound()) {
+    int offs = L->pos() - pc_offset() - 1;
+    ASSERT(offs <= 0);
+    if (is_int8(offs - sizeof(int8_t))) {
+      // 1110 1011 #8-bit disp
+      EMIT(0xEB);
+      EMIT((offs - sizeof(int8_t)) & 0xFF);
+    } else {
+      // 1110 1001 #32-bit disp
+      EMIT(0xE9);
+      emit(offs - sizeof(int32_t));
+    }
+  } else  if (L->is_linked()) {
+    // 1110 1001 #32-bit disp
+    EMIT(0xE9);
+    emit(L->pos());
+    L->link_to(pc_offset() - sizeof(int32_t));
+  } else {
+    // 1110 1001 #32-bit disp
+    ASSERT(L->is_unused());
+    EMIT(0xE9);
+    int32_t current = pc_offset();
+    emit(current);
+    L->link_to(current);
+  }
+}
+
+
  void Assembler::mov(Register dst, const Operand& src) {
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
@@ -356,8 +470,8 @@
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
    emit_rex_64(dst, src);
-  EMIT(0x89);
-  EMIT(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
+  EMIT(0x8B);
+  EMIT(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
  }



Modified: branches/bleeding_edge/src/x64/assembler-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64.h      (original)
+++ branches/bleeding_edge/src/x64/assembler-x64.h      Tue May 26 05:32:09 2009
@@ -676,9 +676,9 @@
    void jmp(Handle<Code> code, RelocInfo::Mode rmode);

    // Conditional jumps
-  void j(Condition cc, Label* L, Hint hint = no_hint);
-  void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint =  
no_hint);
-  void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
+  void j(Condition cc, Label* L);
+  void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
+  void j(Condition cc, Handle<Code> code);

    // Floating-point operations
    void fld(int i);

Modified: branches/bleeding_edge/test/cctest/test-assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-assembler-x64.cc    (original)
+++ branches/bleeding_edge/test/cctest/test-assembler-x64.cc    Tue May 26  
05:32:09 2009
@@ -38,8 +38,13 @@
  using v8::internal::byte;
  using v8::internal::OS;
  using v8::internal::Assembler;
+using v8::internal::Operand;
+using v8::internal::Label;
  using v8::internal::rax;
  using v8::internal::rsi;
+using v8::internal::rdi;
+using v8::internal::rbp;
+using v8::internal::rsp;
  using v8::internal::FUNCTION_CAST;
  using v8::internal::CodeDesc;

@@ -60,7 +65,7 @@
  #define __ assm.


-TEST(AssemblerX640) {
+TEST(AssemblerX64ReturnOperation) {
    // Allocate an executable page of memory.
    size_t actual_size;
    byte* buffer =  
static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -79,6 +84,116 @@
    // Call the function from C++.
    int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    CHECK_EQ(2, result);
+}
+
+TEST(AssemblerX64StackOperations) {
+  // Allocate an executable page of memory.
+  size_t actual_size;
+  byte* buffer =  
static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+                                                 &actual_size,
+                                                 true));
+  CHECK(buffer);
+  Assembler assm(buffer, actual_size);
+
+  // Assemble a simple function that copies argument 2 and returns it.
+  // We compile without stack frame pointers, so the gdb debugger shows
+  // incorrect stack frames when debugging this function (which has them).
+  __ push(rbp);
+  __ mov(rbp, rsp);
+  __ push(rsi);  // Value at (rbp - 8)
+  __ push(rsi);  // Value at (rbp - 16)
+  __ push(rdi);  // Value at (rbp - 24)
+  __ pop(rax);
+  __ pop(rax);
+  __ pop(rax);
+  __ pop(rbp);
+  __ nop();
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  // Call the function from C++.
+  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
+  CHECK_EQ(2, result);
+}
+
+TEST(AssemblerX64ArithmeticOperations) {
+  // Allocate an executable page of memory.
+  size_t actual_size;
+  byte* buffer =  
static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+                                                 &actual_size,
+                                                 true));
+  CHECK(buffer);
+  Assembler assm(buffer, actual_size);
+
+  // Assemble a simple function that copies argument 2 and returns it.
+  __ mov(rax, rsi);
+  __ add(rax, rdi);
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  // Call the function from C++.
+  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
+  CHECK_EQ(5, result);
+}
+
+TEST(AssemblerX64MemoryOperands) {
+  // Allocate an executable page of memory.
+  size_t actual_size;
+  byte* buffer =  
static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+                                                 &actual_size,
+                                                 true));
+  CHECK(buffer);
+  Assembler assm(buffer, actual_size);
+
+  // Assemble a simple function that copies argument 2 and returns it.
+  __ push(rbp);
+  __ mov(rbp, rsp);
+  __ push(rsi);  // Value at (rbp - 8)
+  __ push(rsi);  // Value at (rbp - 16)
+  __ push(rdi);  // Value at (rbp - 24)
+  // const int kStackElementSize = 8;
+  //  __ mov(rax, Operand(rbp,-3 * kStackElementSize));
+  __ pop(rax);
+  __ pop(rax);
+  __ pop(rax);
+  __ pop(rbp);
+  __ nop();
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  // Call the function from C++.
+  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
+  CHECK_EQ(2, result);
+}
+
+TEST(AssemblerX64ControlFlow) {
+  // Allocate an executable page of memory.
+  size_t actual_size;
+  byte* buffer =  
static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+                                                 &actual_size,
+                                                 true));
+  CHECK(buffer);
+  Assembler assm(buffer, actual_size);
+
+  // Assemble a simple function that copies argument 2 and returns it.
+  __ push(rbp);
+  __ mov(rbp, rsp);
+  __ mov(rax, rdi);
+  Label target;
+  __ jmp(&target);
+  __ mov(rax, rsi);
+  __ bind(&target);
+  __ pop(rbp);
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  // Call the function from C++.
+  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
+  CHECK_EQ(3, result);
  }

  #undef __

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to