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 {