Revision: 4113
Author: [email protected]
Date: Fri Mar 12 02:35:45 2010
Log: Compute reaching definitions.

Use the classical worklist algorithm to compute reaching definitions.
All nodes are initially put on the worklist.  Until the worklist is
empty, nodes are removed, their RD_in is recomputed, and if it changes
their successors are added to the worklist.

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

Modified:
 /branches/bleeding_edge/src/data-flow.cc
 /branches/bleeding_edge/src/data-flow.h

=======================================
--- /branches/bleeding_edge/src/data-flow.cc    Fri Mar 12 02:20:31 2010
+++ /branches/bleeding_edge/src/data-flow.cc    Fri Mar 12 02:35:45 2010
@@ -1903,13 +1903,21 @@


 void Node::InitializeReachingDefinitions(int definition_count,
-                                         List<BitVector*>* variables) {
+                                         List<BitVector*>* variables,
+                                         WorkList<Node>* worklist,
+                                         bool mark) {
+  ASSERT(!IsMarkedWith(mark));
   rd_.Initialize(definition_count);
+  MarkWith(mark);
+  worklist->Insert(this);
 }


 void BlockNode::InitializeReachingDefinitions(int definition_count,
- List<BitVector*>* variables) {
+                                              List<BitVector*>* variables,
+                                              WorkList<Node>* worklist,
+                                              bool mark) {
+  ASSERT(!IsMarkedWith(mark));
   int instruction_count = instructions_.length();
   int variable_count = variables->length();

@@ -1932,6 +1940,119 @@
     // This one is generated.
     rd_.gen()->Add(expr->num());
   }
+
+  // Add all blocks except the entry node to the worklist.
+  if (predecessor_ != NULL) {
+    MarkWith(mark);
+    worklist->Insert(this);
+  }
+}
+
+
+void ExitNode::ComputeRDOut(BitVector* result) {
+  // Should not be the predecessor of any node.
+  UNREACHABLE();
+}
+
+
+void BlockNode::ComputeRDOut(BitVector* result) {
+  // All definitions reaching this block ...
+  result->CopyFrom(*rd_.rd_in());
+  // ... except those killed by the block ...
+  result->Subtract(*rd_.kill());
+  // ... but including those generated by the block.
+  result->Union(*rd_.gen());
+}
+
+
+void BranchNode::ComputeRDOut(BitVector* result) {
+  // Branch nodes don't kill or generate definitions.
+  result->CopyFrom(*rd_.rd_in());
+}
+
+
+void JoinNode::ComputeRDOut(BitVector* result) {
+  // Join nodes don't kill or generate definitions.
+  result->CopyFrom(*rd_.rd_in());
+}
+
+
+void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  // The exit node has no successors so we can just update in place.  New
+  // RD_in is the union over all predecessors.
+  int definition_count = rd_.rd_in()->length();
+  rd_.rd_in()->Clear();
+
+  BitVector temp(definition_count);
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    // Because ComputeRDOut always overwrites temp and its value is
+    // always read out before calling ComputeRDOut again, we do not
+    // have to clear it on each iteration of the loop.
+    predecessors_[i]->ComputeRDOut(&temp);
+    rd_.rd_in()->Union(temp);
+  }
+}
+
+
+void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  // The entry block has no predecessor.  Its RD_in does not change.
+  if (predecessor_ == NULL) return;
+
+  BitVector new_rd_in(rd_.rd_in()->length());
+  predecessor_->ComputeRDOut(&new_rd_in);
+
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(new_rd_in);
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
+}
+
+
+void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  BitVector new_rd_in(rd_.rd_in()->length());
+  predecessor_->ComputeRDOut(&new_rd_in);
+
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(new_rd_in);
+  // Add the successors to the worklist if not already present.
+  if (!successor0_->IsMarkedWith(mark)) {
+    successor0_->MarkWith(mark);
+    worklist->Insert(successor0_);
+  }
+  if (!successor1_->IsMarkedWith(mark)) {
+    successor1_->MarkWith(mark);
+    worklist->Insert(successor1_);
+  }
+}
+
+
+void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
+  int definition_count = rd_.rd_in()->length();
+  BitVector new_rd_in(definition_count);
+
+  // New RD_in is the union over all predecessors.
+  BitVector temp(definition_count);
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    predecessors_[i]->ComputeRDOut(&temp);
+    new_rd_in.Union(temp);
+  }
+
+  if (rd_.rd_in()->Equals(new_rd_in)) return;
+
+  // Update RD_in.
+  rd_.rd_in()->CopyFrom(new_rd_in);
+  // Add the successor to the worklist if not already present.
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    worklist->Insert(successor_);
+  }
 }


@@ -1940,7 +2061,7 @@

   int variable_count = variables_.length();
   int definition_count = definitions_->length();
-  int block_count = postorder_->length();
+  int node_count = postorder_->length();

   // Step 1: For each variable, identify the set of all its definitions in
   // the body.
@@ -1972,10 +2093,25 @@
     }
   }

-  // Step 2: Compute KILL and GEN for each block node, initialize RD.
-  for (int i = block_count - 1; i >= 0; i--) {
+  // Step 2: Compute KILL and GEN for each block node, initialize RD_in for
+  // all nodes, and mark and add all nodes to the worklist in reverse
+  // postorder.  All nodes should currently have the same mark.
+ bool mark = postorder_->at(0)->IsMarkedWith(false); // Negation of current.
+  WorkList<Node> worklist(node_count);
+  for (int i = node_count - 1; i >= 0; i--) {
     postorder_->at(i)->InitializeReachingDefinitions(definition_count,
-                                                     &variables_);
+                                                     &variables_,
+                                                     &worklist,
+                                                     mark);
+  }
+
+  // Step 3: Until the worklist is empty, remove an item compute and update
+ // its rd_in based on its predecessor's rd_out. If rd_in has changed, add
+  // all necessary successors to the worklist.
+  while (!worklist.is_empty()) {
+    Node* node = worklist.Remove();
+    node->MarkWith(!mark);
+    node->UpdateRDIn(&worklist, mark);
   }
 }

=======================================
--- /branches/bleeding_edge/src/data-flow.h     Thu Mar 11 08:24:05 2010
+++ /branches/bleeding_edge/src/data-flow.h     Fri Mar 12 02:35:45 2010
@@ -119,6 +119,13 @@
     }
     return true;
   }
+
+  bool Equals(const BitVector& other) {
+    for (int i = 0; i < data_length_; i++) {
+      if (data_[i] != other.data_[i]) return false;
+    }
+    return true;
+  }

   int length() const { return length_; }

@@ -129,7 +136,51 @@
 };


-class ReachingDefinitionsData BASE_EMBEDDED {
+// Simple fixed-capacity list-based worklist (managed as a queue) of
+// pointers to T.
+template<typename T>
+class WorkList BASE_EMBEDDED {
+ public:
+  // The worklist cannot grow bigger than size.  We keep one item empty to
+  // distinguish between empty and full.
+  WorkList(int size)
+      : capacity_(size + 1), head_(0), tail_(0), queue_(capacity_) {
+    for (int i = 0; i < capacity_; i++) queue_.Add(NULL);
+  }
+
+  bool is_empty() { return head_ == tail_; }
+
+  bool is_full() {
+    // The worklist is full if head is at 0 and tail is at capacity - 1:
+    //   head == 0 && tail == capacity-1 ==> tail - head == capacity - 1
+    // or if tail is immediately to the left of head:
+    //   tail+1 == head  ==> tail - head == -1
+    int diff = tail_ - head_;
+    return (diff == -1 || diff == capacity_ - 1);
+  }
+
+  void Insert(T* item) {
+    ASSERT(!is_full());
+    queue_[tail_++] = item;
+    if (tail_ == capacity_) tail_ = 0;
+  }
+
+  T* Remove() {
+    ASSERT(!is_empty());
+    T* item = queue_[head_++];
+    if (head_ == capacity_) head_ = 0;
+    return item;
+  }
+
+ private:
+  int capacity_;  // Including one empty slot.
+  int head_;      // Where the first item is.
+  int tail_;      // Where the next inserted item will go.
+  List<T*> queue_;
+};
+
+
+struct ReachingDefinitionsData BASE_EMBEDDED {
  public:
   ReachingDefinitionsData() : rd_in_(NULL), kill_(NULL), gen_(NULL) {}

@@ -179,7 +230,11 @@

   // Functions used by data-flow analyses.
   virtual void InitializeReachingDefinitions(int definition_count,
-                                             List<BitVector*>* variables);
+                                             List<BitVector*>* variables,
+                                             WorkList<Node>* worklist,
+                                             bool mark);
+  virtual void ComputeRDOut(BitVector* result) = 0;
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;

 #ifdef DEBUG
   void AssignNodeNumber();
@@ -216,6 +271,9 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);

+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif
@@ -261,7 +319,11 @@
                 ZoneList<Node*>* postorder);

   void InitializeReachingDefinitions(int definition_count,
-                                     List<BitVector*>* variables);
+                                     List<BitVector*>* variables,
+                                     WorkList<Node>* worklist,
+                                     bool mark);
+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);

 #ifdef DEBUG
   void PrintText();
@@ -301,6 +363,9 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);

+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif
@@ -340,6 +405,9 @@
                 ZoneList<Node*>* preorder,
                 ZoneList<Node*>* postorder);

+  void ComputeRDOut(BitVector* result);
+  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+
 #ifdef DEBUG
   void PrintText();
 #endif

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

Reply via email to