/* * 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.h" namespace art { // Make sure iterative dfs recording matches old recursive version //#define TEST_DFS static BasicBlock* NeedsVisit(BasicBlock* bb) { if (bb != NULL) { if (bb->visited || bb->hidden) { bb = NULL; } } return bb; } static BasicBlock* 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) { GrowableListIterator iterator; GrowableListIteratorInit(&bb->successor_block_list.blocks, &iterator); while (true) { SuccessorBlockInfo *sbi = reinterpret_cast (GrowableListIteratorNext(&iterator)); if (sbi == NULL) break; res = NeedsVisit(sbi->block); if (res != NULL) break; } } } } return res; } static void MarkPreOrder(CompilationUnit* cu, BasicBlock* block) { block->visited = true; /* Enqueue the pre_order block id */ InsertGrowableList(cu, &cu->dfs_order, block->id); } static void RecordDFSOrders(CompilationUnit* cu, BasicBlock* block) { std::vector succ; MarkPreOrder(cu, block); succ.push_back(block); while (!succ.empty()) { BasicBlock* curr = succ.back(); BasicBlock* next_successor = NextUnvisitedSuccessor(curr); if (next_successor != NULL) { MarkPreOrder(cu, next_successor); succ.push_back(next_successor); continue; } curr->dfs_id = cu->dfs_post_order.num_used; InsertGrowableList(cu, &cu->dfs_post_order, curr->id); succ.pop_back(); } } #if defined(TEST_DFS) /* Enter the node to the dfs_order list then visit its successors */ static void RecursiveRecordDFSOrders(CompilationUnit* cu, BasicBlock* block) { if (block->visited || block->hidden) return; block->visited = true; // Can this block be reached only via previous block fallthrough? if ((block->block_type == kDalvikByteCode) && (block->predecessors->num_used == 1)) { DCHECK_GE(cu->dfs_order.num_used, 1U); int prev_idx = cu->dfs_order.num_used - 1; int prev_id = cu->dfs_order.elem_list[prev_idx]; BasicBlock* pred_bb = (BasicBlock*)block->predecessors->elem_list[0]; } /* Enqueue the pre_order block id */ InsertGrowableList(cu, &cu->dfs_order, block->id); if (block->fall_through) { RecursiveRecordDFSOrders(cu, block->fall_through); } if (block->taken) RecursiveRecordDFSOrders(cu, block->taken); if (block->successor_block_list.block_list_type != kNotUsed) { GrowableListIterator iterator; GrowableListIteratorInit(&block->successor_block_list.blocks, &iterator); while (true) { SuccessorBlockInfo *successor_block_info = (SuccessorBlockInfo *) GrowableListIteratorNext(&iterator); if (successor_block_info == NULL) break; BasicBlock* succ_bb = successor_block_info->block; RecursiveRecordDFSOrders(cu, succ_bb); } } /* Record postorder in basic block and enqueue normal id in dfs_post_order */ block->dfs_id = cu->dfs_post_order.num_used; InsertGrowableList(cu, &cu->dfs_post_order, block->id); return; } #endif /* Sort the blocks by the Depth-First-Search */ static void ComputeDFSOrders(CompilationUnit* cu) { /* Initialize or reset the DFS pre_order list */ if (cu->dfs_order.elem_list == NULL) { CompilerInitGrowableList(cu, &cu->dfs_order, cu->num_blocks, kListDfsOrder); } else { /* Just reset the used length on the counter */ cu->dfs_order.num_used = 0; } /* Initialize or reset the DFS post_order list */ if (cu->dfs_post_order.elem_list == NULL) { CompilerInitGrowableList(cu, &cu->dfs_post_order, cu->num_blocks, kListDfsPostOrder); } else { /* Just reset the used length on the counter */ cu->dfs_post_order.num_used = 0; } #if defined(TEST_DFS) // Reset visited flags DataFlowAnalysisDispatcher(cu, ClearVisitedFlag, kAllNodes, false /* is_iterative */); // Record pre and post order dfs RecursiveRecordDFSOrders(cu, cu->entry_block); // Copy the results for later comparison and reset the lists GrowableList recursive_dfs_order; GrowableList recursive_dfs_post_order; CompilerInitGrowableList(cu, &recursive_dfs_order, cu->dfs_order.num_used, kListDfsOrder); for (unsigned int i = 0; i < cu->dfs_order.num_used; i++) { InsertGrowableList(cu, &recursive_dfs_order, cu->dfs_order.elem_list[i]); } cu->dfs_order.num_used = 0; CompilerInitGrowableList(cu, &recursive_dfs_post_order, cu->dfs_post_order.num_used, kListDfsOrder); for (unsigned int i = 0; i < cu->dfs_post_order.num_used; i++) { InsertGrowableList(cu, &recursive_dfs_post_order, cu->dfs_post_order.elem_list[i]); } cu->dfs_post_order.num_used = 0; #endif // Reset visited flags from all nodes DataFlowAnalysisDispatcher(cu, ClearVisitedFlag, kAllNodes, false /* is_iterative */); // Record dfs orders RecordDFSOrders(cu, cu->entry_block); #if defined(TEST_DFS) bool mismatch = false; mismatch |= (cu->dfs_order.num_used != recursive_dfs_order.num_used); for (unsigned int i = 0; i < cu->dfs_order.num_used; i++) { mismatch |= (cu->dfs_order.elem_list[i] != recursive_dfs_order.elem_list[i]); } mismatch |= (cu->dfs_post_order.num_used != recursive_dfs_post_order.num_used); for (unsigned int i = 0; i < cu->dfs_post_order.num_used; i++) { mismatch |= (cu->dfs_post_order.elem_list[i] != recursive_dfs_post_order.elem_list[i]); } if (mismatch) { LOG(INFO) << "Mismatch for " << PrettyMethod(cu->method_idx, *cu->dex_file); LOG(INFO) << "New dfs"; for (unsigned int i = 0; i < cu->dfs_order.num_used; i++) { LOG(INFO) << i << " - " << cu->dfs_order.elem_list[i]; } LOG(INFO) << "Recursive dfs"; for (unsigned int i = 0; i < recursive_dfs_order.num_used; i++) { LOG(INFO) << i << " - " << recursive_dfs_order.elem_list[i]; } LOG(INFO) << "New post dfs"; for (unsigned int i = 0; i < cu->dfs_post_order.num_used; i++) { LOG(INFO) << i << " - " << cu->dfs_post_order.elem_list[i]; } LOG(INFO) << "Recursive post dfs"; for (unsigned int i = 0; i < recursive_dfs_post_order.num_used; i++) { LOG(INFO) << i << " - " << recursive_dfs_post_order.elem_list[i]; } } CHECK_EQ(cu->dfs_order.num_used, recursive_dfs_order.num_used); for (unsigned int i = 0; i < cu->dfs_order.num_used; i++) { CHECK_EQ(cu->dfs_order.elem_list[i], recursive_dfs_order.elem_list[i]); } CHECK_EQ(cu->dfs_post_order.num_used, recursive_dfs_post_order.num_used); for (unsigned int i = 0; i < cu->dfs_post_order.num_used; i++) { CHECK_EQ(cu->dfs_post_order.elem_list[i], recursive_dfs_post_order.elem_list[i]); } #endif cu->num_reachable_blocks = cu->dfs_order.num_used; } /* * Mark block bit on the per-Dalvik register vector to denote that Dalvik * register idx is defined in BasicBlock bb. */ static bool FillDefBlockMatrix(CompilationUnit* cu, BasicBlock* bb) { if (bb->data_flow_info == NULL) return false; ArenaBitVectorIterator iterator; BitVectorIteratorInit(bb->data_flow_info->def_v, &iterator); while (true) { int idx = BitVectorIteratorNext(&iterator); if (idx == -1) break; /* Block bb defines register idx */ SetBit(cu, cu->def_block_matrix[idx], bb->id); } return true; } static void ComputeDefBlockMatrix(CompilationUnit* cu) { int num_registers = cu->num_dalvik_registers; /* Allocate num_dalvik_registers bit vector pointers */ cu->def_block_matrix = static_cast (NewMem(cu, sizeof(ArenaBitVector *) * num_registers, true, kAllocDFInfo)); int i; /* Initialize num_register vectors with num_blocks bits each */ for (i = 0; i < num_registers; i++) { cu->def_block_matrix[i] = AllocBitVector(cu, cu->num_blocks, false, kBitMapBMatrix); } DataFlowAnalysisDispatcher(cu, FindLocalLiveIn, kAllNodes, false /* is_iterative */); DataFlowAnalysisDispatcher(cu, FillDefBlockMatrix, kAllNodes, false /* is_iterative */); /* * 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++) { SetBit(cu, cu->def_block_matrix[in_reg], cu->entry_block->id); } } /* Compute the post-order traversal of the CFG */ static void ComputeDomPostOrderTraversal(CompilationUnit* cu, BasicBlock* bb) { ArenaBitVectorIterator bv_iterator; BitVectorIteratorInit(bb->i_dominated, &bv_iterator); GrowableList* block_list = &cu->block_list; /* Iterate through the dominated blocks first */ while (true) { //TUNING: hot call to BitVectorIteratorNext int bb_idx = BitVectorIteratorNext(&bv_iterator); if (bb_idx == -1) break; BasicBlock* dominated_bb = reinterpret_cast(GrowableListGetElement(block_list, bb_idx)); ComputeDomPostOrderTraversal(cu, dominated_bb); } /* Enter the current block id */ InsertGrowableList(cu, &cu->dom_post_order_traversal, bb->id); /* hacky loop detection */ if (bb->taken && IsBitSet(bb->dominators, bb->taken->id)) { cu->has_loop = true; } } static void CheckForDominanceFrontier(CompilationUnit* cu, 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) { SetBit(cu, dom_bb->dom_frontier, succ_bb->id); } } /* Worker function to compute the dominance frontier */ static bool ComputeDominanceFrontier(CompilationUnit* cu, BasicBlock* bb) { GrowableList* block_list = &cu->block_list; /* Calculate DF_local */ if (bb->taken) { CheckForDominanceFrontier(cu, bb, bb->taken); } if (bb->fall_through) { CheckForDominanceFrontier(cu, bb, bb->fall_through); } if (bb->successor_block_list.block_list_type != kNotUsed) { GrowableListIterator iterator; GrowableListIteratorInit(&bb->successor_block_list.blocks, &iterator); while (true) { SuccessorBlockInfo *successor_block_info = reinterpret_cast(GrowableListIteratorNext(&iterator)); if (successor_block_info == NULL) break; BasicBlock* succ_bb = successor_block_info->block; CheckForDominanceFrontier(cu, bb, succ_bb); } } /* Calculate DF_up */ ArenaBitVectorIterator bv_iterator; BitVectorIteratorInit(bb->i_dominated, &bv_iterator); while (true) { //TUNING: hot call to BitVectorIteratorNext int dominated_idx = BitVectorIteratorNext(&bv_iterator); if (dominated_idx == -1) break; BasicBlock* dominated_bb = reinterpret_cast(GrowableListGetElement(block_list, dominated_idx)); ArenaBitVectorIterator df_iterator; BitVectorIteratorInit(dominated_bb->dom_frontier, &df_iterator); while (true) { //TUNING: hot call to BitVectorIteratorNext int df_up_idx = BitVectorIteratorNext(&df_iterator); if (df_up_idx == -1) break; BasicBlock* df_up_block = reinterpret_cast( GrowableListGetElement(block_list, df_up_idx)); CheckForDominanceFrontier(cu, bb, df_up_block); } } return true; } /* Worker function for initializing domination-related data structures */ static bool InitializeDominationInfo(CompilationUnit* cu, BasicBlock* bb) { int num_total_blocks = cu->block_list.num_used; if (bb->dominators == NULL ) { bb->dominators = AllocBitVector(cu, num_total_blocks, false /* expandable */, kBitMapDominators); bb->i_dominated = AllocBitVector(cu, num_total_blocks, false /* expandable */, kBitMapIDominated); bb->dom_frontier = AllocBitVector(cu, num_total_blocks, false /* expandable */, kBitMapDomFrontier); } else { ClearAllBits(bb->dominators); ClearAllBits(bb->i_dominated); ClearAllBits(bb->dom_frontier); } /* Set all bits in the dominator vector */ SetInitialBits(bb->dominators, num_total_blocks); return true; } /* * Worker function to compute each block's dominators. This implementation * is only used when kDebugVerifyDataflow is active and should compute * the same dominator sets as ComputeBlockDominiators. */ static bool SlowComputeBlockDominators(CompilationUnit* cu, BasicBlock* bb) { GrowableList* block_list = &cu->block_list; int num_total_blocks = block_list->num_used; ArenaBitVector* temp_block_v = cu->temp_block_v; GrowableListIterator iter; /* * The dominator of the entry block has been preset to itself and we need * to skip the calculation here. */ if (bb == cu->entry_block) return false; SetInitialBits(temp_block_v, num_total_blocks); /* Iterate through the predecessors */ GrowableListIteratorInit(bb->predecessors, &iter); while (true) { BasicBlock* pred_bb = reinterpret_cast(GrowableListIteratorNext(&iter)); if (!pred_bb) break; /* temp_block_v = temp_block_v ^ dominators */ if (pred_bb->dominators != NULL) { IntersectBitVectors(temp_block_v, temp_block_v, pred_bb->dominators); } } SetBit(cu, temp_block_v, bb->id); if (CompareBitVectors(temp_block_v, bb->dominators)) { CopyBitVector(bb->dominators, temp_block_v); return true; } return false; } /* * Worker function to compute the idom. This implementation is only * used when kDebugVerifyDataflow is active and should compute the * same i_dom as ComputeblockIDom. */ static bool SlowComputeBlockIDom(CompilationUnit* cu, BasicBlock* bb) { GrowableList* block_list = &cu->block_list; ArenaBitVector* temp_block_v = cu->temp_block_v; ArenaBitVectorIterator bv_iterator; BasicBlock* i_dom; if (bb == cu->entry_block) return false; CopyBitVector(temp_block_v, bb->dominators); ClearBit(temp_block_v, bb->id); BitVectorIteratorInit(temp_block_v, &bv_iterator); /* Should not see any dead block */ DCHECK_NE(CountSetBits(temp_block_v), 0); if (CountSetBits(temp_block_v) == 1) { i_dom = reinterpret_cast (GrowableListGetElement(block_list, BitVectorIteratorNext(&bv_iterator))); bb->i_dom = i_dom; } else { int i_dom_idx = BitVectorIteratorNext(&bv_iterator); DCHECK_NE(i_dom_idx, -1); while (true) { int next_dom = BitVectorIteratorNext(&bv_iterator); if (next_dom == -1) break; BasicBlock* next_dom_bb = reinterpret_cast(GrowableListGetElement(block_list, next_dom)); /* i_dom dominates next_dom - set new i_dom */ if (IsBitSet(next_dom_bb->dominators, i_dom_idx)) { i_dom_idx = next_dom; } } i_dom = reinterpret_cast(GrowableListGetElement(block_list, i_dom_idx)); /* Set the immediate dominator block for bb */ bb->i_dom = i_dom; } /* Add bb to the i_dominated set of the immediate dominator block */ SetBit(cu, i_dom->i_dominated, bb->id); return true; } /* * 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. */ static int FindCommonParent(CompilationUnit *cu, int block1, int block2) { while (block1 != block2) { while (block1 < block2) { block1 = cu->i_dom_list[block1]; DCHECK_NE(block1, NOTVISITED); } while (block2 < block1) { block2 = cu->i_dom_list[block2]; DCHECK_NE(block2, NOTVISITED); } } return block1; } /* Worker function to compute each block's immediate dominator */ static bool ComputeblockIDom(CompilationUnit* cu, BasicBlock* bb) { GrowableListIterator iter; int idom = -1; /* Special-case entry block */ if (bb == cu->entry_block) { return false; } /* Iterate through the predecessors */ GrowableListIteratorInit(bb->predecessors, &iter); /* Find the first processed predecessor */ while (true) { BasicBlock* pred_bb = reinterpret_cast(GrowableListIteratorNext(&iter)); CHECK(pred_bb != NULL); if (cu->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 = reinterpret_cast(GrowableListIteratorNext(&iter)); if (!pred_bb) break; if (cu->i_dom_list[pred_bb->dfs_id] == NOTVISITED) { continue; } else { idom = FindCommonParent(cu, pred_bb->dfs_id, idom); } } DCHECK_NE(idom, NOTVISITED); /* Did something change? */ if (cu->i_dom_list[bb->dfs_id] != idom) { cu->i_dom_list[bb->dfs_id] = idom; return true; } return false; } /* Worker function to compute each block's domintors */ static bool ComputeBlockDominiators(CompilationUnit* cu, BasicBlock* bb) { if (bb == cu->entry_block) { ClearAllBits(bb->dominators); } else { CopyBitVector(bb->dominators, bb->i_dom->dominators); } SetBit(cu, bb->dominators, bb->id); return false; } static bool SetDominators(CompilationUnit* cu, BasicBlock* bb) { if (bb != cu->entry_block) { int idom_dfs_idx = cu->i_dom_list[bb->dfs_id]; DCHECK_NE(idom_dfs_idx, NOTVISITED); int i_dom_idx = cu->dfs_post_order.elem_list[idom_dfs_idx]; BasicBlock* i_dom = reinterpret_cast(GrowableListGetElement(&cu->block_list, i_dom_idx)); if (cu->enable_debug & (1 << kDebugVerifyDataflow)) { DCHECK_EQ(bb->i_dom->id, i_dom->id); } bb->i_dom = i_dom; /* Add bb to the i_dominated set of the immediate dominator block */ SetBit(cu, i_dom->i_dominated, bb->id); } return false; } /* Compute dominators, immediate dominator, and dominance fronter */ static void ComputeDominators(CompilationUnit* cu) { int num_reachable_blocks = cu->num_reachable_blocks; int num_total_blocks = cu->block_list.num_used; /* Initialize domination-related data structures */ DataFlowAnalysisDispatcher(cu, InitializeDominationInfo, kReachableNodes, false /* is_iterative */); /* Initalize & Clear i_dom_list */ if (cu->i_dom_list == NULL) { cu->i_dom_list = static_cast(NewMem(cu, sizeof(int) * num_reachable_blocks, false, kAllocDFInfo)); } for (int i = 0; i < num_reachable_blocks; i++) { cu->i_dom_list[i] = NOTVISITED; } /* For post-order, last block is entry block. Set its i_dom to istelf */ DCHECK_EQ(cu->entry_block->dfs_id, num_reachable_blocks-1); cu->i_dom_list[cu->entry_block->dfs_id] = cu->entry_block->dfs_id; /* Compute the immediate dominators */ DataFlowAnalysisDispatcher(cu, ComputeblockIDom, kReversePostOrderTraversal, true /* is_iterative */); /* Set the dominator for the root node */ ClearAllBits(cu->entry_block->dominators); SetBit(cu, cu->entry_block->dominators, cu->entry_block->id); if (cu->temp_block_v == NULL) { cu->temp_block_v = AllocBitVector(cu, num_total_blocks, false /* expandable */, kBitMapTmpBlockV); } else { ClearAllBits(cu->temp_block_v); } cu->entry_block->i_dom = NULL; /* For testing, compute sets using alternate mechanism */ if (cu->enable_debug & (1 << kDebugVerifyDataflow)) { // Use alternate mechanism to compute dominators for comparison DataFlowAnalysisDispatcher(cu, SlowComputeBlockDominators, kPreOrderDFSTraversal, true /* is_iterative */); DataFlowAnalysisDispatcher(cu, SlowComputeBlockIDom, kReachableNodes, false /* is_iterative */); } DataFlowAnalysisDispatcher(cu, SetDominators, kReachableNodes, false /* is_iterative */); DataFlowAnalysisDispatcher(cu, ComputeBlockDominiators, kReversePostOrderTraversal, false /* is_iterative */); /* * Now go ahead and compute the post order traversal based on the * i_dominated sets. */ if (cu->dom_post_order_traversal.elem_list == NULL) { CompilerInitGrowableList(cu, &cu->dom_post_order_traversal, num_reachable_blocks, kListDomPostOrderTraversal); } else { cu->dom_post_order_traversal.num_used = 0; } ComputeDomPostOrderTraversal(cu, cu->entry_block); DCHECK_EQ(cu->dom_post_order_traversal.num_used, static_cast(cu->num_reachable_blocks)); /* Now compute the dominance frontier for each block */ DataFlowAnalysisDispatcher(cu, ComputeDominanceFrontier, kPostOrderDOMTraversal, false /* is_iterative */); } /* * Perform dest U= src1 ^ ~src2 * This is probably not general enough to be placed in BitVector.[ch]. */ static void ComputeSuccLineIn(ArenaBitVector* dest, const ArenaBitVector* src1, const ArenaBitVector* src2) { if (dest->storage_size != src1->storage_size || dest->storage_size != src2->storage_size || dest->expandable != src1->expandable || dest->expandable != src2->expandable) { LOG(FATAL) << "Incompatible set properties"; } unsigned int idx; for (idx = 0; idx < dest->storage_size; idx++) { dest->storage[idx] |= src1->storage[idx] & ~src2->storage[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. */ static bool ComputeBlockLiveIns(CompilationUnit* cu, BasicBlock* bb) { ArenaBitVector* temp_dalvik_register_v = cu->temp_dalvik_register_v; if (bb->data_flow_info == NULL) return false; CopyBitVector(temp_dalvik_register_v, 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) { GrowableListIterator iterator; GrowableListIteratorInit(&bb->successor_block_list.blocks, &iterator); while (true) { SuccessorBlockInfo *successor_block_info = reinterpret_cast(GrowableListIteratorNext(&iterator)); 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 (CompareBitVectors(temp_dalvik_register_v, bb->data_flow_info->live_in_v)) { CopyBitVector(bb->data_flow_info->live_in_v, temp_dalvik_register_v); return true; } return false; } /* Insert phi nodes to for each variable to the dominance frontiers */ static void InsertPhiNodes(CompilationUnit* cu) { int dalvik_reg; const GrowableList* block_list = &cu->block_list; ArenaBitVector* phi_blocks = AllocBitVector(cu, cu->num_blocks, false, kBitMapPhi); ArenaBitVector* tmp_blocks = AllocBitVector(cu, cu->num_blocks, false, kBitMapTmpBlocks); ArenaBitVector* input_blocks = AllocBitVector(cu, cu->num_blocks, false, kBitMapInputBlocks); cu->temp_dalvik_register_v = AllocBitVector(cu, cu->num_dalvik_registers, false, kBitMapRegisterV); DataFlowAnalysisDispatcher(cu, ComputeBlockLiveIns, kPostOrderDFSTraversal, true /* is_iterative */); /* Iterate through each Dalvik register */ for (dalvik_reg = cu->num_dalvik_registers - 1; dalvik_reg >= 0; dalvik_reg--) { bool change; ArenaBitVectorIterator iterator; CopyBitVector(input_blocks, cu->def_block_matrix[dalvik_reg]); ClearAllBits(phi_blocks); /* Calculate the phi blocks for each Dalvik register */ do { change = false; ClearAllBits(tmp_blocks); BitVectorIteratorInit(input_blocks, &iterator); while (true) { int idx = BitVectorIteratorNext(&iterator); if (idx == -1) break; BasicBlock* def_bb = reinterpret_cast(GrowableListGetElement(block_list, idx)); /* Merge the dominance frontier to tmp_blocks */ //TUNING: hot call to UnifyBitVetors if (def_bb->dom_frontier != NULL) { UnifyBitVetors(tmp_blocks, tmp_blocks, def_bb->dom_frontier); } } if (CompareBitVectors(phi_blocks, tmp_blocks)) { change = true; CopyBitVector(phi_blocks, tmp_blocks); /* * Iterate through the original blocks plus the new ones in * the dominance frontier. */ CopyBitVector(input_blocks, phi_blocks); UnifyBitVetors(input_blocks, input_blocks, cu->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. */ BitVectorIteratorInit(phi_blocks, &iterator); while (true) { int idx = BitVectorIteratorNext(&iterator); if (idx == -1) break; BasicBlock* phi_bb = reinterpret_cast(GrowableListGetElement(block_list, idx)); /* Variable will be clobbered before being used - no need for phi */ if (!IsBitSet(phi_bb->data_flow_info->live_in_v, dalvik_reg)) continue; MIR *phi = static_cast(NewMem(cu, sizeof(MIR), true, kAllocDFInfo)); phi->dalvikInsn.opcode = static_cast(kMirOpPhi); phi->dalvikInsn.vA = dalvik_reg; phi->offset = phi_bb->start_offset; PrependMIR(phi_bb, phi); } } } /* * Worker function to insert phi-operands with latest SSA names from * predecessor blocks */ static bool InsertPhiNodeOperands(CompilationUnit* cu, BasicBlock* bb) { GrowableListIterator iter; MIR *mir; std::vector uses; std::vector 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(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(cu, ssa_reg); uses.clear(); incoming_arc.clear(); /* Iterate through the predecessors */ GrowableListIteratorInit(bb->predecessors, &iter); while (true) { BasicBlock* pred_bb = reinterpret_cast(GrowableListIteratorNext(&iter)); 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(NewMem(cu, sizeof(int) * num_uses, false, kAllocDFInfo)); mir->ssa_rep->fp_use = static_cast(NewMem(cu, sizeof(bool) * num_uses, true, kAllocDFInfo)); int* incoming = static_cast(NewMem(cu, sizeof(int) * num_uses, false, kAllocDFInfo)); // TODO: Ugly, rework (but don't burden each MIR/LIR for Phi-only needs) mir->dalvikInsn.vB = reinterpret_cast(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; } static void DoDFSPreOrderSSARename(CompilationUnit* cu, BasicBlock* block) { if (block->visited || block->hidden) return; block->visited = true; /* Process this block */ DoSSAConversion(cu, block); int map_size = sizeof(int) * cu->num_dalvik_registers; /* Save SSA map snapshot */ int* saved_ssa_map = static_cast(NewMem(cu, map_size, false, kAllocDalvikToSSAMap)); memcpy(saved_ssa_map, cu->vreg_to_ssa_map, map_size); if (block->fall_through) { DoDFSPreOrderSSARename(cu, block->fall_through); /* Restore SSA map snapshot */ memcpy(cu->vreg_to_ssa_map, saved_ssa_map, map_size); } if (block->taken) { DoDFSPreOrderSSARename(cu, block->taken); /* Restore SSA map snapshot */ memcpy(cu->vreg_to_ssa_map, saved_ssa_map, map_size); } if (block->successor_block_list.block_list_type != kNotUsed) { GrowableListIterator iterator; GrowableListIteratorInit(&block->successor_block_list.blocks, &iterator); while (true) { SuccessorBlockInfo *successor_block_info = reinterpret_cast(GrowableListIteratorNext(&iterator)); if (successor_block_info == NULL) break; BasicBlock* succ_bb = successor_block_info->block; DoDFSPreOrderSSARename(cu, succ_bb); /* Restore SSA map snapshot */ memcpy(cu->vreg_to_ssa_map, saved_ssa_map, map_size); } } cu->vreg_to_ssa_map = saved_ssa_map; return; } /* Perform SSA transformation for the whole method */ void SSATransformation(CompilationUnit* cu) { /* Compute the DFS order */ ComputeDFSOrders(cu); if (!cu->disable_dataflow) { /* Compute the dominator info */ ComputeDominators(cu); } /* Allocate data structures in preparation for SSA conversion */ CompilerInitializeSSAConversion(cu); if (!cu->disable_dataflow) { /* Find out the "Dalvik reg def x block" relation */ ComputeDefBlockMatrix(cu); /* Insert phi nodes to dominance frontiers for all variables */ InsertPhiNodes(cu); } /* Rename register names by local defs and phi nodes */ DataFlowAnalysisDispatcher(cu, ClearVisitedFlag, kAllNodes, false /* is_iterative */); DoDFSPreOrderSSARename(cu, cu->entry_block); if (!cu->disable_dataflow) { /* * Shared temp bit vector used by each block to count the number of defs * from all the predecessor blocks. */ cu->temp_ssa_register_v = AllocBitVector(cu, cu->num_ssa_regs, false, kBitMapTempSSARegisterV); cu->temp_ssa_block_id_v = static_cast(NewMem(cu, sizeof(int) * cu->num_ssa_regs, false, kAllocDFInfo)); /* Insert phi-operands with latest SSA names from predecessor blocks */ DataFlowAnalysisDispatcher(cu, InsertPhiNodeOperands, kReachableNodes, false /* is_iterative */); } } } // namespace art