Merge "Improved instruction + offset hunting."
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index ba1b168..a7a1c0f 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -67,20 +67,28 @@
   static bool IsAddOrSubAConstant(HInstruction* instruction,
                                   /* out */ HInstruction** left_instruction,
                                   /* out */ int32_t* right_constant) {
-    if (instruction->IsAdd() || instruction->IsSub()) {
+    HInstruction* left_so_far = nullptr;
+    int32_t right_so_far = 0;
+    while (instruction->IsAdd() || instruction->IsSub()) {
       HBinaryOperation* bin_op = instruction->AsBinaryOperation();
       HInstruction* left = bin_op->GetLeft();
       HInstruction* right = bin_op->GetRight();
       if (right->IsIntConstant()) {
-        *left_instruction = left;
-        int32_t c = right->AsIntConstant()->GetValue();
-        *right_constant = instruction->IsAdd() ? c : -c;
-        return true;
+        int32_t v = right->AsIntConstant()->GetValue();
+        int32_t c = instruction->IsAdd() ? v : -v;
+        if (!WouldAddOverflowOrUnderflow(right_so_far, c)) {
+          instruction = left;
+          left_so_far = left;
+          right_so_far += c;
+          continue;
+        }
       }
+      break;
     }
-    *left_instruction = nullptr;
-    *right_constant = 0;
-    return false;
+    // Return result: either false and "null+0" or true and "instr+constant".
+    *left_instruction = left_so_far;
+    *right_constant = right_so_far;
+    return left_so_far != nullptr;
   }
 
   // Expresses any instruction as a value bound.
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 31bb94c..32bbc5b 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -391,6 +391,36 @@
       array[base + 1] = 1;
   }
 
+  /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+
+  /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (after)
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+
+  static void constantIndexing10(int[] array, int base) {
+    // Offset hidden in incremented base.
+    array[base] = 1;
+    array[++base] = 2;
+    array[++base] = 3;
+    array[++base] = 4;
+  }
+
   static void runAllConstantIndices() {
     int[] a1 = { 0 };
     int[] a6 = { 0, 0, 0, 0, 0, 0 };
@@ -502,6 +532,12 @@
         a6[3] != 3 || a6[4] != 40 || a6[5] != 10) {
       System.out.println("constant indices 9 failed!");
     }
+
+    constantIndexing10(a6, 0);
+    if (a6[0] != 1 || a6[1] != 2  || a6[2] != 3  ||
+        a6[3] != 4 || a6[4] != 40 || a6[5] != 10) {
+      System.out.println("constant indices 10 failed!");
+    }
   }
 
   // A helper into which the actual throwing function should be inlined.