ART: ArrayGet hoisting restriction added.

Currently if we hoist ArrayGet from loop there is no guarantee
that insn will be executed at runtime. Because of that we could
face issues like crashes in generated code.

This patch introduces restriction for ArrayGet hoisting. We say
that ArrayGet execution is guaranteed at least one time if its bb
dominates all exit blocks.

Signed-off-by: Anton Shamin <anton.shamin@intel.com>

(cherry picked from commit f89381fed12faf96c45a83a989ae2fff82c05f3b)

BUG=29145171

Change-Id: Ia5664dedb1543d78a7b4038801b8372572f069f6
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index b65e98a..f0c4eaf 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1154,7 +1154,11 @@
           loop->IsDefinedOutOfTheLoop(array_get->InputAt(1))) {
         SideEffects loop_effects = side_effects_.GetLoopEffects(loop->GetHeader());
         if (!array_get->GetSideEffects().MayDependOn(loop_effects)) {
-          HoistToPreHeaderOrDeoptBlock(loop, array_get);
+          // We can hoist ArrayGet only if its execution is guaranteed on every iteration.
+          // In other words only if array_get_bb dominates all back branches.
+          if (loop->DominatesAllBackEdges(array_get->GetBlock())) {
+            HoistToPreHeaderOrDeoptBlock(loop, array_get);
+          }
         }
       }
     }
@@ -1379,13 +1383,7 @@
       }
       // Does the current basic block dominate all back edges? If not,
       // don't apply dynamic bce to something that may not be executed.
-      for (HBasicBlock* back_edge : loop->GetBackEdges()) {
-        if (!block->Dominates(back_edge)) {
-          return false;
-        }
-      }
-      // Success!
-      return true;
+      return loop->DominatesAllBackEdges(block);
     }
     return false;
   }
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 60329cc..f4d3842 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -734,6 +734,15 @@
   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.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6960ceb..f3915a2 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -733,6 +733,8 @@
     return blocks_.GetHighestBitSet() != -1;
   }
 
+  bool DominatesAllBackEdges(HBasicBlock* block);
+
  private:
   // Internal recursive implementation of `Populate`.
   void PopulateRecursive(HBasicBlock* block);
diff --git a/test/562-bce-preheader/src/Main.java b/test/562-bce-preheader/src/Main.java
index 8b527b4..4397f67 100644
--- a/test/562-bce-preheader/src/Main.java
+++ b/test/562-bce-preheader/src/Main.java
@@ -90,6 +90,25 @@
     return a;
   }
 
+  /**
+   * Example shows that we can hoist ArrayGet to pre-header only if
+   * its execution is guaranteed.
+   */
+  public static int hoistcheck(int[] c) {
+    int i = 0, i2 = 0, i3 = 0, k = 0;
+    int n = c.length;
+    for (i = -100000000; i < 20; i += 10000000) {
+      i3 = i;
+      i2 = 0;
+      while (i2++ < 1) {
+        if (i3 >= 0 && i3 < n) {
+          k += c[i3];
+        }
+      }
+    }
+    return k;
+  }
+
   public static void main(String args[]) {
     int[][] x = new int[2][2];
     int y;
@@ -119,6 +138,9 @@
     int[] z = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     expectEquals(10, doit(z));
 
+    int c[] = { 1, 2, 3, 5 };
+    expectEquals(1, hoistcheck(c));
+
     System.out.println("passed");
   }