ART: Fix loop information after dead code elimination
Compilation failed when only some blocks of a loop were removed during
dead code elimination.
Bug: 20680703
Change-Id: If31025169ca493f0d7f7f2788576e98d05f03394
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 91cd60a..cd427c5 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -65,10 +65,13 @@
for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
if (live_blocks.IsBitSet(block->GetBlockId())) {
- continue;
+ // If this block is part of a loop that is being dismantled, we need to
+ // update its loop information.
+ block->UpdateLoopInformation();
+ } else {
+ MaybeRecordDeadBlock(block);
+ block->DisconnectAndDelete();
}
- MaybeRecordDeadBlock(block);
- block->DisconnectAndDelete();
}
// Connect successive blocks created by dead branches. Order does not matter.
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 699987c..f07f4c7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -376,7 +376,6 @@
}
HBasicBlock* HLoopInformation::GetPreHeader() const {
- DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
return header_->GetDominator();
}
@@ -1038,6 +1037,20 @@
SetGraph(nullptr);
}
+void HBasicBlock::UpdateLoopInformation() {
+ // Check if loop information points to a dismantled loop. If so, replace with
+ // the loop information of a larger loop which contains this block, or nullptr
+ // otherwise. We iterate in case the larger loop has been destroyed too.
+ while (IsInLoop() && loop_information_->GetBackEdges().IsEmpty()) {
+ if (IsLoopHeader()) {
+ HSuspendCheck* suspend_check = loop_information_->GetSuspendCheck();
+ DCHECK_EQ(suspend_check->GetBlock(), this);
+ RemoveInstruction(suspend_check);
+ }
+ loop_information_ = loop_information_->GetPreHeader()->GetLoopInformation();
+ }
+}
+
void HBasicBlock::MergeWith(HBasicBlock* other) {
DCHECK_EQ(GetGraph(), other->GetGraph());
DCHECK(GetDominatedBlocks().Contains(other));
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3fe23e1..25ef780 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -636,7 +636,7 @@
void RemoveInstructionOrPhi(HInstruction* instruction, bool ensure_safety = true);
bool IsLoopHeader() const {
- return (loop_information_ != nullptr) && (loop_information_->GetHeader() == this);
+ return IsInLoop() && (loop_information_->GetHeader() == this);
}
bool IsLoopPreHeaderFirstPredecessor() const {
@@ -655,7 +655,7 @@
void SetInLoop(HLoopInformation* info) {
if (IsLoopHeader()) {
// Nothing to do. This just means `info` is an outer loop.
- } else if (loop_information_ == nullptr) {
+ } else if (!IsInLoop()) {
loop_information_ = info;
} else if (loop_information_->Contains(*info->GetHeader())) {
// Block is currently part of an outer loop. Make it part of this inner loop.
@@ -674,6 +674,11 @@
loop_information_ = info;
}
+ // Checks if the loop information points to a valid loop. If the loop has been
+ // dismantled (does not have a back edge any more), loop information is
+ // removed or replaced with the information of the first valid outer loop.
+ void UpdateLoopInformation();
+
bool IsInLoop() const { return loop_information_ != nullptr; }
// Returns wheter this block dominates the blocked passed as parameter.
@@ -727,7 +732,7 @@
void Advance() {
DCHECK(!Done());
- current_ = current_->GetHeader()->GetDominator()->GetLoopInformation();
+ current_ = current_->GetPreHeader()->GetLoopInformation();
}
HLoopInformation* Current() const {