| /* |
| * 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_->NewMem(sizeof(ArenaBitVector *) * num_registers, true, |
| 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_->NewMem(sizeof(int) * num_reachable_blocks, false, |
| 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_->NewMem(sizeof(MIR), true, 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_->NewMem(sizeof(int) * num_uses, false, |
| ArenaAllocator::kAllocDFInfo)); |
| mir->ssa_rep->fp_use = |
| static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_uses, true, |
| ArenaAllocator::kAllocDFInfo)); |
| int* incoming = |
| static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, false, |
| 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_->NewMem(map_size, false, 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 |