普通文本  |  717行  |  22.78 KB

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "compiler_internals.h"
#include "dataflow_iterator-inl.h"

#define NOTVISITED (-1)

namespace art {

void MIRGraph::ClearAllVisitedFlags() {
  AllNodesIterator iter(this, false /* not iterative */);
  for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
    bb->visited = false;
  }
}

BasicBlock* MIRGraph::NeedsVisit(BasicBlock* bb) {
  if (bb != NULL) {
    if (bb->visited || bb->hidden) {
      bb = NULL;
    }
  }
  return bb;
}

BasicBlock* MIRGraph::NextUnvisitedSuccessor(BasicBlock* bb) {
  BasicBlock* res = NeedsVisit(bb->fall_through);
  if (res == NULL) {
    res = NeedsVisit(bb->taken);
    if (res == NULL) {
      if (bb->successor_block_list.block_list_type != kNotUsed) {
        GrowableArray<SuccessorBlockInfo*>::Iterator iterator(bb->successor_block_list.blocks);
        while (true) {
          SuccessorBlockInfo *sbi = iterator.Next();
          if (sbi == NULL) {
            break;
          }
          res = NeedsVisit(sbi->block);
          if (res != NULL) {
            break;
          }
        }
      }
    }
  }
  return res;
}

void MIRGraph::MarkPreOrder(BasicBlock* block) {
  block->visited = true;
  /* Enqueue the pre_order block id */
  dfs_order_->Insert(block->id);
}

void MIRGraph::RecordDFSOrders(BasicBlock* block) {
  std::vector<BasicBlock*> succ;
  MarkPreOrder(block);
  succ.push_back(block);
  while (!succ.empty()) {
    BasicBlock* curr = succ.back();
    BasicBlock* next_successor = NextUnvisitedSuccessor(curr);
    if (next_successor != NULL) {
      MarkPreOrder(next_successor);
      succ.push_back(next_successor);
      continue;
    }
    curr->dfs_id = dfs_post_order_->Size();
    dfs_post_order_->Insert(curr->id);
    succ.pop_back();
  }
}

/* Sort the blocks by the Depth-First-Search */
void MIRGraph::ComputeDFSOrders() {
  /* Initialize or reset the DFS pre_order list */
  if (dfs_order_ == NULL) {
    dfs_order_ = new (arena_) GrowableArray<int>(arena_, GetNumBlocks(), kGrowableArrayDfsOrder);
  } else {
    /* Just reset the used length on the counter */
    dfs_order_->Reset();
  }

  /* Initialize or reset the DFS post_order list */
  if (dfs_post_order_ == NULL) {
    dfs_post_order_ = new (arena_) GrowableArray<int>(arena_, GetNumBlocks(), kGrowableArrayDfsPostOrder);
  } else {
    /* Just reset the used length on the counter */
    dfs_post_order_->Reset();
  }

  // Reset visited flags from all nodes
  ClearAllVisitedFlags();

  // Record dfs orders
  RecordDFSOrders(GetEntryBlock());

  num_reachable_blocks_ = dfs_order_->Size();
}

/*
 * Mark block bit on the per-Dalvik register vector to denote that Dalvik
 * register idx is defined in BasicBlock bb.
 */
bool MIRGraph::FillDefBlockMatrix(BasicBlock* bb) {
  if (bb->data_flow_info == NULL) {
    return false;
  }

  ArenaBitVector::Iterator iterator(bb->data_flow_info->def_v);
  while (true) {
    int idx = iterator.Next();
    if (idx == -1) {
      break;
    }
    /* Block bb defines register idx */
    def_block_matrix_[idx]->SetBit(bb->id);
  }
  return true;
}

void MIRGraph::ComputeDefBlockMatrix() {
  int num_registers = cu_->num_dalvik_registers;
  /* Allocate num_dalvik_registers bit vector pointers */
  def_block_matrix_ = static_cast<ArenaBitVector**>
      (arena_->Alloc(sizeof(ArenaBitVector *) * num_registers,
                     ArenaAllocator::kAllocDFInfo));
  int i;

  /* Initialize num_register vectors with num_blocks bits each */
  for (i = 0; i < num_registers; i++) {
    def_block_matrix_[i] =
        new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapBMatrix);
  }
  AllNodesIterator iter(this, false /* not iterative */);
  for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
    FindLocalLiveIn(bb);
  }
  AllNodesIterator iter2(this, false /* not iterative */);
  for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) {
    FillDefBlockMatrix(bb);
  }

  /*
   * Also set the incoming parameters as defs in the entry block.
   * Only need to handle the parameters for the outer method.
   */
  int num_regs = cu_->num_dalvik_registers;
  int in_reg = num_regs - cu_->num_ins;
  for (; in_reg < num_regs; in_reg++) {
    def_block_matrix_[in_reg]->SetBit(GetEntryBlock()->id);
  }
}

void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) {
  if (dom_post_order_traversal_ == NULL) {
    // First time - create the array.
    dom_post_order_traversal_ =
        new (arena_) GrowableArray<int>(arena_, num_reachable_blocks_,
                                        kGrowableArrayDomPostOrderTraversal);
  } else {
    dom_post_order_traversal_->Reset();
  }
  ClearAllVisitedFlags();
  std::vector<std::pair<BasicBlock*, ArenaBitVector::Iterator*> > work_stack;
  bb->visited = true;
  work_stack.push_back(std::make_pair(bb, new (arena_) ArenaBitVector::Iterator(bb->i_dominated)));
  while (!work_stack.empty()) {
    std::pair<BasicBlock*, ArenaBitVector::Iterator*> curr = work_stack.back();
    BasicBlock* curr_bb = curr.first;
    ArenaBitVector::Iterator* curr_idom_iter = curr.second;
    int bb_idx = curr_idom_iter->Next();
    while ((bb_idx != -1) && (NeedsVisit(GetBasicBlock(bb_idx)) == NULL)) {
      bb_idx = curr_idom_iter->Next();
    }
    if (bb_idx != -1) {
      BasicBlock* new_bb = GetBasicBlock(bb_idx);
      new_bb->visited = true;
      work_stack.push_back(
          std::make_pair(new_bb, new (arena_) ArenaBitVector::Iterator(new_bb->i_dominated)));
    } else {
      // no successor/next
      dom_post_order_traversal_->Insert(curr_bb->id);
      work_stack.pop_back();

      /* hacky loop detection */
      if (curr_bb->taken && curr_bb->dominators->IsBitSet(curr_bb->taken->id)) {
        attributes_ |= METHOD_HAS_LOOP;
      }
    }
  }
}

void MIRGraph::CheckForDominanceFrontier(BasicBlock* dom_bb,
                                         const BasicBlock* succ_bb) {
  /*
   * TODO - evaluate whether phi will ever need to be inserted into exit
   * blocks.
   */
  if (succ_bb->i_dom != dom_bb &&
    succ_bb->block_type == kDalvikByteCode &&
    succ_bb->hidden == false) {
    dom_bb->dom_frontier->SetBit(succ_bb->id);
  }
}

/* Worker function to compute the dominance frontier */
bool MIRGraph::ComputeDominanceFrontier(BasicBlock* bb) {
  /* Calculate DF_local */
  if (bb->taken) {
    CheckForDominanceFrontier(bb, bb->taken);
  }
  if (bb->fall_through) {
    CheckForDominanceFrontier(bb, bb->fall_through);
  }
  if (bb->successor_block_list.block_list_type != kNotUsed) {
    GrowableArray<SuccessorBlockInfo*>::Iterator iterator(bb->successor_block_list.blocks);
      while (true) {
        SuccessorBlockInfo *successor_block_info = iterator.Next();
        if (successor_block_info == NULL) {
          break;
        }
        BasicBlock* succ_bb = successor_block_info->block;
        CheckForDominanceFrontier(bb, succ_bb);
      }
  }

  /* Calculate DF_up */
  ArenaBitVector::Iterator bv_iterator(bb->i_dominated);
  while (true) {
    // TUNING: hot call to BitVectorIteratorNext
    int dominated_idx = bv_iterator.Next();
    if (dominated_idx == -1) {
      break;
    }
    BasicBlock* dominated_bb = GetBasicBlock(dominated_idx);
    ArenaBitVector::Iterator df_iterator(dominated_bb->dom_frontier);
    while (true) {
      // TUNING: hot call to BitVectorIteratorNext
      int df_up_idx = df_iterator.Next();
      if (df_up_idx == -1) {
        break;
      }
      BasicBlock* df_up_block = GetBasicBlock(df_up_idx);
      CheckForDominanceFrontier(bb, df_up_block);
    }
  }

  return true;
}

/* Worker function for initializing domination-related data structures */
void MIRGraph::InitializeDominationInfo(BasicBlock* bb) {
  int num_total_blocks = GetBasicBlockListCount();

  if (bb->dominators == NULL) {
    bb->dominators = new (arena_) ArenaBitVector(arena_, num_total_blocks,
                                                 false /* expandable */, kBitMapDominators);
    bb->i_dominated = new (arena_) ArenaBitVector(arena_, num_total_blocks,
                                                  false /* expandable */, kBitMapIDominated);
    bb->dom_frontier = new (arena_) ArenaBitVector(arena_, num_total_blocks,
                                                   false /* expandable */, kBitMapDomFrontier);
  } else {
    bb->dominators->ClearAllBits();
    bb->i_dominated->ClearAllBits();
    bb->dom_frontier->ClearAllBits();
  }
  /* Set all bits in the dominator vector */
  bb->dominators->SetInitialBits(num_total_blocks);

  return;
}

/*
 * Walk through the ordered i_dom list until we reach common parent.
 * Given the ordering of i_dom_list, this common parent represents the
 * last element of the intersection of block1 and block2 dominators.
  */
int MIRGraph::FindCommonParent(int block1, int block2) {
  while (block1 != block2) {
    while (block1 < block2) {
      block1 = i_dom_list_[block1];
      DCHECK_NE(block1, NOTVISITED);
    }
    while (block2 < block1) {
      block2 = i_dom_list_[block2];
      DCHECK_NE(block2, NOTVISITED);
    }
  }
  return block1;
}

/* Worker function to compute each block's immediate dominator */
bool MIRGraph::ComputeblockIDom(BasicBlock* bb) {
  /* Special-case entry block */
  if (bb == GetEntryBlock()) {
    return false;
  }

  /* Iterate through the predecessors */
  GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);

  /* Find the first processed predecessor */
  int idom = -1;
  while (true) {
    BasicBlock* pred_bb = iter.Next();
    CHECK(pred_bb != NULL);
    if (i_dom_list_[pred_bb->dfs_id] != NOTVISITED) {
      idom = pred_bb->dfs_id;
      break;
    }
  }

  /* Scan the rest of the predecessors */
  while (true) {
      BasicBlock* pred_bb = iter.Next();
      if (!pred_bb) {
        break;
      }
      if (i_dom_list_[pred_bb->dfs_id] == NOTVISITED) {
        continue;
      } else {
        idom = FindCommonParent(pred_bb->dfs_id, idom);
      }
  }

  DCHECK_NE(idom, NOTVISITED);

  /* Did something change? */
  if (i_dom_list_[bb->dfs_id] != idom) {
    i_dom_list_[bb->dfs_id] = idom;
    return true;
  }
  return false;
}

/* Worker function to compute each block's domintors */
bool MIRGraph::ComputeBlockDominators(BasicBlock* bb) {
  if (bb == GetEntryBlock()) {
    bb->dominators->ClearAllBits();
  } else {
    bb->dominators->Copy(bb->i_dom->dominators);
  }
  bb->dominators->SetBit(bb->id);
  return false;
}

bool MIRGraph::SetDominators(BasicBlock* bb) {
  if (bb != GetEntryBlock()) {
    int idom_dfs_idx = i_dom_list_[bb->dfs_id];
    DCHECK_NE(idom_dfs_idx, NOTVISITED);
    int i_dom_idx = dfs_post_order_->Get(idom_dfs_idx);
    BasicBlock* i_dom = GetBasicBlock(i_dom_idx);
    bb->i_dom = i_dom;
    /* Add bb to the i_dominated set of the immediate dominator block */
    i_dom->i_dominated->SetBit(bb->id);
  }
  return false;
}

/* Compute dominators, immediate dominator, and dominance fronter */
void MIRGraph::ComputeDominators() {
  int num_reachable_blocks = num_reachable_blocks_;
  int num_total_blocks = GetBasicBlockListCount();

  /* Initialize domination-related data structures */
  ReachableNodesIterator iter(this, false /* not iterative */);
  for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
    InitializeDominationInfo(bb);
  }

  /* Initalize & Clear i_dom_list */
  if (i_dom_list_ == NULL) {
    i_dom_list_ = static_cast<int*>(arena_->Alloc(sizeof(int) * num_reachable_blocks,
                                                  ArenaAllocator::kAllocDFInfo));
  }
  for (int i = 0; i < num_reachable_blocks; i++) {
    i_dom_list_[i] = NOTVISITED;
  }

  /* For post-order, last block is entry block.  Set its i_dom to istelf */
  DCHECK_EQ(GetEntryBlock()->dfs_id, num_reachable_blocks-1);
  i_dom_list_[GetEntryBlock()->dfs_id] = GetEntryBlock()->dfs_id;

  /* Compute the immediate dominators */
  ReversePostOrderDfsIterator iter2(this, true /* iterative */);
  bool change = false;
  for (BasicBlock* bb = iter2.Next(false); bb != NULL; bb = iter2.Next(change)) {
    change = ComputeblockIDom(bb);
  }

  /* Set the dominator for the root node */
  GetEntryBlock()->dominators->ClearAllBits();
  GetEntryBlock()->dominators->SetBit(GetEntryBlock()->id);

  if (temp_block_v_ == NULL) {
    temp_block_v_ = new (arena_) ArenaBitVector(arena_, num_total_blocks,
                                                false /* expandable */, kBitMapTmpBlockV);
  } else {
    temp_block_v_->ClearAllBits();
  }
  GetEntryBlock()->i_dom = NULL;

  ReachableNodesIterator iter3(this, false /* not iterative */);
  for (BasicBlock* bb = iter3.Next(); bb != NULL; bb = iter3.Next()) {
    SetDominators(bb);
  }

  ReversePostOrderDfsIterator iter4(this, false /* not iterative */);
  for (BasicBlock* bb = iter4.Next(); bb != NULL; bb = iter4.Next()) {
    ComputeBlockDominators(bb);
  }

  // Compute the dominance frontier for each block.
  ComputeDomPostOrderTraversal(GetEntryBlock());
  PostOrderDOMIterator iter5(this, false /* not iterative */);
  for (BasicBlock* bb = iter5.Next(); bb != NULL; bb = iter5.Next()) {
    ComputeDominanceFrontier(bb);
  }
}

/*
 * Perform dest U= src1 ^ ~src2
 * This is probably not general enough to be placed in BitVector.[ch].
 */
void MIRGraph::ComputeSuccLineIn(ArenaBitVector* dest, const ArenaBitVector* src1,
                                 const ArenaBitVector* src2) {
  if (dest->GetStorageSize() != src1->GetStorageSize() ||
      dest->GetStorageSize() != src2->GetStorageSize() ||
      dest->IsExpandable() != src1->IsExpandable() ||
      dest->IsExpandable() != src2->IsExpandable()) {
    LOG(FATAL) << "Incompatible set properties";
  }

  unsigned int idx;
  for (idx = 0; idx < dest->GetStorageSize(); idx++) {
    dest->GetRawStorage()[idx] |= src1->GetRawStorageWord(idx) & ~(src2->GetRawStorageWord(idx));
  }
}

/*
 * Iterate through all successor blocks and propagate up the live-in sets.
 * The calculated result is used for phi-node pruning - where we only need to
 * insert a phi node if the variable is live-in to the block.
 */
bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) {
  ArenaBitVector* temp_dalvik_register_v = temp_dalvik_register_v_;

  if (bb->data_flow_info == NULL) {
    return false;
  }
  temp_dalvik_register_v->Copy(bb->data_flow_info->live_in_v);
  if (bb->taken && bb->taken->data_flow_info)
    ComputeSuccLineIn(temp_dalvik_register_v, bb->taken->data_flow_info->live_in_v,
                      bb->data_flow_info->def_v);
  if (bb->fall_through && bb->fall_through->data_flow_info)
    ComputeSuccLineIn(temp_dalvik_register_v, bb->fall_through->data_flow_info->live_in_v,
                      bb->data_flow_info->def_v);
  if (bb->successor_block_list.block_list_type != kNotUsed) {
    GrowableArray<SuccessorBlockInfo*>::Iterator iterator(bb->successor_block_list.blocks);
    while (true) {
      SuccessorBlockInfo *successor_block_info = iterator.Next();
      if (successor_block_info == NULL) {
        break;
      }
      BasicBlock* succ_bb = successor_block_info->block;
      if (succ_bb->data_flow_info) {
        ComputeSuccLineIn(temp_dalvik_register_v, succ_bb->data_flow_info->live_in_v,
                          bb->data_flow_info->def_v);
      }
    }
  }
  if (!temp_dalvik_register_v->Equal(bb->data_flow_info->live_in_v)) {
    bb->data_flow_info->live_in_v->Copy(temp_dalvik_register_v);
    return true;
  }
  return false;
}

/* Insert phi nodes to for each variable to the dominance frontiers */
void MIRGraph::InsertPhiNodes() {
  int dalvik_reg;
  ArenaBitVector* phi_blocks =
      new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapPhi);
  ArenaBitVector* tmp_blocks =
      new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapTmpBlocks);
  ArenaBitVector* input_blocks =
      new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapInputBlocks);

  temp_dalvik_register_v_ =
      new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapRegisterV);

  PostOrderDfsIterator iter(this, true /* iterative */);
  bool change = false;
  for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) {
    change = ComputeBlockLiveIns(bb);
  }

  /* Iterate through each Dalvik register */
  for (dalvik_reg = cu_->num_dalvik_registers - 1; dalvik_reg >= 0; dalvik_reg--) {
    bool change;

    input_blocks->Copy(def_block_matrix_[dalvik_reg]);
    phi_blocks->ClearAllBits();

    /* Calculate the phi blocks for each Dalvik register */
    do {
      change = false;
      tmp_blocks->ClearAllBits();
      ArenaBitVector::Iterator iterator(input_blocks);

      while (true) {
        int idx = iterator.Next();
        if (idx == -1) {
          break;
        }
        BasicBlock* def_bb = GetBasicBlock(idx);

        /* Merge the dominance frontier to tmp_blocks */
        // TUNING: hot call to Union().
        if (def_bb->dom_frontier != NULL) {
          tmp_blocks->Union(def_bb->dom_frontier);
        }
      }
      if (!phi_blocks->Equal(tmp_blocks)) {
        change = true;
        phi_blocks->Copy(tmp_blocks);

        /*
         * Iterate through the original blocks plus the new ones in
         * the dominance frontier.
         */
        input_blocks->Copy(phi_blocks);
        input_blocks->Union(def_block_matrix_[dalvik_reg]);
      }
    } while (change);

    /*
     * Insert a phi node for dalvik_reg in the phi_blocks if the Dalvik
     * register is in the live-in set.
     */
    ArenaBitVector::Iterator iterator(phi_blocks);
    while (true) {
      int idx = iterator.Next();
      if (idx == -1) {
        break;
      }
      BasicBlock* phi_bb = GetBasicBlock(idx);
      /* Variable will be clobbered before being used - no need for phi */
      if (!phi_bb->data_flow_info->live_in_v->IsBitSet(dalvik_reg)) {
        continue;
      }
      MIR *phi =
          static_cast<MIR*>(arena_->Alloc(sizeof(MIR), ArenaAllocator::kAllocDFInfo));
      phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpPhi);
      phi->dalvikInsn.vA = dalvik_reg;
      phi->offset = phi_bb->start_offset;
      phi->m_unit_index = 0;  // Arbitrarily assign all Phi nodes to outermost method.
      PrependMIR(phi_bb, phi);
    }
  }
}

/*
 * Worker function to insert phi-operands with latest SSA names from
 * predecessor blocks
 */
bool MIRGraph::InsertPhiNodeOperands(BasicBlock* bb) {
  MIR *mir;
  std::vector<int> uses;
  std::vector<int> incoming_arc;

  /* Phi nodes are at the beginning of each block */
  for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
    if (mir->dalvikInsn.opcode != static_cast<Instruction::Code>(kMirOpPhi))
      return true;
    int ssa_reg = mir->ssa_rep->defs[0];
    DCHECK_GE(ssa_reg, 0);   // Shouldn't see compiler temps here
    int v_reg = SRegToVReg(ssa_reg);

    uses.clear();
    incoming_arc.clear();

    /* Iterate through the predecessors */
    GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);
    while (true) {
      BasicBlock* pred_bb = iter.Next();
      if (!pred_bb) {
        break;
      }
      int ssa_reg = pred_bb->data_flow_info->vreg_to_ssa_map[v_reg];
      uses.push_back(ssa_reg);
      incoming_arc.push_back(pred_bb->id);
    }

    /* Count the number of SSA registers for a Dalvik register */
    int num_uses = uses.size();
    mir->ssa_rep->num_uses = num_uses;
    mir->ssa_rep->uses =
        static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo));
    mir->ssa_rep->fp_use =
        static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_uses, ArenaAllocator::kAllocDFInfo));
    int* incoming =
        static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo));
    // TODO: Ugly, rework (but don't burden each MIR/LIR for Phi-only needs)
    mir->dalvikInsn.vB = reinterpret_cast<uintptr_t>(incoming);

    /* Set the uses array for the phi node */
    int *use_ptr = mir->ssa_rep->uses;
    for (int i = 0; i < num_uses; i++) {
      *use_ptr++ = uses[i];
      *incoming++ = incoming_arc[i];
    }
  }

  return true;
}

void MIRGraph::DoDFSPreOrderSSARename(BasicBlock* block) {
  if (block->visited || block->hidden) {
    return;
  }
  block->visited = true;

  /* Process this block */
  DoSSAConversion(block);
  int map_size = sizeof(int) * cu_->num_dalvik_registers;

  /* Save SSA map snapshot */
  int* saved_ssa_map =
      static_cast<int*>(arena_->Alloc(map_size, ArenaAllocator::kAllocDalvikToSSAMap));
  memcpy(saved_ssa_map, vreg_to_ssa_map_, map_size);

  if (block->fall_through) {
    DoDFSPreOrderSSARename(block->fall_through);
    /* Restore SSA map snapshot */
    memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size);
  }
  if (block->taken) {
    DoDFSPreOrderSSARename(block->taken);
    /* Restore SSA map snapshot */
    memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size);
  }
  if (block->successor_block_list.block_list_type != kNotUsed) {
    GrowableArray<SuccessorBlockInfo*>::Iterator iterator(block->successor_block_list.blocks);
    while (true) {
      SuccessorBlockInfo *successor_block_info = iterator.Next();
      if (successor_block_info == NULL) {
        break;
      }
      BasicBlock* succ_bb = successor_block_info->block;
      DoDFSPreOrderSSARename(succ_bb);
      /* Restore SSA map snapshot */
      memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size);
    }
  }
  vreg_to_ssa_map_ = saved_ssa_map;
  return;
}

/* Perform SSA transformation for the whole method */
void MIRGraph::SSATransformation() {
  /* Compute the DFS order */
  ComputeDFSOrders();

  /* Compute the dominator info */
  ComputeDominators();

  /* Allocate data structures in preparation for SSA conversion */
  CompilerInitializeSSAConversion();

  /* Find out the "Dalvik reg def x block" relation */
  ComputeDefBlockMatrix();

  /* Insert phi nodes to dominance frontiers for all variables */
  InsertPhiNodes();

  /* Rename register names by local defs and phi nodes */
  ClearAllVisitedFlags();
  DoDFSPreOrderSSARename(GetEntryBlock());

  /*
   * Shared temp bit vector used by each block to count the number of defs
   * from all the predecessor blocks.
   */
  temp_ssa_register_v_ =
      new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false, kBitMapTempSSARegisterV);

  /* Insert phi-operands with latest SSA names from predecessor blocks */
  ReachableNodesIterator iter2(this, false /* not iterative */);
  for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) {
    InsertPhiNodeOperands(bb);
  }

  if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
    DumpCFG("/sdcard/3_post_ssa_cfg/", false);
  }
  if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) {
    VerifyDataflow();
  }
}

}  // namespace art