Added helper functions for fixed register allocation.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 9 Feb 2010 10:18:51 +0000 (10:18 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 9 Feb 2010 10:18:51 +0000 (10:18 +0000)
Added helper functions to the fast code generator for temporary, ad hoc
fixed register allocation.  Also inlined some helper functions that had only
one call site to simplify the code generator API for now.

Review URL: http://codereview.chromium.org/586002

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

src/arm/fast-codegen-arm.cc
src/fast-codegen.h
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc

index 80da533..d777dd8 100644 (file)
@@ -35,49 +35,29 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-void FastCodeGenerator::EmitLoadReceiver(Register reg) {
-  // Offset 2 is due to return address and saved frame pointer.
-  int index = 2 + scope()->num_parameters();
-  __ ldr(reg, MemOperand(sp, index * kPointerSize));
-}
+Register FastCodeGenerator::accumulator0() { return r0; }
+Register FastCodeGenerator::accumulator1() { return r1; }
+Register FastCodeGenerator::scratch0() { return r3; }
+Register FastCodeGenerator::scratch1() { return r4; }
+Register FastCodeGenerator::receiver_reg() { return r2; }
+Register FastCodeGenerator::context_reg() { return cp; }
 
 
-void FastCodeGenerator::EmitReceiverMapCheck() {
-  Comment cmnt(masm(), ";; MapCheck(this)");
-  if (FLAG_print_ir) {
-    PrintF("MapCheck(this)\n");
-  }
-
-  ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
-  Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
-  Handle<Map> map(object->map());
-
-  EmitLoadReceiver(r1);
-  __ CheckMap(r1, r3, map, bailout(), false);
-}
-
-
-void FastCodeGenerator::EmitGlobalMapCheck() {
-  Comment cmnt(masm(), ";; GlobalMapCheck");
-  if (FLAG_print_ir) {
-    PrintF(";; GlobalMapCheck()");
-  }
-
-  ASSERT(info()->has_global_object());
-  Handle<Map> map(info()->global_object()->map());
-
-  __ ldr(r3, CodeGenerator::GlobalObject());
-  __ CheckMap(r3, r3, map, bailout(), true);
+void FastCodeGenerator::EmitLoadReceiver() {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + scope()->num_parameters();
+  __ ldr(receiver_reg(), MemOperand(sp, index * kPointerSize));
 }
 
 
 void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
   ASSERT(cell->IsJSGlobalPropertyCell());
-  __ mov(r0, Operand(cell));
-  __ ldr(r0, FieldMemOperand(r0, JSGlobalPropertyCell::kValueOffset));
+  __ mov(accumulator0(), Operand(cell));
+  __ ldr(accumulator0(),
+         FieldMemOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
   if (FLAG_debug_code) {
     __ mov(ip, Operand(Factory::the_hole_value()));
-    __ cmp(r0, ip);
+    __ cmp(accumulator0(), ip);
     __ Check(ne, "DontDelete cells can't contain the hole");
   }
 }
@@ -96,15 +76,16 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
   // Negative offsets are inobject properties.
   if (offset < 0) {
     offset += map->instance_size();
-    __ mov(r2, r1);  // Copy receiver for write barrier.
+    __ mov(scratch0(), receiver_reg());  // Copy receiver for write barrier.
   } else {
     offset += FixedArray::kHeaderSize;
-    __ ldr(r2, FieldMemOperand(r1, JSObject::kPropertiesOffset));
+    __ ldr(scratch0(),
+           FieldMemOperand(receiver_reg(), JSObject::kPropertiesOffset));
   }
   // Perform the store.
-  __ str(r0, FieldMemOperand(r2, offset));
-  __ mov(r3, Operand(offset));
-  __ RecordWrite(r2, r3, ip);
+  __ str(accumulator0(), FieldMemOperand(scratch0(), offset));
+  __ mov(scratch1(), Operand(offset));
+  __ RecordWrite(scratch0(), scratch1(), ip);
 }
 
 
@@ -119,19 +100,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to cp (context) at
   // this point.
 
-  // Receiver (this) is allocated to r1 if there are this properties.
-  if (info()->has_this_properties()) EmitReceiverMapCheck();
+  // Receiver (this) is allocated to a fixed register.
+  if (info()->has_this_properties()) {
+    Comment cmnt(masm(), ";; MapCheck(this)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(this)\n");
+    }
+    ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
+    Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
+    Handle<Map> map(object->map());
+    EmitLoadReceiver();
+    __ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
+  }
 
-  // If there is a global variable access check if the global object
-  // is the same as at lazy-compilation time.
-  if (info()->has_globals()) EmitGlobalMapCheck();
+  // If there is a global variable access check if the global object is the
+  // same as at lazy-compilation time.
+  if (info()->has_globals()) {
+    Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(GLOBAL)\n");
+    }
+    ASSERT(info()->has_global_object());
+    Handle<Map> map(info()->global_object()->map());
+    __ ldr(scratch0(), CodeGenerator::GlobalObject());
+    __ CheckMap(scratch0(), scratch1(), map, bailout(), true);
+  }
 
   VisitStatements(function()->body());
 
   Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  if (FLAG_print_ir) {
+    PrintF("Return(<undefined>)\n");
+  }
   __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
-
-  Comment epilogue_cmnt(masm(), ";; Epilogue");
   __ mov(sp, fp);
   __ ldm(ia_w, sp, fp.bit() | lr.bit());
   int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
index cbcb5bf..4c1e04b 100644 (file)
@@ -79,13 +79,22 @@ class FastCodeGenerator: public AstVisitor {
   FunctionLiteral* function() { return info_->function(); }
   Scope* scope() { return info_->scope(); }
 
+  // Platform-specific fixed registers, all guaranteed distinct.
+  Register accumulator0();
+  Register accumulator1();
+  Register scratch0();
+  Register scratch1();
+  Register receiver_reg();
+  Register context_reg();
+
   // AST node visit functions.
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
-  // Emit code to load the receiver from the stack into a given register.
-  void EmitLoadReceiver(Register reg);
+  // Emit code to load the receiver from the stack into the fixed receiver
+  // register.
+  void EmitLoadReceiver();
 
   // Emit code to check that the receiver has the same map as the
   // compile-time receiver.  Receiver is expected in {ia32-edx, x64-rdx,
index 126f96b..7ae5d4b 100644 (file)
@@ -35,48 +35,28 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-void FastCodeGenerator::EmitLoadReceiver(Register reg) {
-  // Offset 2 is due to return address and saved frame pointer.
-  int index = 2 + function()->scope()->num_parameters();
-  __ mov(reg, Operand(ebp, index * kPointerSize));
-}
+Register FastCodeGenerator::accumulator0() { return eax; }
+Register FastCodeGenerator::accumulator1() { return edx; }
+Register FastCodeGenerator::scratch0() { return ecx; }
+Register FastCodeGenerator::scratch1() { return edi; }
+Register FastCodeGenerator::receiver_reg() { return ebx; }
+Register FastCodeGenerator::context_reg() { return esi; }
 
 
-void FastCodeGenerator::EmitReceiverMapCheck() {
-  Comment cmnt(masm(), ";; MapCheck(this)");
-  if (FLAG_print_ir) {
-    PrintF("MapCheck(this)\n");
-  }
-
-  ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
-  Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
-  Handle<Map> map(object->map());
-
-  EmitLoadReceiver(edx);
-  __ CheckMap(edx, map, bailout(), false);
-}
-
-
-void FastCodeGenerator::EmitGlobalMapCheck() {
-  Comment cmnt(masm(), ";; GlobalMapCheck");
-  if (FLAG_print_ir) {
-    PrintF(";; GlobalMapCheck()");
-  }
-
-  ASSERT(info()->has_global_object());
-  Handle<Map> map(info()->global_object()->map());
-
-  __ mov(ebx, CodeGenerator::GlobalObject());
-  __ CheckMap(ebx, map, bailout(), true);
+void FastCodeGenerator::EmitLoadReceiver() {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + function()->scope()->num_parameters();
+  __ mov(receiver_reg(), Operand(ebp, index * kPointerSize));
 }
 
 
 void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
   ASSERT(cell->IsJSGlobalPropertyCell());
-  __ mov(eax, Immediate(cell));
-  __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
+  __ mov(accumulator0(), Immediate(cell));
+  __ mov(accumulator0(),
+         FieldOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
   if (FLAG_debug_code) {
-    __ cmp(eax, Factory::the_hole_value());
+    __ cmp(accumulator0(), Factory::the_hole_value());
     __ Check(not_equal, "DontDelete cells can't contain the hole");
   }
 }
@@ -95,16 +75,19 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
   // Negative offsets are inobject properties.
   if (offset < 0) {
     offset += map->instance_size();
-    __ mov(ecx, edx);  // Copy receiver for write barrier.
+    __ mov(scratch0(), receiver_reg());  // Copy receiver for write barrier.
   } else {
     offset += FixedArray::kHeaderSize;
-    __ mov(ecx, FieldOperand(edx, JSObject::kPropertiesOffset));
+    __ mov(scratch0(),
+           FieldOperand(receiver_reg(), JSObject::kPropertiesOffset));
   }
   // Perform the store.
-  __ mov(FieldOperand(ecx, offset), eax);
+  __ mov(FieldOperand(scratch0(), offset), accumulator0());
   // Preserve value from write barrier in case it's needed.
-  __ mov(ebx, eax);
-  __ RecordWrite(ecx, offset, ebx, edi);
+  __ mov(accumulator1(), accumulator0());
+  // The other accumulator register is available as a scratch register
+  // because this is not an AST leaf node.
+  __ RecordWrite(scratch0(), offset, accumulator1(), scratch1());
 }
 
 
@@ -121,19 +104,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
-  // Receiver (this) is allocated to edx if there are this properties.
-  if (info()->has_this_properties()) EmitReceiverMapCheck();
+  // Receiver (this) is allocated to a fixed register.
+  if (info()->has_this_properties()) {
+    Comment cmnt(masm(), ";; MapCheck(this)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(this)\n");
+    }
+    ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
+    Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
+    Handle<Map> map(object->map());
+    EmitLoadReceiver();
+    __ CheckMap(receiver_reg(), map, bailout(), false);
+  }
 
-  // If there is a global variable access check if the global object
-  // is the same as at lazy-compilation time.
-  if (info()->has_globals()) EmitGlobalMapCheck();
+  // If there is a global variable access check if the global object is the
+  // same as at lazy-compilation time.
+  if (info()->has_globals()) {
+    Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(GLOBAL)\n");
+    }
+    ASSERT(info()->has_global_object());
+    Handle<Map> map(info()->global_object()->map());
+    __ mov(scratch0(), CodeGenerator::GlobalObject());
+    __ CheckMap(scratch0(), map, bailout(), true);
+  }
 
   VisitStatements(function()->body());
 
   Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  if (FLAG_print_ir) {
+    PrintF("Return(<undefined>)\n");
+  }
   __ mov(eax, Factory::undefined_value());
-
-  Comment epilogue_cmnt(masm(), ";; Epilogue");
   __ mov(esp, ebp);
   __ pop(ebp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);
index c6e7be2..02f8df6 100644 (file)
@@ -35,48 +35,30 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-void FastCodeGenerator::EmitLoadReceiver(Register reg) {
-  // Offset 2 is due to return address and saved frame pointer.
-  int index = 2 + scope()->num_parameters();
-  __ movq(reg, Operand(rbp, index * kPointerSize));
-}
+// Registers rcx, rdi, and r8-r15 are free to use as scratch registers
+// without saving and restoring any other registers.
+Register FastCodeGenerator::accumulator0() { return rax; }
+Register FastCodeGenerator::accumulator1() { return rdx; }
+Register FastCodeGenerator::scratch0() { return rcx; }
+Register FastCodeGenerator::scratch1() { return rdi; }
+Register FastCodeGenerator::receiver_reg() { return rbx; }
+Register FastCodeGenerator::context_reg() { return rsi; }
 
 
-void FastCodeGenerator::EmitReceiverMapCheck() {
-  Comment cmnt(masm(), ";; MapCheck(this)");
-  if (FLAG_print_ir) {
-    PrintF("MapCheck(this)\n");
-  }
-
-  ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
-  Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
-  Handle<Map> map(object->map());
-
-  EmitLoadReceiver(rdx);
-  __ CheckMap(rdx, map, bailout(), false);
-}
-
-
-void FastCodeGenerator::EmitGlobalMapCheck() {
-  Comment cmnt(masm(), ";; GlobalMapCheck");
-  if (FLAG_print_ir) {
-    PrintF(";; GlobalMapCheck()");
-  }
-
-  ASSERT(info()->has_global_object());
-  Handle<Map> map(info()->global_object()->map());
-
-  __ movq(rbx, CodeGenerator::GlobalObject());
-  __ CheckMap(rbx, map, bailout(), true);
+void FastCodeGenerator::EmitLoadReceiver() {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + scope()->num_parameters();
+  __ movq(receiver_reg(), Operand(rbp, index * kPointerSize));
 }
 
 
 void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
   ASSERT(cell->IsJSGlobalPropertyCell());
-  __ Move(rax, cell);
-  __ movq(rax, FieldOperand(rax, JSGlobalPropertyCell::kValueOffset));
+  __ Move(accumulator0(), cell);
+  __ movq(accumulator0(),
+          FieldOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
   if (FLAG_debug_code) {
-    __ Cmp(rax, Factory::the_hole_value());
+    __ Cmp(accumulator0(), Factory::the_hole_value());
     __ Check(not_equal, "DontDelete cells can't contain the hole");
   }
 }
@@ -95,16 +77,19 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
   // Negative offsets are inobject properties.
   if (offset < 0) {
     offset += map->instance_size();
-    __ movq(rcx, rdx);  // Copy receiver for write barrier.
+    __ movq(scratch0(), receiver_reg());  // Copy receiver for write barrier.
   } else {
     offset += FixedArray::kHeaderSize;
-    __ movq(rcx, FieldOperand(rdx, JSObject::kPropertiesOffset));
+    __ movq(scratch0(),
+            FieldOperand(receiver_reg(), JSObject::kPropertiesOffset));
   }
   // Perform the store.
-  __ movq(FieldOperand(rcx, offset), rax);
+  __ movq(FieldOperand(scratch0(), offset), accumulator0());
   // Preserve value from write barrier in case it's needed.
-  __ movq(rbx, rax);
-  __ RecordWrite(rcx, offset, rbx, rdi);
+  __ movq(accumulator1(), accumulator0());
+  // The other accumulator register is available as a scratch register
+  // because this is not an AST leaf node.
+  __ RecordWrite(scratch0(), offset, accumulator1(), scratch1());
 }
 
 
@@ -121,19 +106,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
-  // Receiver (this) is allocated to rdx if there are this properties.
-  if (info()->has_this_properties()) EmitReceiverMapCheck();
+  // Receiver (this) is allocated to a fixed register.
+  if (info()->has_this_properties()) {
+    Comment cmnt(masm(), ";; MapCheck(this)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(this)\n");
+    }
+    ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
+    Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
+    Handle<Map> map(object->map());
+    EmitLoadReceiver();
+    __ CheckMap(receiver_reg(), map, bailout(), false);
+  }
 
-  // If there is a global variable access check if the global object
-  // is the same as at lazy-compilation time.
-  if (info()->has_globals()) EmitGlobalMapCheck();
+  // If there is a global variable access check if the global object is the
+  // same as at lazy-compilation time.
+  if (info()->has_globals()) {
+    Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
+    if (FLAG_print_ir) {
+      PrintF("MapCheck(GLOBAL)\n");
+    }
+    ASSERT(info()->has_global_object());
+    Handle<Map> map(info()->global_object()->map());
+    __ movq(scratch0(), CodeGenerator::GlobalObject());
+    __ CheckMap(scratch0(), map, bailout(), true);
+  }
 
   VisitStatements(info()->function()->body());
 
   Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  if (FLAG_print_ir) {
+    PrintF("Return(<undefined>)\n");
+  }
   __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
-
-  Comment epilogue_cmnt(masm(), ";; Epilogue");
   __ movq(rsp, rbp);
   __ pop(rbp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);