diff options
Diffstat (limited to 'compiler/optimizing/nodes.cc')
-rw-r--r-- | compiler/optimizing/nodes.cc | 175 |
1 files changed, 121 insertions, 54 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 989970fb49..68fb0acf7f 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -21,6 +21,7 @@ #include "base/bit_vector-inl.h" #include "base/bit_utils.h" #include "base/stl_util.h" +#include "intrinsics.h" #include "mirror/class-inl.h" #include "scoped_thread_state_change.h" @@ -54,7 +55,6 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) { visiting.ClearBit(current_id); worklist.pop_back(); } else { - DCHECK_LT(successors_visited[current_id], current->GetSuccessors().size()); HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++]; uint32_t successor_id = successor->GetBlockId(); if (visiting.IsBitSet(successor_id)) { @@ -88,7 +88,7 @@ static void RemoveAsUser(HInstruction* instruction) { void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const { for (size_t i = 0; i < blocks_.size(); ++i) { if (!visited.IsBitSet(i)) { - HBasicBlock* block = GetBlock(i); + HBasicBlock* block = blocks_[i]; DCHECK(block->GetPhis().IsEmpty()) << "Phis are not inserted at this stage"; for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { RemoveAsUser(it.Current()); @@ -100,7 +100,7 @@ void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visit void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) { for (size_t i = 0; i < blocks_.size(); ++i) { if (!visited.IsBitSet(i)) { - HBasicBlock* block = GetBlock(i); + HBasicBlock* block = blocks_[i]; // We only need to update the successor, which might be live. for (HBasicBlock* successor : block->GetSuccessors()) { successor->RemovePredecessor(block); @@ -174,7 +174,6 @@ void HGraph::ComputeDominanceInformation() { if (successors_visited[current_id] == current->GetSuccessors().size()) { worklist.pop_back(); } else { - DCHECK_LT(successors_visited[current_id], current->GetSuccessors().size()); HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++]; if (successor->GetDominator() == nullptr) { @@ -185,7 +184,6 @@ void HGraph::ComputeDominanceInformation() { // Once all the forward edges have been visited, we know the immediate // dominator of the block. We can then start visiting its successors. - DCHECK_LT(successor->GetBlockId(), visits.size()); if (++visits[successor->GetBlockId()] == successor->GetPredecessors().size() - successor->NumberOfBackEdges()) { successor->GetDominator()->AddDominatedBlock(successor); @@ -257,7 +255,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) { pre_header->AddInstruction(new (arena_) HGoto(header->GetDexPc())); for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) { - HBasicBlock* predecessor = header->GetPredecessor(pred); + HBasicBlock* predecessor = header->GetPredecessors()[pred]; if (!info->IsBackEdge(*predecessor)) { predecessor->ReplaceSuccessor(header, pre_header); pred--; @@ -267,10 +265,10 @@ void HGraph::SimplifyLoop(HBasicBlock* header) { } // Make sure the first predecessor of a loop header is the incoming block. - if (info->IsBackEdge(*header->GetPredecessor(0))) { - HBasicBlock* to_swap = header->GetPredecessor(0); + if (info->IsBackEdge(*header->GetPredecessors()[0])) { + HBasicBlock* to_swap = header->GetPredecessors()[0]; for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) { - HBasicBlock* predecessor = header->GetPredecessor(pred); + HBasicBlock* predecessor = header->GetPredecessors()[pred]; if (!info->IsBackEdge(*predecessor)) { header->predecessors_[pred] = to_swap; header->predecessors_[0] = predecessor; @@ -293,7 +291,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) { } static bool CheckIfPredecessorAtIsExceptional(const HBasicBlock& block, size_t pred_idx) { - HBasicBlock* predecessor = block.GetPredecessor(pred_idx); + HBasicBlock* predecessor = block.GetPredecessors()[pred_idx]; if (!predecessor->EndsWithTryBoundary()) { // Only edges from HTryBoundary can be exceptional. return false; @@ -343,7 +341,7 @@ void HGraph::SimplifyCatchBlocks() { HBasicBlock* normal_block = catch_block->SplitBefore(catch_block->GetFirstInstruction()); for (size_t j = 0; j < catch_block->GetPredecessors().size(); ++j) { if (!CheckIfPredecessorAtIsExceptional(*catch_block, j)) { - catch_block->GetPredecessor(j)->ReplaceSuccessor(catch_block, normal_block); + catch_block->GetPredecessors()[j]->ReplaceSuccessor(catch_block, normal_block); --j; } } @@ -365,7 +363,7 @@ void HGraph::ComputeTryBlockInformation() { // Infer try membership from the first predecessor. Having simplified loops, // the first predecessor can never be a back edge and therefore it must have // been visited already and had its try membership set. - HBasicBlock* first_predecessor = block->GetPredecessor(0); + HBasicBlock* first_predecessor = block->GetPredecessors()[0]; DCHECK(!block->IsLoopHeader() || !block->GetLoopInformation()->IsBackEdge(*first_predecessor)); const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors(); if (try_entry != nullptr) { @@ -385,7 +383,7 @@ void HGraph::SimplifyCFG() { if (block == nullptr) continue; if (block->NumberOfNormalSuccessors() > 1) { for (size_t j = 0; j < block->GetSuccessors().size(); ++j) { - HBasicBlock* successor = block->GetSuccessor(j); + HBasicBlock* successor = block->GetSuccessors()[j]; DCHECK(!successor->IsCatchBlock()); if (successor->GetPredecessors().size() > 1) { SplitCriticalEdge(block, successor); @@ -534,7 +532,7 @@ bool HLoopInformation::Populate() { void HLoopInformation::Update() { HGraph* graph = header_->GetGraph(); for (uint32_t id : blocks_.Indexes()) { - HBasicBlock* block = graph->GetBlock(id); + HBasicBlock* block = graph->GetBlocks()[id]; // Reset loop information of non-header blocks inside the loop, except // members of inner nested loops because those should already have been // updated by their own LoopInformation. @@ -576,6 +574,17 @@ bool HLoopInformation::IsIn(const HLoopInformation& other) const { return other.blocks_.IsBitSet(header_->GetBlockId()); } +bool HLoopInformation::IsLoopInvariant(HInstruction* instruction, bool must_dominate) const { + HLoopInformation* other_loop = instruction->GetBlock()->GetLoopInformation(); + if (other_loop != this && (other_loop == nullptr || !other_loop->IsIn(*this))) { + if (must_dominate) { + return instruction->GetBlock()->Dominates(GetHeader()); + } + return true; + } + return false; +} + size_t HLoopInformation::GetLifetimeEnd() const { size_t last_position = 0; for (HBasicBlock* back_edge : GetBackEdges()) { @@ -608,8 +617,23 @@ static void UpdateInputsUsers(HInstruction* instruction) { void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial, HInstruction* replacement) { DCHECK(initial->GetBlock() == this); - InsertInstructionBefore(replacement, initial); - initial->ReplaceWith(replacement); + if (initial->IsControlFlow()) { + // We can only replace a control flow instruction with another control flow instruction. + DCHECK(replacement->IsControlFlow()); + DCHECK_EQ(replacement->GetId(), -1); + DCHECK_EQ(replacement->GetType(), Primitive::kPrimVoid); + DCHECK_EQ(initial->GetBlock(), this); + DCHECK_EQ(initial->GetType(), Primitive::kPrimVoid); + DCHECK(initial->GetUses().IsEmpty()); + DCHECK(initial->GetEnvUses().IsEmpty()); + replacement->SetBlock(this); + replacement->SetId(GetGraph()->GetNextInstructionId()); + instructions_.InsertInstructionBefore(replacement, initial); + UpdateInputsUsers(replacement); + } else { + InsertInstructionBefore(replacement, initial); + initial->ReplaceWith(replacement); + } RemoveInstruction(initial); } @@ -743,7 +767,6 @@ void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env, } void HEnvironment::RemoveAsUserOfInput(size_t index) const { - DCHECK_LT(index, Size()); const HUserRecord<HEnvironment*>& user_record = vregs_[index]; user_record.GetInstruction()->RemoveEnvironmentUser(user_record.GetUseNode()); } @@ -1435,7 +1458,7 @@ void HBasicBlock::MergeWith(HBasicBlock* other) { // Update links to the successors of `other`. successors_.clear(); while (!other->successors_.empty()) { - HBasicBlock* successor = other->GetSuccessor(0); + HBasicBlock* successor = other->GetSuccessors()[0]; successor->ReplacePredecessor(other, this); } @@ -1472,7 +1495,7 @@ void HBasicBlock::MergeWithInlined(HBasicBlock* other) { // Update links to the successors of `other`. successors_.clear(); while (!other->successors_.empty()) { - HBasicBlock* successor = other->GetSuccessor(0); + HBasicBlock* successor = other->GetSuccessors()[0]; successor->ReplacePredecessor(other, this); } @@ -1488,11 +1511,11 @@ void HBasicBlock::MergeWithInlined(HBasicBlock* other) { void HBasicBlock::ReplaceWith(HBasicBlock* other) { while (!GetPredecessors().empty()) { - HBasicBlock* predecessor = GetPredecessor(0); + HBasicBlock* predecessor = GetPredecessors()[0]; predecessor->ReplaceSuccessor(this, other); } while (!GetSuccessors().empty()) { - HBasicBlock* successor = GetSuccessor(0); + HBasicBlock* successor = GetSuccessors()[0]; successor->ReplacePredecessor(this, other); } for (HBasicBlock* dominated : GetDominatedBlocks()) { @@ -1567,9 +1590,9 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { if (GetBlocks().size() == 3) { // Simple case of an entry block, a body block, and an exit block. // Put the body block's instruction into `invoke`'s block. - HBasicBlock* body = GetBlock(1); - DCHECK(GetBlock(0)->IsEntryBlock()); - DCHECK(GetBlock(2)->IsExitBlock()); + HBasicBlock* body = GetBlocks()[1]; + DCHECK(GetBlocks()[0]->IsEntryBlock()); + DCHECK(GetBlocks()[2]->IsExitBlock()); DCHECK(!body->IsExitBlock()); HInstruction* last = body->GetLastInstruction(); @@ -1579,7 +1602,6 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { // Replace the invoke with the return value of the inlined graph. if (last->IsReturn()) { return_value = last->InputAt(0); - invoke->ReplaceWith(return_value); } else { DCHECK(last->IsReturnVoid()); } @@ -1594,16 +1616,16 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { HBasicBlock* at = invoke->GetBlock(); HBasicBlock* to = at->SplitAfter(invoke); - HBasicBlock* first = entry_block_->GetSuccessor(0); + HBasicBlock* first = entry_block_->GetSuccessors()[0]; DCHECK(!first->IsInLoop()); at->MergeWithInlined(first); exit_block_->ReplaceWith(to); // Update all predecessors of the exit block (now the `to` block) // to not `HReturn` but `HGoto` instead. - bool returns_void = to->GetPredecessor(0)->GetLastInstruction()->IsReturnVoid(); + bool returns_void = to->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid(); if (to->GetPredecessors().size() == 1) { - HBasicBlock* predecessor = to->GetPredecessor(0); + HBasicBlock* predecessor = to->GetPredecessors()[0]; HInstruction* last = predecessor->GetLastInstruction(); if (!returns_void) { return_value = last->InputAt(0); @@ -1627,14 +1649,11 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { } } - if (return_value != nullptr) { - invoke->ReplaceWith(return_value); - } - // Update the meta information surrounding blocks: // (1) the graph they are now in, // (2) the reverse post order of that graph, - // (3) the potential loop information they are now in. + // (3) the potential loop information they are now in, + // (4) try block membership. // We don't add the entry block, the exit block, and the first block, which // has been merged with `at`. @@ -1650,41 +1669,47 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { size_t index_of_at = IndexOfElement(outer_graph->reverse_post_order_, at); MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at); - // Do a reverse post order of the blocks in the callee and do (1), (2), - // and (3) to the blocks that apply. - HLoopInformation* info = at->GetLoopInformation(); + HLoopInformation* loop_info = at->GetLoopInformation(); + // Copy TryCatchInformation if `at` is a try block, not if it is a catch block. + TryCatchInformation* try_catch_info = at->IsTryBlock() ? at->GetTryCatchInformation() : nullptr; + + // Do a reverse post order of the blocks in the callee and do (1), (2), (3) + // and (4) to the blocks that apply. for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) { HBasicBlock* current = it.Current(); if (current != exit_block_ && current != entry_block_ && current != first) { DCHECK(!current->IsInLoop()); + DCHECK(current->GetTryCatchInformation() == nullptr); DCHECK(current->GetGraph() == this); current->SetGraph(outer_graph); outer_graph->AddBlock(current); outer_graph->reverse_post_order_[++index_of_at] = current; - if (info != nullptr) { - current->SetLoopInformation(info); + if (loop_info != nullptr) { + current->SetLoopInformation(loop_info); for (HLoopInformationOutwardIterator loop_it(*at); !loop_it.Done(); loop_it.Advance()) { loop_it.Current()->Add(current); } } + current->SetTryCatchInformation(try_catch_info); } } - // Do (1), (2), and (3) to `to`. + // Do (1), (2), (3) and (4) to `to`. to->SetGraph(outer_graph); outer_graph->AddBlock(to); outer_graph->reverse_post_order_[++index_of_at] = to; - if (info != nullptr) { - to->SetLoopInformation(info); + if (loop_info != nullptr) { + to->SetLoopInformation(loop_info); for (HLoopInformationOutwardIterator loop_it(*at); !loop_it.Done(); loop_it.Advance()) { loop_it.Current()->Add(to); } - if (info->IsBackEdge(*at)) { + if (loop_info->IsBackEdge(*at)) { // Only `to` can become a back edge, as the inlined blocks // are predecessors of `to`. - info->ReplaceBackEdge(at, to); + loop_info->ReplaceBackEdge(at, to); } } + to->SetTryCatchInformation(try_catch_info); } // Update the next instruction id of the outer graph, so that instructions @@ -1700,20 +1725,21 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { size_t parameter_index = 0; for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* current = it.Current(); + HInstruction* replacement = nullptr; if (current->IsNullConstant()) { - current->ReplaceWith(outer_graph->GetNullConstant(current->GetDexPc())); + replacement = outer_graph->GetNullConstant(current->GetDexPc()); } else if (current->IsIntConstant()) { - current->ReplaceWith(outer_graph->GetIntConstant( - current->AsIntConstant()->GetValue(), current->GetDexPc())); + replacement = outer_graph->GetIntConstant( + current->AsIntConstant()->GetValue(), current->GetDexPc()); } else if (current->IsLongConstant()) { - current->ReplaceWith(outer_graph->GetLongConstant( - current->AsLongConstant()->GetValue(), current->GetDexPc())); + replacement = outer_graph->GetLongConstant( + current->AsLongConstant()->GetValue(), current->GetDexPc()); } else if (current->IsFloatConstant()) { - current->ReplaceWith(outer_graph->GetFloatConstant( - current->AsFloatConstant()->GetValue(), current->GetDexPc())); + replacement = outer_graph->GetFloatConstant( + current->AsFloatConstant()->GetValue(), current->GetDexPc()); } else if (current->IsDoubleConstant()) { - current->ReplaceWith(outer_graph->GetDoubleConstant( - current->AsDoubleConstant()->GetValue(), current->GetDexPc())); + replacement = outer_graph->GetDoubleConstant( + current->AsDoubleConstant()->GetValue(), current->GetDexPc()); } else if (current->IsParameterValue()) { if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect() @@ -1723,13 +1749,25 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { size_t last_input_index = invoke->InputCount() - 1; DCHECK(parameter_index != last_input_index); } - current->ReplaceWith(invoke->InputAt(parameter_index++)); + replacement = invoke->InputAt(parameter_index++); } else if (current->IsCurrentMethod()) { - current->ReplaceWith(outer_graph->GetCurrentMethod()); + replacement = outer_graph->GetCurrentMethod(); } else { DCHECK(current->IsGoto() || current->IsSuspendCheck()); entry_block_->RemoveInstruction(current); } + if (replacement != nullptr) { + current->ReplaceWith(replacement); + // If the current is the return value then we need to update the latter. + if (current == return_value) { + DCHECK_EQ(entry_block_, return_value->GetBlock()); + return_value = replacement; + } + } + } + + if (return_value != nullptr) { + invoke->ReplaceWith(return_value); } // Finally remove the invoke from the caller. @@ -1873,6 +1911,35 @@ bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) { return false; } +void HInvoke::SetIntrinsic(Intrinsics intrinsic, + IntrinsicNeedsEnvironmentOrCache needs_env_or_cache) { + intrinsic_ = intrinsic; + IntrinsicOptimizations opt(this); + if (needs_env_or_cache == kNoEnvironmentOrCache) { + opt.SetDoesNotNeedDexCache(); + opt.SetDoesNotNeedEnvironment(); + } +} + +bool HInvoke::NeedsEnvironment() const { + if (!IsIntrinsic()) { + return true; + } + IntrinsicOptimizations opt(*this); + return !opt.GetDoesNotNeedEnvironment(); +} + +bool HInvokeStaticOrDirect::NeedsDexCacheOfDeclaringClass() const { + if (GetMethodLoadKind() != MethodLoadKind::kDexCacheViaMethod) { + return false; + } + if (!IsIntrinsic()) { + return true; + } + IntrinsicOptimizations opt(*this); + return !opt.GetDoesNotNeedDexCache(); +} + void HInstruction::RemoveEnvironmentUsers() { for (HUseIterator<HEnvironment*> use_it(GetEnvUses()); !use_it.Done(); use_it.Advance()) { HUseListNode<HEnvironment*>* user_node = use_it.Current(); |