bce: handle a pattern for circular buffer

Change-Id: Ie54bdd7c044af58deea0d0addaaa8186cabf3532
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 811a3bd..deaeb8e 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -823,6 +823,21 @@
     FindAndHandlePartialArrayLength(ushr);
   }
 
+  void VisitAnd(HAnd* instruction) {
+    if (instruction->GetRight()->IsIntConstant()) {
+      int32_t constant = instruction->GetRight()->AsIntConstant()->GetValue();
+      if (constant > 0) {
+        // constant serves as a mask so any number masked with it
+        // gets a [0, constant] value range.
+        ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+            GetGraph()->GetArena(),
+            ValueBound(nullptr, 0),
+            ValueBound(nullptr, constant));
+        GetValueRangeMap(instruction->GetBlock())->Overwrite(instruction->GetId(), range);
+      }
+    }
+  }
+
   void VisitNewArray(HNewArray* new_array) {
     HInstruction* len = new_array->InputAt(0);
     if (!len->IsIntConstant()) {
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index ad4092b..ebd5b0e 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -314,6 +314,29 @@
     array[10] = 1; // Bounds check can't be eliminated.
   }
 
+
+  static byte readData() {
+    return 1;
+  }
+
+  // CHECK-START: void Main.circularBufferProducer() BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.circularBufferProducer() BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void circularBufferProducer() {
+    byte[] array = new byte[4096];
+    int i = 0;
+    while (true) {
+      array[i & (array.length - 1)] = readData();
+      i++;
+    }
+  }
+
+
   // CHECK-START: void Main.pyramid1(int[]) BCE (before)
   // CHECK: BoundsCheck
   // CHECK: ArraySet