Revision: 2643
Author: [email protected]
Date: Fri Aug  7 00:15:31 2009
Log: Add support for (some) assignment expressions to the CFG builder and
fast-mode compiler.

1. We avoid generating a useless temporary for assignments with
nontrivial right-hand sides.  Instead of translating id = expr into:

...
tmp = <last expr instruction>
id = tmp

we generate directly

...
id = <last expr instruction>

by passing a data destination ('hint') down the AST.  The semantics is
to use the destination as a result location if a temp is needed.  It
may be ignored.  NULL indicates I don't care and you should generate a
temp.

2. We correctly handle assignments as subexpressions.  When building
the CFG for an expression we accumulate the assigned variables and we
emit a move to a fresh temporary if a value in a variable is in
jeopardy of being overwritten.

Review URL: http://codereview.chromium.org/165056
http://code.google.com/p/v8/source/detail?r=2643

Modified:
  /branches/bleeding_edge/src/arm/cfg-arm.cc
  /branches/bleeding_edge/src/cfg.cc
  /branches/bleeding_edge/src/cfg.h
  /branches/bleeding_edge/src/ia32/cfg-ia32.cc
  /branches/bleeding_edge/src/x64/cfg-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/cfg-arm.cc  Thu Aug  6 04:14:48 2009
+++ /branches/bleeding_edge/src/arm/cfg-arm.cc  Fri Aug  7 00:15:31 2009
@@ -106,28 +106,33 @@
      __ RecordPosition(pos_);
    }
  }
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+  location()->Move(masm, value());
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!val1_->is_on_stack());
+  ASSERT(!value1()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (val0_->is_temporary()) {
+  if (value0()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (val1_->is_temporary()) {
+  } else if (value1()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Move left to r1 and right to r0.
-  val0_->Get(masm, r1);
-  val1_->Get(masm, r0);
-  GenericBinaryOpStub stub(op_, mode);
+  value0()->Get(masm, r1);
+  value1()->Get(masm, r0);
+  GenericBinaryOpStub stub(op(), mode);
    __ CallStub(&stub);
-  loc_->Set(masm, r0);
+  location()->Set(masm, r0);
  }


@@ -165,6 +170,12 @@
        return MemOperand(r0);
    }
  }
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  __ mov(ip, Operand(handle_));
+  __ str(ip, ToMemOperand(loc));
+}


  void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -181,6 +192,18 @@
    __ ldr(ip, ToMemOperand(this));
    __ push(ip);  // Push will not destroy ip.
  }
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+  // Double dispatch.
+  value->MoveToSlot(masm, this);
+}
+
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  __ ldr(ip, ToMemOperand(this));
+  __ str(ip, ToMemOperand(loc));
+}


  void TempLocation::Get(MacroAssembler* masm, Register reg) {
@@ -191,9 +214,8 @@
      case STACK:
        __ pop(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -206,9 +228,8 @@
      case STACK:
        __ push(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -219,13 +240,38 @@
        __ push(r0);
        break;
      case STACK:
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
+  }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+  switch (where_) {
+    case ACCUMULATOR:
+      value->Get(masm, r0);
+    case STACK:
+      value->Push(masm);
        break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
    }
  }


+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  switch (where_) {
+    case ACCUMULATOR:
+      __ str(r0, ToMemOperand(loc));
+    case STACK:
+      __ pop(ip);
+      __ str(ip, ToMemOperand(loc));
+      break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
+  }
+}
+
  #undef __

  } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/cfg.cc  Thu Aug  6 04:14:48 2009
+++ /branches/bleeding_edge/src/cfg.cc  Fri Aug  7 00:15:31 2009
@@ -42,7 +42,7 @@
  CfgGlobals::CfgGlobals(FunctionLiteral* fun)
      : global_fun_(fun),
        global_exit_(new ExitNode()),
-      effect_(new Effect()),
+      nowhere_(new Nowhere()),
  #ifdef DEBUG
        node_counter_(0),
        temp_counter_(0),
@@ -60,6 +60,12 @@
    if (fun->scope()->num_heap_slots() > 0) {
      BAILOUT("function has context slots");
    }
+  if (fun->scope()->num_stack_slots() > kPointerSize) {
+    BAILOUT("function has too many locals");
+  }
+  if (fun->scope()->num_parameters() > kPointerSize - 1) {
+    BAILOUT("function has too many parameters");
+  }
    if (fun->scope()->arguments() != NULL) {
      BAILOUT("function uses .arguments");
    }
@@ -71,18 +77,18 @@

    StatementBuilder builder;
    builder.VisitStatements(body);
-  Cfg* cfg = builder.cfg();
-  if (cfg == NULL) {
+  Cfg* graph = builder.graph();
+  if (graph == NULL) {
      BAILOUT("unsupported statement type");
    }
-  if (cfg->is_empty()) {
+  if (graph->is_empty()) {
      BAILOUT("function body produces empty cfg");
    }
-  if (cfg->has_exit()) {
+  if (graph->has_exit()) {
      BAILOUT("control path without explicit return");
    }
-  cfg->PrependEntryNode();
-  return cfg;
+  graph->PrependEntryNode();
+  return graph;
  }

  #undef BAILOUT
@@ -192,11 +198,21 @@

    return code;
  }
+
+
+void MoveInstr::FastAllocate(TempLocation* temp) {
+  ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
+  if (temp == value()) {
+    temp->set_where(TempLocation::ACCUMULATOR);
+  } else {
+    temp->set_where(TempLocation::STACK);
+  }
+}


  void BinaryOpInstr::FastAllocate(TempLocation* temp) {
-  ASSERT(temp->where() == TempLocation::NOWHERE);
-  if (temp == val0_ || temp == val1_) {
+  ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
+  if (temp == value0() || temp == value1()) {
      temp->set_where(TempLocation::ACCUMULATOR);
    } else {
      temp->set_where(TempLocation::STACK);
@@ -205,7 +221,7 @@


  void ReturnInstr::FastAllocate(TempLocation* temp) {
-  ASSERT(temp->where() == TempLocation::NOWHERE);
+  ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
    if (temp == value_) {
      temp->set_where(TempLocation::ACCUMULATOR);
    } else {
@@ -226,7 +242,7 @@
  // Macros (temporarily) handling unsupported expression types.
  #define BAILOUT(reason)                         \
    do {                                          \
-    cfg_ = NULL;                                \
+    graph_ = NULL;                              \
      return;                                     \
    } while (false)

@@ -260,11 +276,13 @@
    if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) {
      BAILOUT("unsupported slot type (not a parameter or local)");
    }
+  // Ignore the passed destination.
    value_ = new SlotLocation(slot->type(), slot->index());
  }


  void ExpressionBuilder::VisitLiteral(Literal* expr) {
+  // Ignore the passed destination.
    value_ = new Constant(expr->handle());
  }

@@ -290,7 +308,42 @@


  void ExpressionBuilder::VisitAssignment(Assignment* expr) {
-  BAILOUT("Assignment");
+  if (expr->op() != Token::ASSIGN && expr->op() != Token::INIT_VAR) {
+    BAILOUT("unsupported compound assignment");
+  }
+  Expression* lhs = expr->target();
+  if (lhs->AsProperty() != NULL) {
+    BAILOUT("unsupported property assignment");
+  }
+  Variable* var = lhs->AsVariableProxy()->AsVariable();
+  if (var == NULL) {
+    BAILOUT("unsupported invalid left-hand side");
+  }
+  if (var->is_global()) {
+    BAILOUT("unsupported global variable");
+  }
+  Slot* slot = var->slot();
+  ASSERT(slot != NULL);
+  if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) {
+    BAILOUT("unsupported slot lhs (not a parameter or local)");
+  }
+
+  ExpressionBuilder builder;
+  SlotLocation* loc = new SlotLocation(slot->type(), slot->index());
+  builder.Build(expr->value(), loc);
+  if (builder.graph() == NULL) {
+    BAILOUT("unsupported expression in assignment");
+  }
+  // If the expression did not come back in the slot location, append
+  // a move to the CFG.
+  graph_ = builder.graph();
+  if (builder.value() != loc) {
+    graph()->Append(new MoveInstr(loc, builder.value()));
+  }
+  // Record the assignment.
+  assigned_vars_.AddElement(loc);
+  // Ignore the destination passed to us.
+  value_ = loc;
  }


@@ -354,21 +407,35 @@
      case Token::DIV:
      case Token::MOD: {
        ExpressionBuilder left, right;
-      left.Build(expr->left());
-      if (left.cfg() == NULL) {
+      left.Build(expr->left(), NULL);
+      if (left.graph() == NULL) {
          BAILOUT("unsupported left subexpression in binop");
        }
-      right.Build(expr->right());
-      if (right.cfg() == NULL) {
+      right.Build(expr->right(), NULL);
+      if (right.graph() == NULL) {
          BAILOUT("unsupported right subexpression in binop");
        }

-      Location* temp = new TempLocation();
-      cfg_ = left.cfg();
-      cfg_->Concatenate(right.cfg());
-      cfg_->Append(new BinaryOpInstr(temp, op, left.value(),  
right.value()));
-
-      value_ = temp;
+      if (destination_ == NULL) destination_ = new TempLocation();
+
+      graph_ = left.graph();
+      // Insert a move to a fresh temporary if the left value is in a
+      // slot that's assigned on the right.
+      Location* temp = NULL;
+      if (left.value()->is_slot() &&
+           
right.assigned_vars()->Contains(SlotLocation::cast(left.value()))) {
+        temp = new TempLocation();
+        graph()->Append(new MoveInstr(temp, left.value()));
+      }
+      graph()->Concatenate(right.graph());
+      graph()->Append(new BinaryOpInstr(destination_, op,
+                                        temp == NULL ? left.value() : temp,
+                                        right.value()));
+
+      assigned_vars_ = *left.assigned_vars();
+      assigned_vars()->Union(right.assigned_vars());
+
+      value_ = destination_;
        return;
      }

@@ -393,18 +460,18 @@
  // Macros (temporarily) handling unsupported statement types.
  #define BAILOUT(reason)                         \
    do {                                          \
-    cfg_ = NULL;                                \
+    graph_ = NULL;                              \
      return;                                     \
    } while (false)

  #define CHECK_BAILOUT()                         \
-  if (cfg_ == NULL) { return; } else {}
+  if (graph() == NULL) { return; } else {}

  void StatementBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
    for (int i = 0, len = stmts->length(); i < len; i++) {
      Visit(stmts->at(i));
      CHECK_BAILOUT();
-    if (!cfg_->has_exit()) return;
+    if (!graph()->has_exit()) return;
    }
  }

@@ -425,19 +492,12 @@

  void StatementBuilder::VisitExpressionStatement(ExpressionStatement* stmt)  
{
    ExpressionBuilder builder;
-  builder.Build(stmt->expression());
-  if (builder.cfg() == NULL) {
+  builder.Build(stmt->expression(), CfgGlobals::current()->nowhere());
+  if (builder.graph() == NULL) {
      BAILOUT("unsupported expression in expression statement");
    }
-  // Here's a temporary hack: we bang on the last instruction of the
-  // expression (if any) to set its location to Effect.
-  if (!builder.cfg()->is_empty()) {
-    InstructionBlock* block =  
InstructionBlock::cast(builder.cfg()->exit());
-    Instruction* instr = block->instructions()->last();
-    instr->set_location(CfgGlobals::current()->effect_location());
-  }
-  cfg_->Append(new PositionInstr(stmt->statement_pos()));
-  cfg_->Concatenate(builder.cfg());
+  graph()->Append(new PositionInstr(stmt->statement_pos()));
+  graph()->Concatenate(builder.graph());
  }


@@ -463,14 +523,14 @@

  void StatementBuilder::VisitReturnStatement(ReturnStatement* stmt) {
    ExpressionBuilder builder;
-  builder.Build(stmt->expression());
-  if (builder.cfg() == NULL) {
+  builder.Build(stmt->expression(), NULL);
+  if (builder.graph() == NULL) {
      BAILOUT("unsupported expression in return statement");
    }

-  cfg_->Append(new PositionInstr(stmt->statement_pos()));
-  cfg_->Concatenate(builder.cfg());
-  cfg_->AppendReturnInstruction(builder.value());
+  graph()->Append(new PositionInstr(stmt->statement_pos()));
+  graph()->Concatenate(builder.graph());
+  graph()->AppendReturnInstruction(builder.value());
  }


@@ -530,8 +590,8 @@
  }


-void Effect::Print() {
-  PrintF("Effect");
+void Nowhere::Print() {
+  PrintF("Nowhere");
  }


@@ -553,15 +613,24 @@
  void TempLocation::Print() {
    PrintF("Temp(%d)", number());
  }
+
+
+void MoveInstr::Print() {
+  PrintF("Move(");
+  location()->Print();
+  PrintF(", ");
+  value_->Print();
+  PrintF(")\n");
+}


  void BinaryOpInstr::Print() {
    PrintF("BinaryOp(");
-  loc_->Print();
-  PrintF(", %s, ", Token::Name(op_));
-  val0_->Print();
+  location()->Print();
+  PrintF(", %s, ", Token::Name(op()));
+  value0()->Print();
    PrintF(", ");
-  val1_->Print();
+  value1()->Print();
    PrintF(")\n");
  }

=======================================
--- /branches/bleeding_edge/src/cfg.h   Thu Aug  6 04:14:48 2009
+++ /branches/bleeding_edge/src/cfg.h   Fri Aug  7 00:15:31 2009
@@ -43,21 +43,23 @@
  // Instructions are described by the following grammar.
  //
  // <Instruction> ::=
-//     BinaryOpInstr <Location> Token::Value <Value> <Value>
-//   | ReturnInstr Effect <Value>
+//     MoveInstr <Location> <Value>
+//   | BinaryOpInstr <Location> Token::Value <Value> <Value>
+//   | ReturnInstr Nowhere <Value>
+//   | PositionInstr <Int>
  //
  // Values are trivial expressions:
  //
  // <Value> ::= Constant | <Location>
  //
  // Locations are storable values ('lvalues').  They can be slots,
-// compiler-generated temporaries, or the special location 'Effect'
+// compiler-generated temporaries, or the special location 'Nowhere'
  // indicating that no value is needed.
  //
  // <Location> ::=
  //     SlotLocation Slot::Type <Index>
  //   | TempLocation
-//   | Effect
+//   | Nowhere


  // Administrative nodes: There are several types of 'administrative' nodes
@@ -95,8 +97,8 @@
    // The shared global exit node for all exits from the function.
    ExitNode* exit() { return global_exit_; }

-  // A singleton effect location.
-  Location* effect_location() { return effect_; }
+  // A singleton.
+  Location* nowhere() { return nowhere_; }

  #ifdef DEBUG
    int next_node_number() { return node_counter_++; }
@@ -107,7 +109,7 @@
    static CfgGlobals* top_;
    FunctionLiteral* global_fun_;
    ExitNode* global_exit_;
-  Location* effect_;
+  Location* nowhere_;

  #ifdef DEBUG
    // Used to number nodes and temporaries when printing.
@@ -119,6 +121,8 @@
  };


+class SlotLocation;
+
  // Values represent trivial source expressions: ones with no side effects
  // and that do not require code to be generated.
  class Value : public ZoneObject {
@@ -133,6 +137,9 @@

    // True if the value is a compiler-generated temporary location.
    virtual bool is_temporary() { return false; }
+
+  // True if the value is a slot location.
+  virtual bool is_slot() { return false; }

    // Support for fast-compilation mode:

@@ -142,6 +149,9 @@
    // Push the value on the stack.
    virtual void Push(MacroAssembler* masm) = 0;

+  // Move the value into a slot location.
+  virtual void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) = 0;
+
  #ifdef DEBUG
    virtual void Print() = 0;
  #endif
@@ -158,6 +168,7 @@
    // Support for fast-compilation mode.
    void Get(MacroAssembler* masm, Register reg);
    void Push(MacroAssembler* masm);
+  void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);

  #ifdef DEBUG
    void Print();
@@ -173,9 +184,9 @@
   public:
    virtual ~Location() {}

-  // Static factory function returning the singleton effect location.
-  static Location* Effect() {
-    return CfgGlobals::current()->effect_location();
+  // Static factory function returning the singleton nowhere location.
+  static Location* Nowhere() {
+    return CfgGlobals::current()->nowhere();
    }

    // Support for fast-compilation mode:
@@ -191,29 +202,34 @@
    // temporary it was not allocated to the stack.
    virtual void Push(MacroAssembler* masm) = 0;

+  // Emit code to move a value into this location.
+  virtual void Move(MacroAssembler* masm, Value* value) = 0;
+
  #ifdef DEBUG
    virtual void Print() = 0;
  #endif
  };


-// Effect is a special (singleton) location that indicates the value of a
+// Nowhere is a special (singleton) location that indicates the value of a
  // computation is not needed (though its side effects are).
-class Effect : public Location {
+class Nowhere : public Location {
   public:
-  // We should not try to emit code to read Effect.
+  // We should not try to emit code to read Nowhere.
    void Get(MacroAssembler* masm, Register reg) { UNREACHABLE(); }
    void Push(MacroAssembler* masm) { UNREACHABLE(); }
-
-  // Setting Effect is ignored.
+  void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {  
UNREACHABLE(); }
+
+  // Setting Nowhere is ignored.
    void Set(MacroAssembler* masm, Register reg) {}
+  void Move(MacroAssembler* masm, Value* value) {}

  #ifdef DEBUG
    void Print();
  #endif

   private:
-  Effect() {}
+  Nowhere() {}

    friend class CfgGlobals;
  };
@@ -224,15 +240,26 @@
  class SlotLocation : public Location {
   public:
    SlotLocation(Slot::Type type, int index) : type_(type), index_(index) {}
+
+  // Cast accessor.
+  static SlotLocation* cast(Value* value) {
+    ASSERT(value->is_slot());
+    return reinterpret_cast<SlotLocation*>(value);
+  }

    // Accessors.
    Slot::Type type() { return type_; }
    int index() { return index_; }
+
+  // Predicates.
+  bool is_slot() { return true; }

    // Support for fast-compilation mode.
    void Get(MacroAssembler* masm, Register reg);
    void Set(MacroAssembler* masm, Register reg);
    void Push(MacroAssembler* masm);
+  void Move(MacroAssembler* masm, Value* value);
+  void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);

  #ifdef DEBUG
    void Print();
@@ -252,21 +279,21 @@
   public:
    // Fast-compilation mode allocation decisions.
    enum Where {
-    NOWHERE,      // Not yet allocated.
-    ACCUMULATOR,  // Allocated to the dedicated accumulator register.
-    STACK         //   "   "   "   "  stack.
+    NOT_ALLOCATED,  // Not yet allocated.
+    ACCUMULATOR,    // Allocated to the dedicated accumulator register.
+    STACK           //   "   "   "   "  stack.
    };

-  TempLocation() : where_(NOWHERE) {
+  TempLocation() : where_(NOT_ALLOCATED) {
  #ifdef DEBUG
      number_ = -1;
  #endif
    }

    // Cast accessor.
-  static TempLocation* cast(Location* loc) {
-    ASSERT(loc->is_temporary());
-    return reinterpret_cast<TempLocation*>(loc);
+  static TempLocation* cast(Value* value) {
+    ASSERT(value->is_temporary());
+    return reinterpret_cast<TempLocation*>(value);
    }

    // Accessors.
@@ -281,6 +308,8 @@
    void Get(MacroAssembler* masm, Register reg);
    void Set(MacroAssembler* masm, Register reg);
    void Push(MacroAssembler* masm);
+  void Move(MacroAssembler* masm, Value* value);
+  void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);

  #ifdef DEBUG
    int number() {
@@ -306,16 +335,16 @@
  class Instruction : public ZoneObject {
   public:
    // Every instruction has a location where its result is stored (which may
-  // be Effect, the default).
-  Instruction() : loc_(CfgGlobals::current()->effect_location()) {}
-
-  explicit Instruction(Location* loc) : loc_(loc) {}
+  // be Nowhere, the default).
+  Instruction() : location_(CfgGlobals::current()->nowhere()) {}
+
+  explicit Instruction(Location* location) : location_(location) {}

    virtual ~Instruction() {}

    // Accessors.
-  Location* location() { return loc_; }
-  void set_location(Location* loc) { loc_ = loc; }
+  Location* location() { return location_; }
+  void set_location(Location* location) { location_ = location; }

    // Support for fast-compilation mode:

@@ -332,7 +361,7 @@
  #endif

   protected:
-  Location* loc_;
+  Location* location_;
  };


@@ -360,13 +389,39 @@
  };


+// Move a value to a location.
+class MoveInstr : public Instruction {
+ public:
+  MoveInstr(Location* loc, Value* value) : Instruction(loc), value_(value)  
{}
+
+  // Accessors.
+  Value* value() { return value_; }
+
+  // Support for fast-compilation mode.
+  void Compile(MacroAssembler* masm);
+  void FastAllocate(TempLocation* temp);
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+ private:
+  Value* value_;
+};
+
+
  // Perform a (non-short-circuited) binary operation on a pair of values,
  // leaving the result in a location.
  class BinaryOpInstr : public Instruction {
   public:
-  BinaryOpInstr(Location* loc, Token::Value op, Value* val0, Value* val1)
-      : Instruction(loc), op_(op), val0_(val0), val1_(val1) {
-  }
+  BinaryOpInstr(Location* loc, Token::Value op, Value* value0, Value*  
value1)
+      : Instruction(loc), op_(op), value0_(value0), value1_(value1) {
+  }
+
+  // Accessors.
+  Token::Value op() { return op_; }
+  Value* value0() { return value0_; }
+  Value* value1() { return value1_; }

    // Support for fast-compilation mode.
    void Compile(MacroAssembler* masm);
@@ -378,8 +433,8 @@

   private:
    Token::Value op_;
-  Value* val0_;
-  Value* val1_;
+  Value* value0_;
+  Value* value1_;
  };


@@ -390,7 +445,6 @@
  // successor is the global exit node for the current function.
  class ReturnInstr : public Instruction {
   public:
-  // Location is always Effect.
    explicit ReturnInstr(Value* value) : value_(value) {}

    virtual ~ReturnInstr() {}
@@ -605,6 +659,52 @@
  };


+// An implementation of a set of locations (currently slot locations).
+class LocationSet BASE_EMBEDDED {
+ public:
+  // Construct an empty location set.
+  LocationSet() : parameters_(0), locals_(0) {}
+
+  // Raw accessors.
+  uintptr_t parameters() { return parameters_; }
+  uintptr_t locals() { return locals_; }
+
+  // Insert an element.
+  void AddElement(SlotLocation* location) {
+    if (location->type() == Slot::PARAMETER) {
+      // Parameter indexes begin with -1 ('this').
+      ASSERT(location->index() < kPointerSize - 1);
+      parameters_ |= (1 << (location->index() + 1));
+    } else {
+      ASSERT(location->type() == Slot::LOCAL);
+      ASSERT(location->index() < kPointerSize);
+      locals_ |= (1 << location->index());
+    }
+  }
+
+  // (Destructively) compute the union with another set.
+  void Union(LocationSet* other) {
+    parameters_ |= other->parameters();
+    locals_ |= other->locals();
+  }
+
+  bool Contains(SlotLocation* location) {
+    if (location->type() == Slot::PARAMETER) {
+      ASSERT(location->index() < kPointerSize - 1);
+      return (parameters_ & (1 << (location->index() + 1)));
+    } else {
+      ASSERT(location->type() == Slot::LOCAL);
+      ASSERT(location->index() < kPointerSize);
+      return (locals_ & (1 << location->index()));
+    }
+  }
+
+ private:
+  uintptr_t parameters_;
+  uintptr_t locals_;
+};
+
+
  // An ExpressionBuilder traverses an expression and returns an open CFG
  // fragment (currently a possibly empty list of instructions represented by
  // a singleton instruction block) and the expression's value.
@@ -612,15 +712,23 @@
  // Failure is to build the CFG is indicated by a NULL CFG.
  class ExpressionBuilder : public AstVisitor {
   public:
-  ExpressionBuilder() : value_(NULL), cfg_(NULL) {}
+  ExpressionBuilder() : value_(NULL), graph_(NULL), destination_(NULL) {}

    // Result accessors.
    Value* value() { return value_; }
-  Cfg* cfg() { return cfg_; }
-
-  void Build(Expression* expr) {
+  Cfg* graph() { return graph_; }
+  LocationSet* assigned_vars() { return &assigned_vars_; }
+
+  // Build the cfg for an expression and remember its value.  The
+  // destination is a 'hint' where the value should go which may be  
ignored.
+  // NULL is used to indicate no preference.
+  //
+  // Concretely, if the expression needs to generate a temporary for its
+  // value, it should use the passed destination or generate one if NULL.
+  void Build(Expression* expr, Location* destination) {
      value_ = NULL;
-    cfg_ = new Cfg();
+    graph_ = new Cfg();
+    destination_ = destination;
      Visit(expr);
    }

@@ -630,8 +738,13 @@
  #undef DECLARE_VISIT

   private:
+  // State for the visitor.  Output parameters.
    Value* value_;
-  Cfg* cfg_;
+  Cfg* graph_;
+  LocationSet assigned_vars_;
+
+  // Input parameters.
+  Location* destination_;
  };


@@ -640,9 +753,9 @@
  // accumulator.
  class StatementBuilder : public AstVisitor {
   public:
-  StatementBuilder() : cfg_(new Cfg()) {}
-
-  Cfg* cfg() { return cfg_; }
+  StatementBuilder() : graph_(new Cfg()) {}
+
+  Cfg* graph() { return graph_; }

    void VisitStatements(ZoneList<Statement*>* stmts);

@@ -652,7 +765,7 @@
  #undef DECLARE_VISIT

   private:
-  Cfg* cfg_;
+  Cfg* graph_;
  };


=======================================
--- /branches/bleeding_edge/src/ia32/cfg-ia32.cc        Thu Aug  6 04:14:48 2009
+++ /branches/bleeding_edge/src/ia32/cfg-ia32.cc        Fri Aug  7 00:15:31 2009
@@ -119,30 +119,35 @@
      __ RecordPosition(pos_);
    }
  }
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+  location()->Move(masm, value());
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!val1_->is_on_stack());
+  ASSERT(!value1()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (val0_->is_temporary()) {
+  if (value0()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (val1_->is_temporary()) {
+  } else if (value1()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Push both operands and call the specialized stub.
-  if (!val0_->is_on_stack()) {
-    val0_->Push(masm);
-  }
-  val1_->Push(masm);
-  GenericBinaryOpStub stub(op_, mode, SMI_CODE_IN_STUB);
+  if (!value0()->is_on_stack()) {
+    value0()->Push(masm);
+  }
+  value1()->Push(masm);
+  GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
    __ CallStub(&stub);
-  loc_->Set(masm, eax);
+  location()->Set(masm, eax);
  }


@@ -179,6 +184,11 @@
        return Operand(eax);
    }
  }
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  __ mov(ToOperand(loc), Immediate(handle_));
+}


  void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -194,6 +204,19 @@
  void SlotLocation::Push(MacroAssembler* masm) {
    __ push(ToOperand(this));
  }
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+  // We dispatch to the value because in some cases (temp or constant)
+  // we can use a single instruction.
+  value->MoveToSlot(masm, this);
+}
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  // The accumulator is not live across a MoveInstr.
+  __ mov(eax, ToOperand(this));
+  __ mov(ToOperand(loc), eax);
+}


  void TempLocation::Get(MacroAssembler* masm, Register reg) {
@@ -204,9 +227,8 @@
      case STACK:
        __ pop(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -219,9 +241,8 @@
      case STACK:
        __ push(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -232,9 +253,36 @@
        __ push(eax);
        break;
      case STACK:
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
+  }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+  switch (where_) {
+    case ACCUMULATOR:
+      value->Get(masm, eax);
        break;
+    case STACK:
+      value->Push(masm);
+      break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
+  }
+}
+
+
+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  switch (where_) {
+    case ACCUMULATOR:
+      __ mov(ToOperand(loc), eax);
+      break;
+    case STACK:
+      __ pop(ToOperand(loc));
+      break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
    }
  }

=======================================
--- /branches/bleeding_edge/src/x64/cfg-x64.cc  Thu Aug  6 04:14:48 2009
+++ /branches/bleeding_edge/src/x64/cfg-x64.cc  Fri Aug  7 00:15:31 2009
@@ -129,30 +129,35 @@
      __ RecordPosition(pos_);
    }
  }
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+  location()->Move(masm, value());
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!val1_->is_on_stack());
+  ASSERT(!value1()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (val0_->is_temporary()) {
+  if (value0()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (val1_->is_temporary()) {
+  } else if (value1()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Push both operands and call the specialized stub.
-  if (!val0_->is_on_stack()) {
-    val0_->Push(masm);
-  }
-  val1_->Push(masm);
-  GenericBinaryOpStub stub(op_, mode, SMI_CODE_IN_STUB);
+  if (!value0()->is_on_stack()) {
+    value0()->Push(masm);
+  }
+  value1()->Push(masm);
+  GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
    __ CallStub(&stub);
-  loc_->Set(masm, rax);
+  location()->Set(masm, rax);
  }


@@ -189,6 +194,11 @@
        return Operand(rax, 0);
    }
  }
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  __ Move(ToOperand(loc), handle_);
+}


  void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -199,6 +209,19 @@
  void SlotLocation::Set(MacroAssembler* masm, Register reg) {
    __ movq(ToOperand(this), reg);
  }
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+  // We dispatch to the value because in some cases (temp or constant) we
+  // can use special instruction sequences.
+  value->MoveToSlot(masm, this);
+}
+
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  __ movq(kScratchRegister, ToOperand(this));
+  __ movq(ToOperand(loc), kScratchRegister);
+}


  void SlotLocation::Push(MacroAssembler* masm) {
@@ -214,9 +237,8 @@
      case STACK:
        __ pop(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -229,9 +251,8 @@
      case STACK:
        __ push(reg);
        break;
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
-      break;
    }
  }

@@ -242,9 +263,36 @@
        __ push(rax);
        break;
      case STACK:
-    case NOWHERE:
+    case NOT_ALLOCATED:
        UNREACHABLE();
+  }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+  switch (where_) {
+    case ACCUMULATOR:
+      value->Get(masm, rax);
        break;
+    case STACK:
+      value->Push(masm);
+      break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
+  }
+}
+
+
+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+  switch (where_) {
+    case ACCUMULATOR:
+      __ movq(ToOperand(loc), rax);
+      break;
+    case STACK:
+      __ pop(ToOperand(loc));
+      break;
+    case NOT_ALLOCATED:
+      UNREACHABLE();
    }
  }


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

Reply via email to