/* Rename register names by local defs and phi nodes */
ClearAllVisitedFlags();
DoDFSPreOrderSSARename(GetEntryBlock());
-
- // Update the maximum number of reachable blocks.
- max_num_reachable_blocks_ = num_reachable_blocks_;
}
+void MIRGraph::SSATransformationEnd() {
+ // Verify the dataflow information after the pass.
+ if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) {
+ VerifyDataflow();
+ }
+
+ temp_bit_vector_size_ = 0u;
+ temp_bit_vector_ = nullptr;
+ DCHECK(temp_scoped_alloc_.get() != nullptr);
+ temp_scoped_alloc_.reset();
+}
+
+void MIRGraph::ComputeTopologicalSortOrder() {
+ std::queue<BasicBlock *> q;
+ std::map<int, int> visited_cnt_values;
+
+ // Clear the nodes.
+ ClearAllVisitedFlags();
+
+ // Create the topological order if need be.
+ if (topological_order_ != nullptr) {
+ topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, 0);
+ }
+ topological_order_->Reset();
+
+ // Set up visitedCntValues map for all BB. The default value for this counters in the map is zero.
+ // also fill initial queue.
+ GrowableArray<BasicBlock*>::Iterator iterator(&block_list_);
+
+ while (true) {
+ BasicBlock* bb = iterator.Next();
+
+ if (bb == nullptr) {
+ break;
+ }
+
+ if (bb->hidden == true) {
+ continue;
+ }
+
+ visited_cnt_values[bb->id] = bb->predecessors->Size();
+
+ GrowableArray<BasicBlockId>::Iterator pred_iterator(bb->predecessors);
+ // To process loops we should not wait for dominators.
+ while (true) {
+ BasicBlock* pred_bb = GetBasicBlock(pred_iterator.Next());
+
+ if (pred_bb == nullptr) {
+ break;
+ }
+
+ if (pred_bb->dominators == nullptr || pred_bb->hidden == true) {
+ continue;
+ }
+
+ // Skip the backward branch.
+ if (pred_bb->dominators->IsBitSet(bb->id) != 0) {
+ visited_cnt_values[bb->id]--;
+ }
+ }
+
+ // Add entry block to queue.
+ if (visited_cnt_values[bb->id] == 0) {
+ q.push(bb);
+ }
+ }
+
+ while (q.size() > 0) {
+ // Get top.
+ BasicBlock *bb = q.front();
+ q.pop();
+
+ DCHECK_EQ(bb->hidden, false);
+
+ if (bb->IsExceptionBlock() == true) {
+ continue;
+ }
+
+ // We've visited all the predecessors. So, we can visit bb.
+ if (bb->visited == false) {
+ bb->visited = true;
+
+ // Now add the basic block.
+ topological_order_->Insert(bb->id);
+
+ // Reduce visitedCnt for all the successors and add into the queue ones with visitedCnt equals to zero.
+ ChildBlockIterator succIter(bb, this);
+ BasicBlock *successor = succIter.Next();
+ while (successor != nullptr) {
+ // one more predecessor was visited.
+ visited_cnt_values[successor->id]--;
+
+ if (visited_cnt_values[successor->id] <= 0 && successor->visited == false && successor->hidden == false) {
+ q.push(successor);
+ }
+
+ // Take next successor.
+ successor = succIter.Next();
+ }
+ }
+ }
+}
+
+bool BasicBlock::IsExceptionBlock() const {
+ if (block_type == kExceptionHandling) {
+ return true;
+ }
+ return false;
+}
+
+ChildBlockIterator::ChildBlockIterator(BasicBlock* bb, MIRGraph* mir_graph)
+ : basic_block_(bb), mir_graph_(mir_graph), visited_fallthrough_(false),
+ visited_taken_(false), have_successors_(false) {
+ // Check if we actually do have successors.
+ if (basic_block_ != 0 && basic_block_->successor_block_list_type != kNotUsed) {
+ have_successors_ = true;
+ successor_iter_.Reset(basic_block_->successor_blocks);
+ }
+}
+
+BasicBlock* ChildBlockIterator::Next() {
+ // We check if we have a basic block. If we don't we cannot get next child.
+ if (basic_block_ == nullptr) {
+ return nullptr;
+ }
+
+ // If we haven't visited fallthrough, return that.
+ if (visited_fallthrough_ == false) {
+ visited_fallthrough_ = true;
+
+ BasicBlock* result = mir_graph_->GetBasicBlock(basic_block_->fall_through);
+ if (result != nullptr) {
+ return result;
+ }
+ }
+
+ // If we haven't visited taken, return that.
+ if (visited_taken_ == false) {
+ visited_taken_ = true;
+
+ BasicBlock* result = mir_graph_->GetBasicBlock(basic_block_->taken);
+ if (result != nullptr) {
+ return result;
+ }
+ }
+
+ // We visited both taken and fallthrough. Now check if we have successors we need to visit.
+ if (have_successors_ == true) {
+ // Get information about next successor block.
+ SuccessorBlockInfo* successor_block_info = successor_iter_.Next();
+
+ // If we don't have anymore successors, return nullptr.
+ if (successor_block_info != nullptr) {
+ return mir_graph_->GetBasicBlock(successor_block_info->block);
+ }
+ }
+
+ // We do not have anything.
+ return nullptr;
+}
+
+BasicBlock* BasicBlock::Copy(CompilationUnit* c_unit) {
+ MIRGraph* mir_graph = c_unit->mir_graph.get();
+ return Copy(mir_graph);
+}
+
+BasicBlock* BasicBlock::Copy(MIRGraph* mir_graph) {
+ BasicBlock* result_bb = mir_graph->CreateNewBB(block_type);
+
+ // We don't do a memcpy style copy here because it would lead to a lot of things
+ // to clean up. Let us do it by hand instead.
+ // Copy in taken and fallthrough.
+ result_bb->fall_through = fall_through;
+ result_bb->taken = taken;
+
+ // Copy successor links if needed.
+ ArenaAllocator* arena = mir_graph->GetArena();
+
+ result_bb->successor_block_list_type = successor_block_list_type;
+ if (result_bb->successor_block_list_type != kNotUsed) {
+ size_t size = successor_blocks->Size();
+ result_bb->successor_blocks = new (arena) GrowableArray<SuccessorBlockInfo*>(arena, size, kGrowableArraySuccessorBlocks);
+ GrowableArray<SuccessorBlockInfo*>::Iterator iterator(successor_blocks);
+ while (true) {
+ SuccessorBlockInfo* sbi_old = iterator.Next();
+ if (sbi_old == nullptr) {
+ break;
+ }
+ SuccessorBlockInfo* sbi_new = static_cast<SuccessorBlockInfo*>(arena->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
+ memcpy(sbi_new, sbi_old, sizeof(SuccessorBlockInfo));
+ result_bb->successor_blocks->Insert(sbi_new);
+ }
+ }
+
+ // Copy offset, method.
+ result_bb->start_offset = start_offset;
+
+ // Now copy instructions.
+ for (MIR* mir = first_mir_insn; mir != 0; mir = mir->next) {
+ // Get a copy first.
+ MIR* copy = mir->Copy(mir_graph);
+
+ // Append it.
+ result_bb->AppendMIR(copy);
+ }
+
+ return result_bb;
+}
+
+MIR* MIR::Copy(MIRGraph* mir_graph) {
+ MIR* res = mir_graph->NewMIR();
+ *res = *this;
+
+ // Remove links
+ res->next = nullptr;
+ res->bb = NullBasicBlockId;
+ res->ssa_rep = nullptr;
+
+ return res;
+}
+
+MIR* MIR::Copy(CompilationUnit* c_unit) {
+ return Copy(c_unit->mir_graph.get());
+}
+
+uint32_t SSARepresentation::GetStartUseIndex(Instruction::Code opcode) {
+ // Default result.
+ int res = 0;
+
+ // We are basically setting the iputs to their igets counterparts.
+ switch (opcode) {
+ case Instruction::IPUT:
+ case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT:
+ case Instruction::IPUT_QUICK:
+ case Instruction::IPUT_OBJECT_QUICK:
+ case Instruction::APUT:
+ case Instruction::APUT_OBJECT:
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_CHAR:
+ case Instruction::APUT_SHORT:
+ case Instruction::SPUT:
+ case Instruction::SPUT_OBJECT:
+ case Instruction::SPUT_BOOLEAN:
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_CHAR:
+ case Instruction::SPUT_SHORT:
+ // Skip the VR containing what to store.
+ res = 1;
+ break;
+ case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_WIDE_QUICK:
+ case Instruction::APUT_WIDE:
+ case Instruction::SPUT_WIDE:
+ // Skip the two VRs containing what to store.
+ res = 2;
+ break;
+ default:
+ // Do nothing in the general case.
+ break;
+ }
+
+ return res;
+}
+
+/**
+ * @brief Given a decoded instruction, it checks whether the instruction
+ * sets a constant and if it does, more information is provided about the
+ * constant being set.
+ * @param ptr_value pointer to a 64-bit holder for the constant.
+ * @param wide Updated by function whether a wide constant is being set by bytecode.
+ * @return Returns false if the decoded instruction does not represent a constant bytecode.
+ */
+bool MIR::DecodedInstruction::GetConstant(int64_t* ptr_value, bool* wide) const {
+ bool sets_const = true;
+ int64_t value = vB;
+
+ DCHECK(ptr_value != nullptr);
+ DCHECK(wide != nullptr);
+
+ switch (opcode) {
+ case Instruction::CONST_4:
+ case Instruction::CONST_16:
+ case Instruction::CONST:
+ *wide = false;
+ value <<= 32; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_HIGH16:
+ *wide = false;
+ value <<= 48; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32:
+ *wide = true;
+ value <<= 32; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_WIDE:
+ *wide = true;
+ value = vB_wide;
+ break;
+ case Instruction::CONST_WIDE_HIGH16:
+ *wide = true;
+ value <<= 48; // In order to get the sign extend.
+ break;
+ default:
+ sets_const = false;
+ break;
+ }
+
+ if (sets_const) {
+ *ptr_value = value;
+ }
+
+ return sets_const;
+}
+
+void BasicBlock::ResetOptimizationFlags(uint16_t reset_flags) {
+ // Reset flags for all MIRs in bb.
+ for (MIR* mir = first_mir_insn; mir != NULL; mir = mir->next) {
+ mir->optimization_flags &= (~reset_flags);
+ }
+}
+
+void BasicBlock::Hide(CompilationUnit* c_unit) {
+ // First lets make it a dalvik bytecode block so it doesn't have any special meaning.
+ block_type = kDalvikByteCode;
+
+ // Mark it as hidden.
+ hidden = true;
+
+ // Detach it from its MIRs so we don't generate code for them. Also detached MIRs
+ // are updated to know that they no longer have a parent.
+ for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+ mir->bb = NullBasicBlockId;
+ }
+ first_mir_insn = nullptr;
+ last_mir_insn = nullptr;
+
+ GrowableArray<BasicBlockId>::Iterator iterator(predecessors);
+
+ MIRGraph* mir_graph = c_unit->mir_graph.get();
+ while (true) {
+ BasicBlock* pred_bb = mir_graph->GetBasicBlock(iterator.Next());
+ if (pred_bb == nullptr) {
+ break;
+ }
+
+ // Sadly we have to go through the children by hand here.
+ pred_bb->ReplaceChild(id, NullBasicBlockId);
+ }
+
+ // Iterate through children of bb we are hiding.
+ ChildBlockIterator successorChildIter(this, mir_graph);
+
+ for (BasicBlock* childPtr = successorChildIter.Next(); childPtr != 0; childPtr = successorChildIter.Next()) {
+ // Replace child with null child.
+ childPtr->predecessors->Delete(id);
+ }
+}
+
+bool BasicBlock::IsSSALiveOut(const CompilationUnit* c_unit, int ssa_reg) {
+ // In order to determine if the ssa reg is live out, we scan all the MIRs. We remember
+ // the last SSA number of the same dalvik register. At the end, if it is different than ssa_reg,
+ // then it is not live out of this BB.
+ int dalvik_reg = c_unit->mir_graph->SRegToVReg(ssa_reg);
+
+ int last_ssa_reg = -1;
+
+ // Walk through the MIRs backwards.
+ for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+ // Get ssa rep.
+ SSARepresentation *ssa_rep = mir->ssa_rep;
+
+ // Go through the defines for this MIR.
+ for (int i = 0; i < ssa_rep->num_defs; i++) {
+ DCHECK(ssa_rep->defs != nullptr);
+
+ // Get the ssa reg.
+ int def_ssa_reg = ssa_rep->defs[i];
+
+ // Get dalvik reg.
+ int def_dalvik_reg = c_unit->mir_graph->SRegToVReg(def_ssa_reg);
+
+ // Compare dalvik regs.
+ if (dalvik_reg == def_dalvik_reg) {
+ // We found a def of the register that we are being asked about.
+ // Remember it.
+ last_ssa_reg = def_ssa_reg;
+ }
+ }
+ }
+
+ if (last_ssa_reg == -1) {
+ // If we get to this point we couldn't find a define of register user asked about.
+ // Let's assume the user knows what he's doing so we can be safe and say that if we
+ // couldn't find a def, it is live out.
+ return true;
+ }
+
+ // If it is not -1, we found a match, is it ssa_reg?
+ return (ssa_reg == last_ssa_reg);
+}
+
+bool BasicBlock::ReplaceChild(BasicBlockId old_bb, BasicBlockId new_bb) {
+ // We need to check taken, fall_through, and successor_blocks to replace.
+ bool found = false;
+ if (taken == old_bb) {
+ taken = new_bb;
+ found = true;
+ }
+
+ if (fall_through == old_bb) {
+ fall_through = new_bb;
+ found = true;
+ }
+
+ if (successor_block_list_type != kNotUsed) {
+ GrowableArray<SuccessorBlockInfo*>::Iterator iterator(successor_blocks);
+ while (true) {
+ SuccessorBlockInfo* successor_block_info = iterator.Next();
+ if (successor_block_info == nullptr) {
+ break;
+ }
+ if (successor_block_info->block == old_bb) {
+ successor_block_info->block = new_bb;
+ found = true;
+ }
+ }
+ }
+
+ return found;
+}
+
+void BasicBlock::UpdatePredecessor(BasicBlockId old_parent, BasicBlockId new_parent) {
+ GrowableArray<BasicBlockId>::Iterator iterator(predecessors);
+ bool found = false;
+
+ while (true) {
+ BasicBlockId pred_bb_id = iterator.Next();
+
+ if (pred_bb_id == NullBasicBlockId) {
+ break;
+ }
+
+ if (pred_bb_id == old_parent) {
+ size_t idx = iterator.GetIndex() - 1;
+ predecessors->Put(idx, new_parent);
+ found = true;
+ break;
+ }
+ }
+
+ // If not found, add it.
+ if (found == false) {
+ predecessors->Insert(new_parent);
+ }
+}
+
+// Create a new basic block with block_id as num_blocks_ that is
+// post-incremented.
+BasicBlock* MIRGraph::CreateNewBB(BBType block_type) {
+ BasicBlock* res = NewMemBB(block_type, num_blocks_++);
+ block_list_.Insert(res);
+ return res;
+}
+
} // namespace art