diff options
Diffstat (limited to 'compiler/optimizing/nodes.cc')
| -rw-r--r-- | compiler/optimizing/nodes.cc | 294 |
1 files changed, 200 insertions, 94 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 1afa36a89c..150d6b029b 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -56,9 +56,11 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) { // Nodes that we're currently visiting, indexed by block id. ArenaBitVector visiting(arena_, blocks_.size(), false, kArenaAllocGraphBuilder); // Number of successors visited from a given node, indexed by block id. - ArenaVector<size_t> successors_visited(blocks_.size(), 0u, arena_->Adapter()); + ArenaVector<size_t> successors_visited(blocks_.size(), + 0u, + arena_->Adapter(kArenaAllocGraphBuilder)); // Stack of nodes that we're currently visiting (same as marked in "visiting" above). - ArenaVector<HBasicBlock*> worklist(arena_->Adapter()); + ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder)); constexpr size_t kDefaultWorklistSize = 8; worklist.reserve(kDefaultWorklistSize); visited->SetBit(entry_block_->GetBlockId()); @@ -99,10 +101,7 @@ static void RemoveEnvironmentUses(HInstruction* instruction) { } static void RemoveAsUser(HInstruction* instruction) { - for (size_t i = 0; i < instruction->InputCount(); i++) { - instruction->RemoveAsUserOfInput(i); - } - + instruction->RemoveAsUserOfAllInputs(); RemoveEnvironmentUses(instruction); } @@ -206,17 +205,35 @@ HInstruction* HBasicBlock::GetFirstInstructionDisregardMoves() const { return instruction; } +static bool UpdateDominatorOfSuccessor(HBasicBlock* block, HBasicBlock* successor) { + DCHECK(ContainsElement(block->GetSuccessors(), successor)); + + HBasicBlock* old_dominator = successor->GetDominator(); + HBasicBlock* new_dominator = + (old_dominator == nullptr) ? block + : CommonDominator::ForPair(old_dominator, block); + + if (old_dominator == new_dominator) { + return false; + } else { + successor->SetDominator(new_dominator); + return true; + } +} + void HGraph::ComputeDominanceInformation() { DCHECK(reverse_post_order_.empty()); reverse_post_order_.reserve(blocks_.size()); reverse_post_order_.push_back(entry_block_); // Number of visits of a given node, indexed by block id. - ArenaVector<size_t> visits(blocks_.size(), 0u, arena_->Adapter()); + ArenaVector<size_t> visits(blocks_.size(), 0u, arena_->Adapter(kArenaAllocGraphBuilder)); // Number of successors visited from a given node, indexed by block id. - ArenaVector<size_t> successors_visited(blocks_.size(), 0u, arena_->Adapter()); + ArenaVector<size_t> successors_visited(blocks_.size(), + 0u, + arena_->Adapter(kArenaAllocGraphBuilder)); // Nodes for which we need to visit successors. - ArenaVector<HBasicBlock*> worklist(arena_->Adapter()); + ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder)); constexpr size_t kDefaultWorklistSize = 8; worklist.reserve(kDefaultWorklistSize); worklist.push_back(entry_block_); @@ -228,15 +245,7 @@ void HGraph::ComputeDominanceInformation() { worklist.pop_back(); } else { HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++]; - - if (successor->GetDominator() == nullptr) { - successor->SetDominator(current); - } else { - // The CommonDominator can work for multiple blocks as long as the - // domination information doesn't change. However, since we're changing - // that information here, we can use the finder only for pairs of blocks. - successor->SetDominator(CommonDominator::ForPair(successor->GetDominator(), current)); - } + UpdateDominatorOfSuccessor(current, successor); // Once all the forward edges have been visited, we know the immediate // dominator of the block. We can then start visiting its successors. @@ -248,6 +257,44 @@ void HGraph::ComputeDominanceInformation() { } } + // Check if the graph has back edges not dominated by their respective headers. + // If so, we need to update the dominators of those headers and recursively of + // their successors. We do that with a fix-point iteration over all blocks. + // The algorithm is guaranteed to terminate because it loops only if the sum + // of all dominator chains has decreased in the current iteration. + bool must_run_fix_point = false; + for (HBasicBlock* block : blocks_) { + if (block != nullptr && + block->IsLoopHeader() && + block->GetLoopInformation()->HasBackEdgeNotDominatedByHeader()) { + must_run_fix_point = true; + break; + } + } + if (must_run_fix_point) { + bool update_occurred = true; + while (update_occurred) { + update_occurred = false; + for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) { + HBasicBlock* block = it.Current(); + for (HBasicBlock* successor : block->GetSuccessors()) { + update_occurred |= UpdateDominatorOfSuccessor(block, successor); + } + } + } + } + + // Make sure that there are no remaining blocks whose dominator information + // needs to be updated. + if (kIsDebugBuild) { + for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) { + HBasicBlock* block = it.Current(); + for (HBasicBlock* successor : block->GetSuccessors()) { + DCHECK(!UpdateDominatorOfSuccessor(block, successor)); + } + } + } + // Populate `dominated_blocks_` information after computing all dominators. // The potential presence of irreducible loops requires to do it after. for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) { @@ -396,8 +443,10 @@ void HGraph::SimplifyCFG() { } GraphAnalysisResult HGraph::AnalyzeLoops() const { - // Order does not matter. - for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) { + // We iterate post order to ensure we visit inner loops before outer loops. + // `PopulateRecursive` needs this guarantee to know whether a natural loop + // contains an irreducible loop. + for (HPostOrderIterator it(*this); !it.Done(); it.Advance()) { HBasicBlock* block = it.Current(); if (block->IsLoopHeader()) { if (block->IsCatchBlock()) { @@ -530,6 +579,14 @@ void HLoopInformation::PopulateRecursive(HBasicBlock* block) { blocks_.SetBit(block->GetBlockId()); block->SetInLoop(this); + if (block->IsLoopHeader()) { + // We're visiting loops in post-order, so inner loops must have been + // populated already. + DCHECK(block->GetLoopInformation()->IsPopulated()); + if (block->GetLoopInformation()->IsIrreducible()) { + contains_irreducible_loop_ = true; + } + } for (HBasicBlock* predecessor : block->GetPredecessors()) { PopulateRecursive(predecessor); } @@ -595,20 +652,16 @@ void HLoopInformation::Populate() { blocks_.SetBit(header_->GetBlockId()); header_->SetInLoop(this); - bool is_irreducible_loop = false; - for (HBasicBlock* back_edge : GetBackEdges()) { - DCHECK(back_edge->GetDominator() != nullptr); - if (!header_->Dominates(back_edge)) { - is_irreducible_loop = true; - break; - } - } + bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader(); if (is_irreducible_loop) { ArenaBitVector visited(graph->GetArena(), graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGraphBuilder); + // Stop marking blocks at the loop header. + visited.SetBit(header_->GetBlockId()); + for (HBasicBlock* back_edge : GetBackEdges()) { PopulateIrreducibleRecursive(back_edge, &visited); } @@ -618,8 +671,26 @@ void HLoopInformation::Populate() { } } - if (is_irreducible_loop || graph->IsCompilingOsr()) { + if (!is_irreducible_loop && graph->IsCompilingOsr()) { + // When compiling in OSR mode, all loops in the compiled method may be entered + // from the interpreter. We treat this OSR entry point just like an extra entry + // to an irreducible loop, so we need to mark the method's loops as irreducible. + // This does not apply to inlined loops which do not act as OSR entry points. + if (suspend_check_ == nullptr) { + // Just building the graph in OSR mode, this loop is not inlined. We never build an + // inner graph in OSR mode as we can do OSR transition only from the outer method. + is_irreducible_loop = true; + } else { + // Look at the suspend check's environment to determine if the loop was inlined. + DCHECK(suspend_check_->HasEnvironment()); + if (!suspend_check_->GetEnvironment()->IsFromInlinedInvoke()) { + is_irreducible_loop = true; + } + } + } + if (is_irreducible_loop) { irreducible_ = true; + contains_irreducible_loop_ = true; graph->SetHasIrreducibleLoops(true); } } @@ -650,6 +721,25 @@ size_t HLoopInformation::GetLifetimeEnd() const { return last_position; } +bool HLoopInformation::HasBackEdgeNotDominatedByHeader() const { + for (HBasicBlock* back_edge : GetBackEdges()) { + DCHECK(back_edge->GetDominator() != nullptr); + if (!header_->Dominates(back_edge)) { + return true; + } + } + return false; +} + +bool HLoopInformation::DominatesAllBackEdges(HBasicBlock* block) { + for (HBasicBlock* back_edge : GetBackEdges()) { + if (!block->Dominates(back_edge)) { + return false; + } + } + return true; +} + bool HBasicBlock::Dominates(HBasicBlock* other) const { // Walk up the dominator tree from `other`, to find out if `this` // is an ancestor. @@ -664,8 +754,9 @@ bool HBasicBlock::Dominates(HBasicBlock* other) const { } static void UpdateInputsUsers(HInstruction* instruction) { - for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { - instruction->InputAt(i)->AddUseAt(instruction, i); + auto&& inputs = instruction->GetInputs(); + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->AddUseAt(instruction, i); } // Environment should be created later. DCHECK(!instruction->HasEnvironment()); @@ -681,8 +772,8 @@ void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial, 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()); + DCHECK(initial->GetUses().empty()); + DCHECK(initial->GetEnvUses().empty()); replacement->SetBlock(this); replacement->SetId(GetGraph()->GetNextInstructionId()); instructions_.InsertInstructionBefore(replacement, initial); @@ -774,8 +865,8 @@ static void Remove(HInstructionList* instruction_list, instruction->SetBlock(nullptr); instruction_list->RemoveInstruction(instruction); if (ensure_safety) { - DCHECK(instruction->GetUses().IsEmpty()); - DCHECK(instruction->GetEnvUses().IsEmpty()); + DCHECK(instruction->GetUses().empty()); + DCHECK(instruction->GetEnvUses().empty()); RemoveAsUser(instruction); } } @@ -839,8 +930,11 @@ void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env, } void HEnvironment::RemoveAsUserOfInput(size_t index) const { - const HUserRecord<HEnvironment*>& user_record = vregs_[index]; - user_record.GetInstruction()->RemoveEnvironmentUser(user_record.GetUseNode()); + const HUserRecord<HEnvironment*>& env_use = vregs_[index]; + HInstruction* user = env_use.GetInstruction(); + auto before_env_use_node = env_use.GetBeforeUseNode(); + user->env_uses_.erase_after(before_env_use_node); + user->FixUpUserRecordsAfterEnvUseRemoval(before_env_use_node); } HInstruction::InstructionKind HInstruction::GetKind() const { @@ -985,30 +1079,36 @@ void HInstruction::RemoveEnvironment() { void HInstruction::ReplaceWith(HInstruction* other) { DCHECK(other != nullptr); - for (HUseIterator<HInstruction*> it(GetUses()); !it.Done(); it.Advance()) { - HUseListNode<HInstruction*>* current = it.Current(); - HInstruction* user = current->GetUser(); - size_t input_index = current->GetIndex(); - user->SetRawInputAt(input_index, other); - other->AddUseAt(user, input_index); - } + // Note: fixup_end remains valid across splice_after(). + auto fixup_end = other->uses_.empty() ? other->uses_.begin() : ++other->uses_.begin(); + other->uses_.splice_after(other->uses_.before_begin(), uses_); + other->FixUpUserRecordsAfterUseInsertion(fixup_end); - for (HUseIterator<HEnvironment*> it(GetEnvUses()); !it.Done(); it.Advance()) { - HUseListNode<HEnvironment*>* current = it.Current(); - HEnvironment* user = current->GetUser(); - size_t input_index = current->GetIndex(); - user->SetRawEnvAt(input_index, other); - other->AddEnvUseAt(user, input_index); - } + // Note: env_fixup_end remains valid across splice_after(). + auto env_fixup_end = + other->env_uses_.empty() ? other->env_uses_.begin() : ++other->env_uses_.begin(); + other->env_uses_.splice_after(other->env_uses_.before_begin(), env_uses_); + other->FixUpUserRecordsAfterEnvUseInsertion(env_fixup_end); - uses_.Clear(); - env_uses_.Clear(); + DCHECK(uses_.empty()); + DCHECK(env_uses_.empty()); } void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) { - RemoveAsUserOfInput(index); - SetRawInputAt(index, replacement); - replacement->AddUseAt(this, index); + HUserRecord<HInstruction*> input_use = InputRecordAt(index); + if (input_use.GetInstruction() == replacement) { + // Nothing to do. + return; + } + HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode(); + // Note: fixup_end remains valid across splice_after(). + auto fixup_end = + replacement->uses_.empty() ? replacement->uses_.begin() : ++replacement->uses_.begin(); + replacement->uses_.splice_after(replacement->uses_.before_begin(), + input_use.GetInstruction()->uses_, + before_use_node); + replacement->FixUpUserRecordsAfterUseInsertion(fixup_end); + input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node); } size_t HInstruction::EnvironmentSize() const { @@ -1024,9 +1124,10 @@ void HPhi::AddInput(HInstruction* input) { void HPhi::RemoveInputAt(size_t index) { RemoveAsUserOfInput(index); inputs_.erase(inputs_.begin() + index); - for (size_t i = index, e = InputCount(); i < e; ++i) { - DCHECK_EQ(InputRecordAt(i).GetUseNode()->GetIndex(), i + 1u); - InputRecordAt(i).GetUseNode()->SetIndex(i); + // Update indexes in use nodes of inputs that have been pulled forward by the erase(). + for (size_t i = index, e = inputs_.size(); i < e; ++i) { + DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i + 1u); + inputs_[i].GetUseNode()->SetIndex(i); } } @@ -1222,16 +1323,18 @@ bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const { return this == instruction->GetPreviousDisregardingMoves(); } -bool HInstruction::Equals(HInstruction* other) const { +bool HInstruction::Equals(const HInstruction* other) const { if (!InstructionTypeEquals(other)) return false; DCHECK_EQ(GetKind(), other->GetKind()); if (!InstructionDataEquals(other)) return false; if (GetType() != other->GetType()) return false; - if (InputCount() != other->InputCount()) return false; - - for (size_t i = 0, e = InputCount(); i < e; ++i) { - if (InputAt(i) != other->InputAt(i)) return false; + auto&& inputs = GetInputs(); + auto&& other_inputs = other->GetInputs(); + if (inputs.size() != other_inputs.size()) return false; + for (size_t i = 0; i != inputs.size(); ++i) { + if (inputs[i] != other_inputs[i]) return false; } + DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode()); return true; } @@ -1280,17 +1383,18 @@ void HInstruction::MoveBeforeFirstUserAndOutOfLoops() { DCHECK_EQ(InputCount(), 0u); // Find the target block. - HUseIterator<HInstruction*> uses_it(GetUses()); - HBasicBlock* target_block = uses_it.Current()->GetUser()->GetBlock(); - uses_it.Advance(); - while (!uses_it.Done() && uses_it.Current()->GetUser()->GetBlock() == target_block) { - uses_it.Advance(); - } - if (!uses_it.Done()) { + auto uses_it = GetUses().begin(); + auto uses_end = GetUses().end(); + HBasicBlock* target_block = uses_it->GetUser()->GetBlock(); + ++uses_it; + while (uses_it != uses_end && uses_it->GetUser()->GetBlock() == target_block) { + ++uses_it; + } + if (uses_it != uses_end) { // This instruction has uses in two or more blocks. Find the common dominator. CommonDominator finder(target_block); - for (; !uses_it.Done(); uses_it.Advance()) { - finder.Update(uses_it.Current()->GetUser()->GetBlock()); + for (; uses_it != uses_end; ++uses_it) { + finder.Update(uses_it->GetUser()->GetBlock()); } target_block = finder.Get(); DCHECK(target_block != nullptr); @@ -1303,10 +1407,10 @@ void HInstruction::MoveBeforeFirstUserAndOutOfLoops() { // Find insertion position. HInstruction* insert_pos = nullptr; - for (HUseIterator<HInstruction*> uses_it2(GetUses()); !uses_it2.Done(); uses_it2.Advance()) { - if (uses_it2.Current()->GetUser()->GetBlock() == target_block && - (insert_pos == nullptr || uses_it2.Current()->GetUser()->StrictlyDominates(insert_pos))) { - insert_pos = uses_it2.Current()->GetUser(); + for (const HUseListNode<HInstruction*>& use : GetUses()) { + if (use.GetUser()->GetBlock() == target_block && + (insert_pos == nullptr || use.GetUser()->StrictlyDominates(insert_pos))) { + insert_pos = use.GetUser(); } } if (insert_pos == nullptr) { @@ -1586,10 +1690,10 @@ void HInstructionList::Add(const HInstructionList& instruction_list) { static void RemoveUsesOfDeadInstruction(HInstruction* insn) { DCHECK(!insn->HasEnvironmentUses()); while (insn->HasNonEnvironmentUses()) { - HUseListNode<HInstruction*>* use = insn->GetUses().GetFirst(); - size_t use_index = use->GetIndex(); - HBasicBlock* user_block = use->GetUser()->GetBlock(); - DCHECK(use->GetUser()->IsPhi() && user_block->IsCatchBlock()); + const HUseListNode<HInstruction*>& use = insn->GetUses().front(); + size_t use_index = use.GetIndex(); + HBasicBlock* user_block = use.GetUser()->GetBlock(); + DCHECK(use.GetUser()->IsPhi() && user_block->IsCatchBlock()); for (HInstructionIterator phi_it(user_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) { phi_it.Current()->AsPhi()->RemoveInputAt(use_index); } @@ -2190,6 +2294,8 @@ ReferenceTypeInfo ReferenceTypeInfo::Create(TypeHandle type_handle, bool is_exac if (kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); DCHECK(IsValidHandle(type_handle)); + DCHECK(!type_handle->IsErroneous()); + DCHECK(!type_handle->IsArrayClass() || !type_handle->GetComponentType()->IsErroneous()); if (!is_exact) { DCHECK(!type_handle->CannotBeAssignedFromOtherTypes()) << "Callers of ReferenceTypeInfo::Create should ensure is_exact is properly computed"; @@ -2287,9 +2393,9 @@ void HInvokeStaticOrDirect::InsertInputAt(size_t index, HInstruction* input) { inputs_.insert(inputs_.begin() + index, HUserRecord<HInstruction*>(input)); input->AddUseAt(this, index); // Update indexes in use nodes of inputs that have been pushed further back by the insert(). - for (size_t i = index + 1u, size = inputs_.size(); i != size; ++i) { - DCHECK_EQ(InputRecordAt(i).GetUseNode()->GetIndex(), i - 1u); - InputRecordAt(i).GetUseNode()->SetIndex(i); + for (size_t i = index + 1u, e = inputs_.size(); i < e; ++i) { + DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i - 1u); + inputs_[i].GetUseNode()->SetIndex(i); } } @@ -2297,9 +2403,9 @@ void HInvokeStaticOrDirect::RemoveInputAt(size_t index) { RemoveAsUserOfInput(index); inputs_.erase(inputs_.begin() + index); // Update indexes in use nodes of inputs that have been pulled forward by the erase(). - for (size_t i = index, e = InputCount(); i < e; ++i) { - DCHECK_EQ(InputRecordAt(i).GetUseNode()->GetIndex(), i + 1u); - InputRecordAt(i).GetUseNode()->SetIndex(i); + for (size_t i = index, e = inputs_.size(); i < e; ++i) { + DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i + 1u); + inputs_[i].GetUseNode()->SetIndex(i); } } @@ -2337,8 +2443,8 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckReq } } -bool HLoadString::InstructionDataEquals(HInstruction* other) const { - HLoadString* other_load_string = other->AsLoadString(); +bool HLoadString::InstructionDataEquals(const HInstruction* other) const { + const HLoadString* other_load_string = other->AsLoadString(); if (string_index_ != other_load_string->string_index_ || GetPackedFields() != other_load_string->GetPackedFields()) { return false; @@ -2367,6 +2473,7 @@ void HLoadString::SetLoadKindInternal(LoadKind load_kind) { } if (!NeedsEnvironment()) { RemoveEnvironment(); + SetSideEffects(SideEffects::None()); } } @@ -2391,12 +2498,11 @@ std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs) { } void HInstruction::RemoveEnvironmentUsers() { - for (HUseIterator<HEnvironment*> use_it(GetEnvUses()); !use_it.Done(); use_it.Advance()) { - HUseListNode<HEnvironment*>* user_node = use_it.Current(); - HEnvironment* user = user_node->GetUser(); - user->SetRawEnvAt(user_node->GetIndex(), nullptr); + for (const HUseListNode<HEnvironment*>& use : GetEnvUses()) { + HEnvironment* user = use.GetUser(); + user->SetRawEnvAt(use.GetIndex(), nullptr); } - env_uses_.Clear(); + env_uses_.clear(); } // Returns an instruction with the opposite Boolean value from 'cond'. |