summaryrefslogtreecommitdiff
path: root/compiler/optimizing/nodes.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/nodes.cc')
-rw-r--r--compiler/optimizing/nodes.cc134
1 files changed, 125 insertions, 9 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index a90ebced69..6009cb50cd 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -185,7 +185,7 @@ void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
if (successor->IsLoopHeader()) {
// If we split at a back edge boundary, make the new block the back edge.
HLoopInformation* info = successor->GetLoopInformation();
- if (info->IsBackEdge(block)) {
+ if (info->IsBackEdge(*block)) {
info->RemoveBackEdge(block);
info->AddBackEdge(new_block);
}
@@ -287,19 +287,49 @@ bool HGraph::AnalyzeNaturalLoops() const {
return true;
}
+void HGraph::AddConstant(HConstant* instruction) {
+ HInstruction* last_instruction = entry_block_->GetLastInstruction();
+ if (last_instruction == nullptr || !last_instruction->IsControlFlow()) {
+ // Called from the builder. Insert at the end of the block.
+ entry_block_->AddInstruction(instruction);
+ } else {
+ // Entry block ends with control-flow. Insert before the last instruction.
+ entry_block_->InsertInstructionBefore(instruction, last_instruction);
+ }
+}
+
HNullConstant* HGraph::GetNullConstant() {
if (cached_null_constant_ == nullptr) {
cached_null_constant_ = new (arena_) HNullConstant();
- entry_block_->InsertInstructionBefore(cached_null_constant_,
- entry_block_->GetLastInstruction());
+ AddConstant(cached_null_constant_);
}
return cached_null_constant_;
}
+HIntConstant* HGraph::GetIntConstant0() {
+ if (cached_int_constant0_ == nullptr) {
+ cached_int_constant0_ = new (arena_) HIntConstant(0);
+ AddConstant(cached_int_constant0_);
+ }
+ return cached_int_constant0_;
+}
+
+HIntConstant* HGraph::GetIntConstant1() {
+ if (cached_int_constant1_ == nullptr) {
+ cached_int_constant1_ = new (arena_) HIntConstant(1);
+ AddConstant(cached_int_constant1_);
+ }
+ return cached_int_constant1_;
+}
+
void HLoopInformation::Add(HBasicBlock* block) {
blocks_.SetBit(block->GetBlockId());
}
+void HLoopInformation::Remove(HBasicBlock* block) {
+ blocks_.ClearBit(block->GetBlockId());
+}
+
void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
if (blocks_.IsBitSet(block->GetBlockId())) {
return;
@@ -621,7 +651,10 @@ FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
void HGraphVisitor::VisitInsertionOrder() {
const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
for (size_t i = 0 ; i < blocks.Size(); i++) {
- VisitBasicBlock(blocks.Get(i));
+ HBasicBlock* block = blocks.Get(i);
+ if (block != nullptr) {
+ VisitBasicBlock(block);
+ }
}
}
@@ -788,6 +821,17 @@ HBasicBlock* HBasicBlock::SplitAfter(HInstruction* cursor) {
return new_block;
}
+bool HBasicBlock::IsSingleGoto() const {
+ HLoopInformation* loop_info = GetLoopInformation();
+ // TODO: Remove the null check b/19084197.
+ return GetFirstInstruction() != nullptr
+ && GetPhis().IsEmpty()
+ && GetFirstInstruction() == GetLastInstruction()
+ && GetLastInstruction()->IsGoto()
+ // Back edges generate the suspend check.
+ && (loop_info == nullptr || !loop_info->IsBackEdge(*this));
+}
+
void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const {
for (HInstruction* current = first_instruction_;
current != nullptr;
@@ -811,14 +855,35 @@ void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& in
}
void HInstructionList::Add(const HInstructionList& instruction_list) {
- DCHECK(!IsEmpty());
- AddAfter(last_instruction_, instruction_list);
+ if (IsEmpty()) {
+ first_instruction_ = instruction_list.first_instruction_;
+ last_instruction_ = instruction_list.last_instruction_;
+ } else {
+ AddAfter(last_instruction_, instruction_list);
+ }
+}
+
+void HBasicBlock::DisconnectFromAll() {
+ DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented scenario";
+
+ for (size_t i = 0, e = predecessors_.Size(); i < e; ++i) {
+ predecessors_.Get(i)->successors_.Delete(this);
+ }
+ for (size_t i = 0, e = successors_.Size(); i < e; ++i) {
+ successors_.Get(i)->predecessors_.Delete(this);
+ }
+ dominator_->dominated_blocks_.Delete(this);
+
+ predecessors_.Reset();
+ successors_.Reset();
+ dominator_ = nullptr;
+ graph_ = nullptr;
}
void HBasicBlock::MergeWith(HBasicBlock* other) {
DCHECK(successors_.IsEmpty()) << "Unimplemented block merge scenario";
- DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented block merge scenario";
- DCHECK(other->GetDominator()->IsEntryBlock() && other->GetGraph() != graph_)
+ DCHECK(dominated_blocks_.IsEmpty()
+ || (dominated_blocks_.Size() == 1 && dominated_blocks_.Get(0) == other))
<< "Unimplemented block merge scenario";
DCHECK(other->GetPhis().IsEmpty());
@@ -1006,7 +1071,7 @@ void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
if (info != nullptr) {
info->Add(to);
to->SetLoopInformation(info);
- if (info->IsBackEdge(at)) {
+ if (info->IsBackEdge(*at)) {
// Only `at` can become a back edge, as the inlined blocks
// are predecessors of `at`.
DCHECK_EQ(1u, info->NumberOfBackEdges());
@@ -1020,6 +1085,57 @@ void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
invoke->GetBlock()->RemoveInstruction(invoke);
}
+void HGraph::MergeEmptyBranches(HBasicBlock* start_block, HBasicBlock* end_block) {
+ // Make sure this is a diamond control-flow path, find the two branches.
+ DCHECK_EQ(start_block->GetSuccessors().Size(), 2u);
+ DCHECK_EQ(end_block->GetPredecessors().Size(), 2u);
+ HBasicBlock* left_branch = start_block->GetSuccessors().Get(0);
+ HBasicBlock* right_branch = start_block->GetSuccessors().Get(1);
+ DCHECK_EQ(left_branch->GetSuccessors().Get(0), end_block);
+ DCHECK_EQ(right_branch->GetSuccessors().Get(0), end_block);
+ DCHECK_EQ(start_block, end_block->GetDominator());
+
+ // Disconnect the branches and merge the two blocks. This will move
+ // all instructions from 'end_block' to 'start_block'.
+ DCHECK(left_branch->IsSingleGoto());
+ DCHECK(right_branch->IsSingleGoto());
+ left_branch->DisconnectFromAll();
+ right_branch->DisconnectFromAll();
+ start_block->RemoveInstruction(start_block->GetLastInstruction());
+ start_block->MergeWith(end_block);
+
+ // Delete the now redundant blocks from the graph.
+ blocks_.Put(left_branch->GetBlockId(), nullptr);
+ blocks_.Put(right_branch->GetBlockId(), nullptr);
+ blocks_.Put(end_block->GetBlockId(), nullptr);
+
+ // Update reverse post order.
+ reverse_post_order_.Delete(left_branch);
+ reverse_post_order_.Delete(right_branch);
+ reverse_post_order_.Delete(end_block);
+
+ // Update loop information.
+ HLoopInformation* loop_info = start_block->GetLoopInformation();
+ if (kIsDebugBuild) {
+ if (loop_info != nullptr) {
+ DCHECK_EQ(loop_info, left_branch->GetLoopInformation());
+ DCHECK_EQ(loop_info, right_branch->GetLoopInformation());
+ DCHECK_EQ(loop_info, end_block->GetLoopInformation());
+ }
+ }
+ while (loop_info != nullptr) {
+ loop_info->Remove(left_branch);
+ loop_info->Remove(right_branch);
+ loop_info->Remove(end_block);
+ if (loop_info->IsBackEdge(*end_block)) {
+ loop_info->RemoveBackEdge(end_block);
+ loop_info->AddBackEdge(start_block);
+ }
+ // Move to parent loop if nested.
+ loop_info = loop_info->GetHeader()->GetDominator()->GetLoopInformation();
+ }
+}
+
std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs) {
ScopedObjectAccess soa(Thread::Current());
os << "["