Author: [EMAIL PROTECTED]
Date: Fri Dec  5 05:58:46 2008
New Revision: 925

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/codegen.cc
    branches/experimental/toiger/src/flag-definitions.h
    branches/experimental/toiger/src/jump-target-ia32.cc
    branches/experimental/toiger/src/register-allocator-ia32.cc
    branches/experimental/toiger/src/register-allocator-ia32.h
    branches/experimental/toiger/src/virtual-frame-ia32.cc
    branches/experimental/toiger/src/virtual-frame-ia32.h

Log:
Initial real implementation of simple merge for frames.  Does not yet
support register->register moves (which never occur right now).

This is preliminary, so comments on what sort of abstractions it needs
are very welcome.
Review URL: http://codereview.chromium.org/13127

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Fri Dec  5 05:58:46  
2008
@@ -247,7 +247,6 @@
        frame_->CallRuntime(Runtime::kTraceEnter, 0);
        // Ignore the return value.
      }
-    frame_->SpillAll();
      CheckStack();

      // Compile the body of the function in a vanilla state. Don't

Modified: branches/experimental/toiger/src/codegen.cc
==============================================================================
--- branches/experimental/toiger/src/codegen.cc (original)
+++ branches/experimental/toiger/src/codegen.cc Fri Dec  5 05:58:46 2008
@@ -78,7 +78,9 @@
                                       Handle<Script> script,
                                       bool is_eval) {
  #ifdef ENABLE_DISASSEMBLER
-  bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
+  bool print_code = Bootstrapper::IsActive()
+      ? FLAG_print_builtin_code
+      : FLAG_print_code;
  #endif

  #ifdef DEBUG
@@ -89,7 +91,6 @@
    if (Bootstrapper::IsActive()) {
      print_source = FLAG_print_builtin_source;
      print_ast = FLAG_print_builtin_ast;
-    print_code = FLAG_print_builtin_code;
      ftype = "builtin";
    } else {
      print_source = FLAG_print_source;

Modified: branches/experimental/toiger/src/flag-definitions.h
==============================================================================
--- branches/experimental/toiger/src/flag-definitions.h (original)
+++ branches/experimental/toiger/src/flag-definitions.h Fri Dec  5 05:58:46  
2008
@@ -249,7 +249,6 @@
  // codegen-ia32.cc / codegen-arm.cc
  DEFINE_bool(trace_codegen, false,
              "print name of functions for which code is generated")
-DEFINE_bool(print_builtin_code, false, "print generated code for builtins")
  DEFINE_bool(print_source, false, "pretty print source code")
  DEFINE_bool(print_builtin_source, false,
              "pretty print source code for builtins")
@@ -342,6 +341,7 @@

  // codegen-ia32.cc / codegen-arm.cc
  DEFINE_bool(print_code, false, "print generated code")
+DEFINE_bool(print_builtin_code, false, "print generated code for builtins")

  // Cleanup...
  #undef FLAG_FULL

Modified: branches/experimental/toiger/src/jump-target-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/jump-target-ia32.cc        (original)
+++ branches/experimental/toiger/src/jump-target-ia32.cc        Fri Dec  5  
05:58:46 2008
@@ -69,11 +69,13 @@

    if (expected_frame_ == NULL) {
      expected_frame_ = current_frame;
-    expected_frame_->EnsureMergable();
      // The frame at the actual function return will always have height  
zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
        expected_frame_->Forget(expected_frame_->height());
      }
+    if (!expected_frame_->IsMergable()) {
+      expected_frame_->MakeMergable();
+    }
      code_generator_->set_frame(NULL);
    } else {
      // No code needs to be emitted to merge to the expected frame at the
@@ -101,11 +103,13 @@

    if (expected_frame_ == NULL) {
      expected_frame_ = new VirtualFrame(current_frame);
-    expected_frame_->EnsureMergable();
      // The frame at the actual function return will always have height  
zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
        expected_frame_->Forget(expected_frame_->height());
      }
+    if (!expected_frame_->IsMergable()) {
+      expected_frame_->MakeMergable();
+    }
    } else {
      // No code needs to be emitted to merge to the expected frame at the
      // actual function return.
@@ -132,7 +136,9 @@
    ASSERT(expected_frame_ == NULL);

    expected_frame_ = new VirtualFrame(current_frame);
-  expected_frame_->EnsureMergable();
+  if (!expected_frame_->IsMergable()) {
+    expected_frame_->MakeMergable();
+  }
    // Adjust the expected frame's height to account for the return address
    // pushed by the call instruction.
    expected_frame_->Adjust(1);
@@ -156,10 +162,12 @@

    if (expected_frame_ == NULL) {
      expected_frame_ = new VirtualFrame(current_frame);
-    expected_frame_->EnsureMergable();
      // The frame at the actual function return will always have height  
zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
        expected_frame_->Forget(expected_frame_->height());
+    }
+    if (!expected_frame_->IsMergable()) {
+      expected_frame_->MakeMergable();
      }
    } else if (current_frame == NULL) {
      code_generator_->set_frame(new VirtualFrame(expected_frame_));

Modified: branches/experimental/toiger/src/register-allocator-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.cc (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.cc Fri Dec  5  
05:58:46 2008
@@ -41,7 +41,7 @@
  }


-Register RegisterAllocator::Allocate() {
+Register RegisterAllocator::AllocateWithoutSpilling() {
    // Return the first free register, if any.
    for (int i = 0; i < num_registers(); i++) {
      if (!registers_.is_used(i)) {
@@ -50,15 +50,21 @@
        return result;
      }
    }
+  return no_reg;
+}

-  // Ask the current frame to spill a register.
-  ASSERT(code_generator_->frame() != NULL);
-  Register result = code_generator_->frame()->SpillAnyRegister();
-  if (!result.is(no_reg)) {
-    ASSERT(!registers_.is_used(result.code()));
-    registers_.Use(result);
-  }

+Register RegisterAllocator::Allocate() {
+  Register result = AllocateWithoutSpilling();
+  if (result.is(no_reg)) {
+    // Ask the current frame to spill a register.
+    ASSERT(code_generator_->frame() != NULL);
+    result = code_generator_->frame()->SpillAnyRegister();
+    if (!result.is(no_reg)) {
+      ASSERT(!registers_.is_used(result.code()));
+      registers_.Use(result);
+    }
+  }
    return result;
  }


Modified: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.h  (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.h  Fri Dec  5  
05:58:46 2008
@@ -101,6 +101,10 @@
    // Allocate a free register if possible or fail by returning no_reg.
    Register Allocate();

+  // Allocate a free register without spilling any or fail and return
+  // no_reg.
+  Register AllocateWithoutSpilling();
+
   private:
    CodeGenerator* code_generator_;
    RegisterFile registers_;

Modified: branches/experimental/toiger/src/virtual-frame-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.cc      (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.cc      Fri Dec  5  
05:58:46 2008
@@ -172,7 +172,7 @@

    if (best_register_code != no_reg.code_) {
      // Spill all occurrences of the register.  There are min_count
-    // occurrences, stop when we've spilled them all to avoid syncing
+    // occurrences, stop when we have spilled them all to avoid syncing
      // elements unnecessarily.
      int i = 0;
      while (min_count > 0) {
@@ -183,17 +183,12 @@
          // Spill it.
          SpillElementAt(i);
          min_count--;
-      } else {
-        if (i > stack_pointer_) {
-          // Make sure to materialize elements on the virtual frame in
-          // memory.  We rely on this to spill occurrences of the register
-          // lying above the current virtual stack pointer.
-          SyncElementAt(i);
-        }
        }
+      i++;
      }
    }

+  ASSERT(cgen_->allocator()->count(best_register_code) == 0);
    Register result = { best_register_code };
    return result;
  }
@@ -203,6 +198,9 @@
  // allocate space in the actual frame for the virtual element immediately
  // above the stack pointer.
  void VirtualFrame::SpillElementAt(int index) {
+  if (index > stack_pointer_ + 1) {
+    SyncRange(stack_pointer_ + 1, index);
+  }
    SyncElementAt(index);
    // The element is now in memory.
    if (elements_[index].is_register()) {
@@ -212,14 +210,15 @@
  }


-// Clear the dirty bits for all elements.
-void VirtualFrame::SyncAll() {
-  for (int i = 0; i < elements_.length(); i++) {
+// Clear the dirty bits for the range of elements in [begin, end).
+void VirtualFrame::SyncRange(int begin, int end) {
+  ASSERT(begin >= 0);
+  ASSERT(end <= elements_.length());
+  for (int i = begin; i < end; i++) {
      SyncElementAt(i);
    }
  }

-
  // Make the type of all elements be MEMORY.
  void VirtualFrame::SpillAll() {
    for (int i = 0; i < elements_.length(); i++) {
@@ -253,17 +252,106 @@
  }


-void VirtualFrame::EnsureMergable() {
+bool VirtualFrame::IsMergable() {
    // We cannot merge to a frame that has constants as elements, because an
-  // arbitrary frame might not have constants in those locations.
-  //
-  // We cannot merge to a frame that has registers as elements because we
-  // haven't implemented merging for such frames yet.
-  SpillAll();
+  // arbitrary frame may not have the same constants at those locations.   
We
+  // cannot merge to a frame that has registers that are mulitply  
referenced
+  // in the frame, because an arbitrary frame might not exhibit the same
+  // sharing.  Thus, a frame is mergable if all elements are in memory or a
+  // register and no register is multiply referenced.
+  for (int i = 0; i < RegisterFile::kNumRegisters; i++) {
+    if (frame_registers_.count(i) > 1) {
+      return false;
+    }
+  }
+
+  for (int i = 0; i < elements_.length(); i++) {
+    if (!elements_[i].is_memory() && !elements_[i].is_register()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+void VirtualFrame::MakeMergable() {
+  Comment cmnt(masm_, "[ Make frame mergable");
+  // Remove constants from the frame and ensure that no registers are
+  // multiply referenced within the frame.  Allocate elements to their
+  // new locations from the top down so that the topmost elements have
+  // a chance to be in registers, then fill them into memory from the
+  // bottom up.  (NB: Currently when spilling registers that are
+  // multiply referenced, it is the lowermost occurrence that gets to
+  // stay in the register.)
+  FrameElement* new_elements = new FrameElement[elements_.length()];
+  FrameElement memory_element;
+  for (int i = elements_.length() - 1; i >= 0; i--) {
+    FrameElement element = elements_[i];
+    if (element.is_constant() ||
+        (element.is_register() &&
+         frame_registers_.count(element.reg().code()) > 1)) {
+      // A simple strategy is to locate these elements in memory if they  
are
+      // synced (avoiding a spill right now) and otherwise to prefer a
+      // register for them.
+      if (element.is_synced()) {
+        new_elements[i] = memory_element;
+      } else {
+        // This code path is currently not triggered.  UNIMPLEMENTED is
+        // temporarily used to trap when it becomes active so we can test
+        // it.
+        UNIMPLEMENTED();
+        Register reg = cgen_->allocator()->AllocateWithoutSpilling();
+        if (reg.is(no_reg)) {
+          new_elements[i] = memory_element;
+        } else {
+          FrameElement register_element(reg, FrameElement::NOT_SYNCED);
+          new_elements[i] = register_element;
+        }
+      }
+
+      // We have not moved register references, but record that we will so
+      // that we do not unnecessarily spill the last reference within the
+      // frame.
+      if (element.is_register()) {
+        Unuse(element.reg());
+      }
+    } else {
+      // The element is in memory or a singly-frame-referenced register.
+      new_elements[i] = element;
+    }
+  }
+
+  // Perform the moves.
+  for (int i = 0; i < elements_.length(); i++) {
+    FrameElement source = elements_[i];
+    FrameElement target = new_elements[i];
+    ASSERT(target.is_register() || target.is_memory());
+    if (target.is_register()) {
+      if (source.is_constant()) {
+        // The allocator's register reference count was incremented by
+        // register allocation, so we only record the new reference in the
+        // frame.  The frame now owns the reference.
+        frame_registers_.Use(target.reg());
+        __ Set(target.reg(), Immediate(source.handle()));
+      } else if (source.is_register() && !source.reg().is(target.reg())) {
+        // The frame now owns the reference.
+        frame_registers_.Use(target.reg());
+        __ mov(target.reg(), source.reg());
+      }
+      elements_[i] = target;
+    } else {
+      // The target is memory.
+      SpillElementAt(i);
+    }
+  }
+
+  delete[] new_elements;
  }


  void VirtualFrame::MergeTo(VirtualFrame* expected) {
+  Comment cmnt(masm_, "[ Merge frame");
    ASSERT(cgen_ == expected->cgen_);
    ASSERT(masm_ == expected->masm_);
    ASSERT(elements_.length() == expected->elements_.length());
@@ -271,12 +359,67 @@
    ASSERT(local_count_ == expected->local_count_);
    ASSERT(frame_pointer_ == expected->frame_pointer_);

-  // Mergable frames do not have constants and they do not (currently) have
-  // registers.  They are always fully spilled, so the only thing needed to
-  // make this frame match the expected one is to spill everything.
-  //
-  // TODO(): Implement a non-stupid way of merging frames.
-  SpillAll();
+  // Mergable frames have all elements in locations, either memory or
+  // register.  We thus have a series of to-memory and to-register moves.
+  // First perform all to-memory moves, register-to-memory moves because
+  // they can free registers and constant-to-memory moves because they do
+  // not use registers.
+  for (int i = 0; i < elements_.length(); i++) {
+    FrameElement source = elements_[i];
+    FrameElement target = expected->elements_[i];
+    if (target.is_memory() && !source.is_memory()) {
+      ASSERT(source.is_register() || source.is_constant());
+      SpillElementAt(i);
+    }
+  }
+
+  // Then register-to-register moves, not yet implemented.
+  for (int i = 0; i < elements_.length(); i++) {
+    FrameElement source = elements_[i];
+    FrameElement target = expected->elements_[i];
+    ASSERT(!source.is_register() || !target.is_register());
+  }
+
+  // Finally, constant-to-register and memory-to-register.  We do these  
from
+  // the top down so we can use pop for memory-to-register moves above the
+  // expected stack pointer.
+  for (int i = elements_.length() - 1; i >= 0; i--) {
+    FrameElement source = elements_[i];
+    FrameElement target = expected->elements_[i];
+    if (target.is_register() && !source.is_register()) {
+      ASSERT(source.is_constant() || source.is_memory());
+      if (source.is_memory()) {
+        ASSERT(i <= stack_pointer_);
+        if (i <= expected->stack_pointer_) {
+          // Elements below both stack pointers can just be moved.
+          __ mov(target.reg(), Operand(ebp, fp_relative(i)));
+        } else {
+          // Elements below the current stack pointer but above the  
expected
+          // one can be popped, bet first we may have to adjust the stack
+          // pointer downward.
+          if (stack_pointer_ > i + 1) {
+#ifdef DEBUG
+            // In debug builds check to ensure this is safe.
+            for (int j = stack_pointer_; j > i; j--) {
+              ASSERT(!elements_[j].is_memory());
+            }
+#endif
+            stack_pointer_ = i + 1;
+            __ add(Operand(esp),
+                   Immediate((stack_pointer_ - i) * kPointerSize));
+          }
+          stack_pointer_--;
+          __ pop(target.reg());
+        }
+        Use(target.reg());
+      } else if (source.is_constant()) {
+        // Not yet implemented.  When done, code in common with the
+        // memory-to-register just above case can be factored out.
+        UNIMPLEMENTED();
+      }
+      elements_[i] = target;
+    }
+  }

    ASSERT(stack_pointer_ == expected->stack_pointer_);
  }
@@ -330,9 +473,11 @@

    if (count > 0) {
      Comment cmnt(masm_, "[ Allocate space for locals");
-    // The locals are constants (the undefined value), but we sync them  
with
-    // the actual frame to allocate space for spilling them.
-    SyncAll();
+    // The locals are initialized to a constant (the undefined value), but
+    // we sync them with the actual frame to allocate space for spilling
+    // them later.  First sync everything above the stack pointer so we can
+    // use pushes to allocate and initialize the locals.
+    SyncRange(stack_pointer_ + 1, elements_.length());
      Handle<Object> undefined = Factory::undefined_value();
      FrameElement initial_value(undefined, FrameElement::SYNCED);
      Register tmp = cgen_->allocator()->Allocate();
@@ -368,7 +513,7 @@
      __ mov(Operand(ebp, fp_relative(index)), temp);
      cgen_->allocator()->Unuse(temp);
    } else {
-    // We haven't actually written the value to memory.
+    // We have not actually written the value to memory.
      elements_[index].clear_sync();

      if (top.is_register()) {

Modified: branches/experimental/toiger/src/virtual-frame-ia32.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.h       (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.h       Fri Dec  5  
05:58:46 2008
@@ -151,9 +151,14 @@
    // it was not possible to spill one.
    Register SpillAnyRegister();

+  // True if an arbitrary frame of the same size could be merged to this
+  // one.  Requires all values to be in a unique register or memory
+  // location.
+  bool IsMergable();
+
    // Ensure that this frame is in a state where an arbitrary frame of the
    // right size could be merged to it.  May emit code.
-  void EnsureMergable();
+  void MakeMergable();

    // Make this virtual frame have a state identical to an expected virtual
    // frame.  As a side effect, code may be emitted to make this frame match
@@ -350,8 +355,8 @@
    // for all the elements below this one (at least).
    void SpillElementAt(int index);

-  // Sync all elements in the frame.
-  void SyncAll();
+  // Sync the range of elements in [begin, end).
+  void SyncRange(int begin, int end);

    // Store the value on top of the frame to a frame slot (typically a local
    // or parameter).

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

Reply via email to