Author: [email protected]
Date: Mon Jun 22 07:22:39 2009
New Revision: 2238

Modified:
    branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc
    branches/bleeding_edge/src/x64/codegen-x64.cc
    branches/bleeding_edge/src/x64/macro-assembler-x64.cc
    branches/bleeding_edge/src/x64/macro-assembler-x64.h
    branches/bleeding_edge/src/x64/virtual-frame-x64.cc

Log:
X64 implementation: Emit correct merge code for virtual frames at CFG  
merges.
Review URL: http://codereview.chromium.org/141043

Modified: branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc       (original)
+++ branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc       Mon Jun 22  
07:22:39 2009
@@ -189,7 +189,7 @@
            backing_element = elements_[element.index()];
          }
          Result fresh = cgen()->allocator()->Allocate();
-        ASSERT(fresh.is_valid());
+        ASSERT(fresh.is_valid());  // A register was spilled if all were  
in use.
          elements_[i] =
              FrameElement::RegisterElement(fresh.reg(),
                                            FrameElement::NOT_SYNCED);
@@ -218,16 +218,15 @@
            }
          }
        }
-      // No need to set the copied flag---there are no copies of
-      // copies or constants so the original was not copied.
+      // No need to set the copied flag---there are no copies.

        // Backwards jump targets can never know the type of a value.
        elements_[i].set_static_type(StaticType::unknown());
      } else {
-      // Clear the copy flag of non-constant, non-copy elements above
-      // the high water mark.  They cannot be copied because copes are
-      // always higher than their backing store and copies are not
-      // allowed above the water mark.
+      // Clear the copy flag of non-constant, non-copy elements.
+      // They cannot be copied because copies are not allowed.
+      // The copy flag is not relied on before the end of this loop,
+      // including when registers are spilled.
        elements_[i].clear_copied();
      }
    }

Modified: branches/bleeding_edge/src/x64/codegen-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/codegen-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/codegen-x64.cc       Mon Jun 22 07:22:39 2009
@@ -146,6 +146,16 @@
            "    }"
            "    return x;"
            "  }"
+          "\n"
+          "  function test_recursion_with_base(x, y, z, w) {"
+          "    if (x) {"
+          "     x = x;"
+          "    } else {"
+          "      x = test_recursion_with_base(y, z, w, 0);"
+          "    }"
+          "    return x;"
+          "  }"
+          "\n"
            "  function test_local_variables(x, y){"
            "    var w; y = x; x = w; w = y; y = x; return w;"
            "  };"
@@ -154,8 +164,9 @@
            "  test_local_variables("
            "      test_nesting_calls(test_local_variables(1,3), 42, 47),"
            "      test_local_variables(-25.3, 2));"
+          "  // return test_recursion_with_base(0, 0, 0, 47);\n"
            "  var o = { x: 42 };"
-          "  return test_if_then_else(1, 47, 39);"
+          "  return test_if_then_else(0, 46, 47);"
            "})()")),
        Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
        0,

Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/macro-assembler-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/macro-assembler-x64.cc       Mon Jun 22  
07:22:39 2009
@@ -267,6 +267,40 @@
  }


+bool MacroAssembler::IsUnsafeSmi(Smi* value) {
+  return false;
+}
+
+void MacroAssembler::LoadUnsafeSmi(Register dst, Smi* source) {
+  UNIMPLEMENTED();
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> source) {
+  if (source->IsSmi()) {
+    if (IsUnsafeSmi(source)) {
+      LoadUnsafeSmi(dst, source);
+    } else {
+      movq(dst, source, RelocInfo::NONE);
+    }
+  } else {
+    movq(dst, source, RelocInfo::EMBEDDED_OBJECT);
+  }
+}
+
+
+void MacroAssembler::Move(const Operand& dst, Handle<Object> source) {
+  Move(kScratchRegister, source);
+  movq(dst, kScratchRegister);
+}
+
+
+void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
+  Move(kScratchRegister, source);
+  cmpq(dst, kScratchRegister);
+}
+
+
  void MacroAssembler::Jump(ExternalReference ext) {
    movq(kScratchRegister, ext);
    jmp(kScratchRegister);

Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/macro-assembler-x64.h        (original)
+++ branches/bleeding_edge/src/x64/macro-assembler-x64.h        Mon Jun 22  
07:22:39 2009
@@ -158,6 +158,21 @@
    void Set(Register dst, int64_t x);
    void Set(const Operand& dst, int64_t x);

+  // Handle support
+  bool IsUnsafeSmi(Smi* value);
+  bool IsUnsafeSmi(Handle<Object> value) {
+    return IsUnsafeSmi(Smi::cast(*value));
+  }
+
+  void LoadUnsafeSmi(Register dst, Smi* source);
+  void LoadUnsafeSmi(Register dst, Handle<Object> source) {
+    LoadUnsafeSmi(dst, Smi::cast(*source));
+  }
+
+  void Move(Register dst, Handle<Object> source);
+  void Move(const Operand& dst, Handle<Object> source);
+  void Cmp(Register dst, Handle<Object> source);
+
    // Control Flow
    void Jump(Address destination, RelocInfo::Mode rmode);
    void Jump(ExternalReference ext);

Modified: branches/bleeding_edge/src/x64/virtual-frame-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/virtual-frame-x64.cc (original)
+++ branches/bleeding_edge/src/x64/virtual-frame-x64.cc Mon Jun 22 07:22:39  
2009
@@ -393,11 +393,250 @@


  void VirtualFrame::MakeMergable() {
-  // UNIMPLEMENTED();
+  for (int i = 0; i < element_count(); i++) {
+    FrameElement element = elements_[i];
+
+    if (element.is_constant() || element.is_copy()) {
+      if (element.is_synced()) {
+        // Just spill.
+        elements_[i] = FrameElement::MemoryElement();
+      } else {
+        // Allocate to a register.
+        FrameElement backing_element;  // Invalid if not a copy.
+        if (element.is_copy()) {
+          backing_element = elements_[element.index()];
+        }
+        Result fresh = cgen()->allocator()->Allocate();
+        ASSERT(fresh.is_valid());  // A register was spilled if all were  
in use.
+        elements_[i] =
+            FrameElement::RegisterElement(fresh.reg(),
+                                          FrameElement::NOT_SYNCED);
+        Use(fresh.reg(), i);
+
+        // Emit a move.
+        if (element.is_constant()) {
+          __ Move(fresh.reg(), element.handle());
+        } else {
+          ASSERT(element.is_copy());
+          // Copies are only backed by register or memory locations.
+          if (backing_element.is_register()) {
+            // The backing store may have been spilled by allocating,
+            // but that's OK.  If it was, the value is right where we
+            // want it.
+            if (!fresh.reg().is(backing_element.reg())) {
+              __ movq(fresh.reg(), backing_element.reg());
+            }
+          } else {
+            ASSERT(backing_element.is_memory());
+            __ movq(fresh.reg(), Operand(rbp,  
fp_relative(element.index())));
+          }
+        }
+      }
+      // No need to set the copied flag---there are no copies.
+      elements_[i].set_static_type(StaticType::unknown());
+    } else {
+      // Clear the copy flag of non-constant, non-copy elements.
+      // They cannot be copied because copies are not allowed.
+      // The copy flag is not relied on before the end of this loop,
+      // including when registers are spilled.
+      elements_[i].clear_copied();
+    }
+  }
  }

-void VirtualFrame::MergeTo(VirtualFrame* a) {
-  UNIMPLEMENTED();
+
+void VirtualFrame::MergeTo(VirtualFrame* expected) {
+  Comment cmnt(masm(), "[ Merge frame");
+  // We should always be merging the code generator's current frame to an
+  // expected frame.
+  ASSERT(cgen()->frame() == this);
+
+  // Adjust the stack pointer upward (toward the top of the virtual
+  // frame) if necessary.
+  if (stack_pointer_ < expected->stack_pointer_) {
+    int difference = expected->stack_pointer_ - stack_pointer_;
+    stack_pointer_ = expected->stack_pointer_;
+    __ subq(rsp, Immediate(difference * kPointerSize));
+  }
+
+  MergeMoveRegistersToMemory(expected);
+  MergeMoveRegistersToRegisters(expected);
+  MergeMoveMemoryToRegisters(expected);
+
+  // Adjust the stack pointer downward if necessary.
+  if (stack_pointer_ > expected->stack_pointer_) {
+    int difference = stack_pointer_ - expected->stack_pointer_;
+    stack_pointer_ = expected->stack_pointer_;
+    __ addq(rsp, Immediate(difference * kPointerSize));
+  }
+
+  // At this point, the frames should be identical.
+  ASSERT(Equals(expected));
+}
+
+
+void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
+  ASSERT(stack_pointer_ >= expected->stack_pointer_);
+
+  // Move registers, constants, and copies to memory.  Perform moves
+  // from the top downward in the frame in order to leave the backing
+  // stores of copies in registers.
+  for (int i = element_count() - 1; i >= 0; i--) {
+    FrameElement target = expected->elements_[i];
+    if (target.is_register()) continue;  // Handle registers later.
+    if (target.is_memory()) {
+      FrameElement source = elements_[i];
+      switch (source.type()) {
+        case FrameElement::INVALID:
+          // Not a legal merge move.
+          UNREACHABLE();
+          break;
+
+        case FrameElement::MEMORY:
+          // Already in place.
+          break;
+
+        case FrameElement::REGISTER:
+          Unuse(source.reg());
+          if (!source.is_synced()) {
+            __ movq(Operand(rbp, fp_relative(i)), source.reg());
+          }
+          break;
+
+        case FrameElement::CONSTANT:
+          if (!source.is_synced()) {
+            __ Move(Operand(rbp, fp_relative(i)), source.handle());
+          }
+          break;
+
+        case FrameElement::COPY:
+          if (!source.is_synced()) {
+            int backing_index = source.index();
+            FrameElement backing_element = elements_[backing_index];
+            if (backing_element.is_memory()) {
+              __ movq(kScratchRegister,
+                       Operand(rbp, fp_relative(backing_index)));
+              __ movq(Operand(rbp, fp_relative(i)), kScratchRegister);
+            } else {
+              ASSERT(backing_element.is_register());
+              __ movq(Operand(rbp, fp_relative(i)), backing_element.reg());
+            }
+          }
+          break;
+      }
+    }
+    elements_[i] = target;
+  }
+}
+
+
+void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
+  // We have already done X-to-memory moves.
+  ASSERT(stack_pointer_ >= expected->stack_pointer_);
+
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    // Move the right value into register i if it is currently in a  
register.
+    int index = expected->register_location(i);
+    int use_index = register_location(i);
+    // Skip if register i is unused in the target or else if source is
+    // not a register (this is not a register-to-register move).
+    if (index == kIllegalIndex || !elements_[index].is_register())  
continue;
+
+    Register target = RegisterAllocator::ToRegister(i);
+    Register source = elements_[index].reg();
+    if (index != use_index) {
+      if (use_index == kIllegalIndex) {  // Target is currently unused.
+        // Copy contents of source from source to target.
+        // Set frame element register to target.
+        Use(target, index);
+        Unuse(source);
+        __ movq(target, source);
+      } else {
+        // Exchange contents of registers source and target.
+        // Nothing except the register backing use_index has changed.
+        elements_[use_index].set_reg(source);
+        set_register_location(target, index);
+        set_register_location(source, use_index);
+        __ xchg(source, target);
+      }
+    }
+
+    if (!elements_[index].is_synced() &&
+        expected->elements_[index].is_synced()) {
+      __ movq(Operand(rbp, fp_relative(index)), target);
+    }
+    elements_[index] = expected->elements_[index];
+  }
+}
+
+
+void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
+  // Move memory, constants, and copies to registers.  This is the
+  // final step and since it is not done from the bottom up, but in
+  // register code order, we have special code to ensure that the backing
+  // elements of copies are in their correct locations when we
+  // encounter the copies.
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    int index = expected->register_location(i);
+    if (index != kIllegalIndex) {
+      FrameElement source = elements_[index];
+      FrameElement target = expected->elements_[index];
+      Register target_reg = RegisterAllocator::ToRegister(i);
+      ASSERT(target.reg().is(target_reg));
+      switch (source.type()) {
+        case FrameElement::INVALID:  // Fall through.
+          UNREACHABLE();
+          break;
+        case FrameElement::REGISTER:
+          ASSERT(source.Equals(target));
+          // Go to next iteration.  Skips Use(target_reg) and syncing
+          // below.  It is safe to skip syncing because a target
+          // register frame element would only be synced if all source
+          // elements were.
+          continue;
+          break;
+        case FrameElement::MEMORY:
+          ASSERT(index <= stack_pointer_);
+          __ movq(target_reg, Operand(rbp, fp_relative(index)));
+          break;
+
+        case FrameElement::CONSTANT:
+          __ Move(target_reg, source.handle());
+          break;
+
+        case FrameElement::COPY: {
+          int backing_index = source.index();
+          FrameElement backing = elements_[backing_index];
+          ASSERT(backing.is_memory() || backing.is_register());
+          if (backing.is_memory()) {
+            ASSERT(backing_index <= stack_pointer_);
+            // Code optimization if backing store should also move
+            // to a register: move backing store to its register first.
+            if (expected->elements_[backing_index].is_register()) {
+              FrameElement new_backing =  
expected->elements_[backing_index];
+              Register new_backing_reg = new_backing.reg();
+              ASSERT(!is_used(new_backing_reg));
+              elements_[backing_index] = new_backing;
+              Use(new_backing_reg, backing_index);
+              __ movq(new_backing_reg,
+                      Operand(rbp, fp_relative(backing_index)));
+              __ movq(target_reg, new_backing_reg);
+            } else {
+              __ movq(target_reg, Operand(rbp,  
fp_relative(backing_index)));
+            }
+          } else {
+            __ movq(target_reg, backing.reg());
+          }
+        }
+      }
+      // Ensure the proper sync state.
+      if (target.is_synced() && !source.is_synced()) {
+        __ movq(Operand(rbp, fp_relative(index)), target_reg);
+      }
+      Use(target_reg, index);
+      elements_[index] = target;
+    }
+  }
  }


@@ -487,19 +726,7 @@
        break;

      case FrameElement::CONSTANT:
-      if (element.handle()->IsSmi()) {
-        if (CodeGeneratorScope::Current()->IsUnsafeSmi(element.handle())) {
-          CodeGeneratorScope::Current()->LoadUnsafeSmi(kScratchRegister,
-                                                       element.handle());
-        } else {
-          __ movq(kScratchRegister, element.handle(), RelocInfo::NONE);
-        }
-      } else {
-        __ movq(kScratchRegister,
-                 element.handle(),
-                 RelocInfo::EMBEDDED_OBJECT);
-      }
-      __ movq(Operand(rbp, fp_relative(index)), kScratchRegister);
+      __ Move(Operand(rbp, fp_relative(index)), element.handle());
        break;

      case FrameElement::COPY: {
@@ -541,20 +768,7 @@
        break;

      case FrameElement::CONSTANT:
-      if (element.handle()->IsSmi()) {
-        if (CodeGeneratorScope::Current()->IsUnsafeSmi(element.handle())) {
-          CodeGeneratorScope::Current()->LoadUnsafeSmi(kScratchRegister,
-                                                       element.handle());
-        } else {
-          CodeGeneratorScope::Current()->masm()->
-              movq(kScratchRegister, element.handle(), RelocInfo::NONE);
-        }
-      } else {
-        CodeGeneratorScope::Current()->masm()->
-            movq(kScratchRegister,
-                 element.handle(),
-                 RelocInfo::EMBEDDED_OBJECT);
-      }
+      __ Move(kScratchRegister, element.handle());
        __ push(kScratchRegister);
        break;


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

Reply via email to