Merge "Avoid unaligned accesses (SIGBUG/BUS_ADRALN) in IRT."
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index ae9974d..811a3bd 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -32,14 +32,7 @@
     if (instruction != nullptr && instruction->IsIntConstant()) {
       // Normalize ValueBound with constant instruction.
       int32_t instr_const = instruction->AsIntConstant()->GetValue();
-      if (constant >= 0 && (instr_const <= INT_MAX - constant)) {
-        // No overflow.
-        instruction_ = nullptr;
-        constant_ = instr_const + constant;
-        return;
-      }
-      if (constant < 0 && (instr_const >= INT_MIN - constant)) {
-        // No underflow.
+      if (!WouldAddOverflowOrUnderflow(instr_const, constant)) {
         instruction_ = nullptr;
         constant_ = instr_const + constant;
         return;
@@ -49,6 +42,22 @@
     constant_ = constant;
   }
 
+  // Return whether (left + right) overflows or underflows.
+  static bool WouldAddOverflowOrUnderflow(int32_t left, int32_t right) {
+    if (right == 0) {
+      return false;
+    }
+    if ((right > 0) && (left <= INT_MAX - right)) {
+      // No overflow.
+      return false;
+    }
+    if ((right < 0) && (left >= INT_MIN - right)) {
+      // No underflow.
+      return false;
+    }
+    return true;
+  }
+
   static bool IsAddOrSubAConstant(HInstruction* instruction,
                                   HInstruction** left_instruction,
                                   int* right_constant) {
@@ -463,10 +472,23 @@
   // Narrow the value range of `instruction` at the end of `basic_block` with `range`,
   // and push the narrowed value range to `successor`.
   void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
-                  HBasicBlock* successor, ValueRange* range) {
+                                HBasicBlock* successor, ValueRange* range) {
     ValueRange* existing_range = LookupValueRange(instruction, basic_block);
-    ValueRange* narrowed_range = (existing_range == nullptr) ?
-        range : existing_range->Narrow(range);
+    if (existing_range == nullptr) {
+      if (range != nullptr) {
+        GetValueRangeMap(successor)->Overwrite(instruction->GetId(), range);
+      }
+      return;
+    }
+    if (existing_range->IsMonotonicValueRange()) {
+      DCHECK(instruction->IsLoopHeaderPhi());
+      // Make sure the comparison is in the loop header so each increment is
+      // checked with a comparison.
+      if (instruction->GetBlock() != basic_block) {
+        return;
+      }
+    }
+    ValueRange* narrowed_range = existing_range->Narrow(range);
     if (narrowed_range != nullptr) {
       GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
     }
@@ -705,6 +727,15 @@
     // Here we are interested in the typical triangular case of nested loops,
     // such as the inner loop 'for (int j=0; j<array.length-i; j++)' where i
     // is the index for outer loop. In this case, we know j is bounded by array.length-1.
+
+    // Try to handle (array.length - i) or (array.length + c - i) format.
+    HInstruction* left_of_left;  // left input of left.
+    int32_t right_const = 0;
+    if (ValueBound::IsAddOrSubAConstant(left, &left_of_left, &right_const)) {
+      left = left_of_left;
+    }
+    // The value of left input of the sub equals (left + right_const).
+
     if (left->IsArrayLength()) {
       HInstruction* array_length = left->AsArrayLength();
       ValueRange* right_range = LookupValueRange(right, sub->GetBlock());
@@ -715,19 +746,83 @@
           HInstruction* upper_inst = upper.GetInstruction();
           // Make sure it's the same array.
           if (ValueBound::Equal(array_length, upper_inst)) {
-            // (array.length - v) where v is in [c1, array.length + c2]
-            // gets [-c2, array.length - c1] as its value range.
-            ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
-                GetGraph()->GetArena(),
-                ValueBound(nullptr, - upper.GetConstant()),
-                ValueBound(array_length, - lower.GetConstant()));
-            GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+            int32_t c0 = right_const;
+            int32_t c1 = lower.GetConstant();
+            int32_t c2 = upper.GetConstant();
+            // (array.length + c0 - v) where v is in [c1, array.length + c2]
+            // gets [c0 - c2, array.length + c0 - c1] as its value range.
+            if (!ValueBound::WouldAddOverflowOrUnderflow(c0, -c2) &&
+                !ValueBound::WouldAddOverflowOrUnderflow(c0, -c1)) {
+              if ((c0 - c1) <= 0) {
+                // array.length + (c0 - c1) won't overflow/underflow.
+                ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+                    GetGraph()->GetArena(),
+                    ValueBound(nullptr, right_const - upper.GetConstant()),
+                    ValueBound(array_length, right_const - lower.GetConstant()));
+                GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+              }
+            }
           }
         }
       }
     }
   }
 
+  void FindAndHandlePartialArrayLength(HBinaryOperation* instruction) {
+    DCHECK(instruction->IsDiv() || instruction->IsShr() || instruction->IsUShr());
+    HInstruction* right = instruction->GetRight();
+    int32_t right_const;
+    if (right->IsIntConstant()) {
+      right_const = right->AsIntConstant()->GetValue();
+      // Detect division by two or more.
+      if ((instruction->IsDiv() && right_const <= 1) ||
+          (instruction->IsShr() && right_const < 1) ||
+          (instruction->IsUShr() && right_const < 1)) {
+        return;
+      }
+    } else {
+      return;
+    }
+
+    // Try to handle array.length/2 or (array.length-1)/2 format.
+    HInstruction* left = instruction->GetLeft();
+    HInstruction* left_of_left;  // left input of left.
+    int32_t c = 0;
+    if (ValueBound::IsAddOrSubAConstant(left, &left_of_left, &c)) {
+      left = left_of_left;
+    }
+    // The value of left input of instruction equals (left + c).
+
+    // (array_length + 1) or smaller divided by two or more
+    // always generate a value in [INT_MIN, array_length].
+    // This is true even if array_length is INT_MAX.
+    if (left->IsArrayLength() && c <= 1) {
+      if (instruction->IsUShr() && c < 0) {
+        // Make sure for unsigned shift, left side is not negative.
+        // e.g. if array_length is 2, ((array_length - 3) >>> 2) is way bigger
+        // than array_length.
+        return;
+      }
+      ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+          GetGraph()->GetArena(),
+          ValueBound(nullptr, INT_MIN),
+          ValueBound(left, 0));
+      GetValueRangeMap(instruction->GetBlock())->Overwrite(instruction->GetId(), range);
+    }
+  }
+
+  void VisitDiv(HDiv* div) {
+    FindAndHandlePartialArrayLength(div);
+  }
+
+  void VisitShr(HShr* shr) {
+    FindAndHandlePartialArrayLength(shr);
+  }
+
+  void VisitUShr(HUShr* ushr) {
+    FindAndHandlePartialArrayLength(ushr);
+  }
+
   void VisitNewArray(HNewArray* new_array) {
     HInstruction* len = new_array->InputAt(0);
     if (!len->IsIntConstant()) {
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 17cb8f3..a298413 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -400,7 +400,6 @@
   loop_body->AddSuccessor(loop_header);
 
   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
-  phi->AddInput(constant_initial);
   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
   HInstruction* array_length = new (allocator) HArrayLength(null_check);
   HInstruction* cmp = nullptr;
@@ -416,6 +415,7 @@
   loop_header->AddInstruction(array_length);
   loop_header->AddInstruction(cmp);
   loop_header->AddInstruction(if_inst);
+  phi->AddInput(constant_initial);
 
   null_check = new (allocator) HNullCheck(parameter, 0);
   array_length = new (allocator) HArrayLength(null_check);
@@ -544,7 +544,6 @@
   loop_body->AddSuccessor(loop_header);
 
   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
-  phi->AddInput(array_length);
   HInstruction* cmp = nullptr;
   if (cond == kCondLE) {
     cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
@@ -556,6 +555,7 @@
   loop_header->AddPhi(phi);
   loop_header->AddInstruction(cmp);
   loop_header->AddInstruction(if_inst);
+  phi->AddInput(array_length);
 
   HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
   null_check = new (allocator) HNullCheck(parameter, 0);
@@ -632,7 +632,7 @@
   ASSERT_TRUE(IsRemoved(bounds_check));
 }
 
-// int[] array = new array[10];
+// int[] array = new int[10];
 // for (int i=0; i<10; i+=increment) { array[i] = 10; }
 static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
                               HInstruction** bounds_check,
@@ -672,7 +672,6 @@
   loop_body->AddSuccessor(loop_header);
 
   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
-  phi->AddInput(constant_initial);
   HInstruction* cmp = nullptr;
   if (cond == kCondGE) {
     cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
@@ -684,6 +683,7 @@
   loop_header->AddPhi(phi);
   loop_header->AddInstruction(cmp);
   loop_header->AddInstruction(if_inst);
+  phi->AddInput(constant_initial);
 
   HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
   HArrayLength* array_length = new (allocator) HArrayLength(null_check);
@@ -708,7 +708,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
   HInstruction* bounds_check = nullptr;
   HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
@@ -718,7 +718,7 @@
   bounds_check_elimination_after_gvn.Run();
   ASSERT_TRUE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
   graph->BuildDominatorTree();
@@ -727,7 +727,7 @@
   bounds_check_elimination_with_initial_1.Run();
   ASSERT_TRUE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
   graph->BuildDominatorTree();
@@ -736,7 +736,7 @@
   bounds_check_elimination_with_greater_than.Run();
   ASSERT_FALSE(IsRemoved(bounds_check));
 
-  // int[] array = new array[10];
+  // int[] array = new int[10];
   // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
   graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
   graph->BuildDominatorTree();
@@ -785,7 +785,6 @@
   loop_body->AddSuccessor(loop_header);
 
   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
-  phi->AddInput(constant_initial);
   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
   HInstruction* array_length = new (allocator) HArrayLength(null_check);
   HInstruction* cmp = nullptr;
@@ -800,6 +799,7 @@
   loop_header->AddInstruction(array_length);
   loop_header->AddInstruction(cmp);
   loop_header->AddInstruction(if_inst);
+  phi->AddInput(constant_initial);
 
   null_check = new (allocator) HNullCheck(parameter, 0);
   array_length = new (allocator) HArrayLength(null_check);
@@ -904,7 +904,6 @@
   HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(outer_header);
   HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
-  phi_i->AddInput(constant_0);
   HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
   HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
   HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
@@ -916,11 +915,11 @@
   outer_header->AddInstruction(add);
   outer_header->AddInstruction(cmp);
   outer_header->AddInstruction(if_inst);
+  phi_i->AddInput(constant_0);
 
   HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(inner_header);
   HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
-  phi_j->AddInput(constant_0);
   null_check = new (&allocator) HNullCheck(parameter, 0);
   array_length = new (&allocator) HArrayLength(null_check);
   HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
@@ -934,6 +933,7 @@
   inner_header->AddInstruction(add);
   inner_header->AddInstruction(cmp);
   inner_header->AddInstruction(if_inst);
+  phi_j->AddInput(constant_0);
 
   HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(inner_body_compare);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index e151c6b..1101569 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1809,7 +1809,7 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::Any());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -1853,8 +1853,6 @@
     case Primitive::kPrimFloat: {
       if (second.IsFpuRegister()) {
         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
-      } else {
-        __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
@@ -1862,8 +1860,6 @@
     case Primitive::kPrimDouble: {
       if (second.IsFpuRegister()) {
         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
-      } else {
-        __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index ef10428..a7f1f74 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -160,6 +160,22 @@
                             instruction->GetId()));
     }
   }
+
+  // Ensure 'instruction' has pointers to its inputs' use entries.
+  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
+    HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i);
+    HInstruction* input = input_record.GetInstruction();
+    HUseListNode<HInstruction*>* use_node = input_record.GetUseNode();
+    if (use_node == nullptr || !input->GetUses().Contains(use_node)) {
+      AddError(StringPrintf("Instruction %s:%d has an invalid pointer to use entry "
+                            "at input %u (%s:%d).",
+                            instruction->DebugName(),
+                            instruction->GetId(),
+                            static_cast<unsigned>(i),
+                            input->DebugName(),
+                            input->GetId()));
+    }
+  }
 }
 
 void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc
index 10f24d8..bf9b8e5 100644
--- a/compiler/optimizing/licm.cc
+++ b/compiler/optimizing/licm.cc
@@ -66,8 +66,7 @@
   for (size_t i = 0, e = environment->Size(); i < e; ++i) {
     HInstruction* input = environment->GetInstructionAt(i);
     if (input != nullptr && IsPhiOf(input, info->GetHeader())) {
-      HUseListNode<HEnvironment*>* env_use = environment->GetInstructionEnvUseAt(i);
-      input->RemoveEnvironmentUser(env_use);
+      environment->RemoveAsUserOfInput(i);
       HInstruction* incoming = input->InputAt(0);
       environment->SetRawEnvAt(i, incoming);
       incoming->AddEnvUseAt(environment, i);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 7a75d26..93787b8 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -34,17 +34,14 @@
 
 static void RemoveAsUser(HInstruction* instruction) {
   for (size_t i = 0; i < instruction->InputCount(); i++) {
-    instruction->InputAt(i)->RemoveUser(instruction, i);
+    instruction->RemoveAsUserOfInput(i);
   }
 
   HEnvironment* environment = instruction->GetEnvironment();
   if (environment != nullptr) {
     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
-      HUseListNode<HEnvironment*>* vreg_env_use = environment->GetInstructionEnvUseAt(i);
-      if (vreg_env_use != nullptr) {
-        HInstruction* vreg = environment->GetInstructionAt(i);
-        DCHECK(vreg != nullptr);
-        vreg->RemoveEnvironmentUser(vreg_env_use);
+      if (environment->GetInstructionAt(i) != nullptr) {
+        environment->RemoveAsUserOfInput(i);
       }
     }
   }
@@ -64,22 +61,19 @@
   }
 }
 
-void HGraph::RemoveBlock(HBasicBlock* block) const {
-  for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
-    block->GetSuccessors().Get(j)->RemovePredecessor(block);
-  }
-  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-    block->RemovePhi(it.Current()->AsPhi());
-  }
-  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-    block->RemoveInstruction(it.Current());
-  }
-}
-
 void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
   for (size_t i = 0; i < blocks_.Size(); ++i) {
     if (!visited.IsBitSet(i)) {
-      RemoveBlock(blocks_.Get(i));
+      HBasicBlock* block = blocks_.Get(i);
+      for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
+        block->GetSuccessors().Get(j)->RemovePredecessor(block);
+      }
+      for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+        block->RemovePhi(it.Current()->AsPhi(), /*ensure_safety=*/ false);
+      }
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+        block->RemoveInstruction(it.Current(), /*ensure_safety=*/ false);
+      }
     }
   }
 }
@@ -439,22 +433,24 @@
 
 static void Remove(HInstructionList* instruction_list,
                    HBasicBlock* block,
-                   HInstruction* instruction) {
+                   HInstruction* instruction,
+                   bool ensure_safety) {
   DCHECK_EQ(block, instruction->GetBlock());
-  DCHECK(instruction->GetUses().IsEmpty());
-  DCHECK(instruction->GetEnvUses().IsEmpty());
   instruction->SetBlock(nullptr);
   instruction_list->RemoveInstruction(instruction);
-
-  RemoveAsUser(instruction);
+  if (ensure_safety) {
+    DCHECK(instruction->GetUses().IsEmpty());
+    DCHECK(instruction->GetEnvUses().IsEmpty());
+    RemoveAsUser(instruction);
+  }
 }
 
-void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
-  Remove(&instructions_, this, instruction);
+void HBasicBlock::RemoveInstruction(HInstruction* instruction, bool ensure_safety) {
+  Remove(&instructions_, this, instruction, ensure_safety);
 }
 
-void HBasicBlock::RemovePhi(HPhi* phi) {
-  Remove(&phis_, this, phi);
+void HBasicBlock::RemovePhi(HPhi* phi, bool ensure_safety) {
+  Remove(&phis_, this, phi, ensure_safety);
 }
 
 void HEnvironment::CopyFrom(HEnvironment* env) {
@@ -467,15 +463,9 @@
   }
 }
 
-template <typename T>
-static void RemoveFromUseList(T user, size_t input_index, HUseList<T>* list) {
-  HUseListNode<T>* current;
-  for (HUseIterator<HInstruction*> use_it(*list); !use_it.Done(); use_it.Advance()) {
-    current = use_it.Current();
-    if (current->GetUser() == user && current->GetIndex() == input_index) {
-      list->Remove(current);
-    }
-  }
+void HEnvironment::RemoveAsUserOfInput(size_t index) const {
+  const HUserRecord<HEnvironment*> user_record = vregs_.Get(index);
+  user_record.GetInstruction()->RemoveEnvironmentUser(user_record.GetUseNode());
 }
 
 HInstruction* HInstruction::GetNextDisregardingMoves() const {
@@ -494,14 +484,6 @@
   return previous;
 }
 
-void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
-  RemoveFromUseList(user, input_index, &uses_);
-}
-
-void HInstruction::RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use) {
-  env_uses_.Remove(use);
-}
-
 void HInstructionList::AddInstruction(HInstruction* instruction) {
   if (first_instruction_ == nullptr) {
     DCHECK(last_instruction_ == nullptr);
@@ -612,7 +594,7 @@
 }
 
 void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
-  InputAt(index)->RemoveUser(this, index);
+  RemoveAsUserOfInput(index);
   SetRawInputAt(index, replacement);
   replacement->AddUseAt(this, index);
 }
@@ -623,7 +605,7 @@
 
 void HPhi::AddInput(HInstruction* input) {
   DCHECK(input->GetBlock() != nullptr);
-  inputs_.Add(input);
+  inputs_.Add(HUserRecord<HInstruction*>(input));
   input->AddUseAt(this, inputs_.Size() - 1);
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 352403d..de448cc 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -31,6 +31,7 @@
 
 namespace art {
 
+class GraphChecker;
 class HBasicBlock;
 class HEnvironment;
 class HInstruction;
@@ -211,7 +212,6 @@
                               ArenaBitVector* visiting);
   void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
   void RemoveDeadBlocks(const ArenaBitVector& visited) const;
-  void RemoveBlock(HBasicBlock* block) const;
 
   ArenaAllocator* const arena_;
 
@@ -490,14 +490,17 @@
   void ReplaceWith(HBasicBlock* other);
 
   void AddInstruction(HInstruction* instruction);
-  void RemoveInstruction(HInstruction* instruction);
   void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor);
   // Replace instruction `initial` with `replacement` within this block.
   void ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                        HInstruction* replacement);
   void AddPhi(HPhi* phi);
   void InsertPhiAfter(HPhi* instruction, HPhi* cursor);
-  void RemovePhi(HPhi* phi);
+  // RemoveInstruction and RemovePhi delete a given instruction from the respective
+  // instruction list. With 'ensure_safety' set to true, it verifies that the
+  // instruction is not in use and removes it from the use lists of its inputs.
+  void RemoveInstruction(HInstruction* instruction, bool ensure_safety = true);
+  void RemovePhi(HPhi* phi, bool ensure_safety = true);
 
   bool IsLoopHeader() const {
     return (loop_information_ != nullptr) && (loop_information_->GetHeader() == this);
@@ -715,6 +718,9 @@
   }
 
   void Remove(HUseListNode<T>* node) {
+    DCHECK(node != nullptr);
+    DCHECK(Contains(node));
+
     if (node->prev_ != nullptr) {
       node->prev_->next_ = node->next_;
     }
@@ -726,6 +732,18 @@
     }
   }
 
+  bool Contains(const HUseListNode<T>* node) const {
+    if (node == nullptr) {
+      return false;
+    }
+    for (HUseListNode<T>* current = first_; current != nullptr; current = current->GetNext()) {
+      if (current == node) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool IsEmpty() const {
     return first_ == nullptr;
   }
@@ -761,6 +779,33 @@
   friend class HValue;
 };
 
+// This class is used by HEnvironment and HInstruction classes to record the
+// instructions they use and pointers to the corresponding HUseListNodes kept
+// by the used instructions.
+template <typename T>
+class HUserRecord : public ValueObject {
+ public:
+  HUserRecord() : instruction_(nullptr), use_node_(nullptr) {}
+  explicit HUserRecord(HInstruction* instruction) : instruction_(instruction), use_node_(nullptr) {}
+
+  HUserRecord(const HUserRecord<T>& old_record, HUseListNode<T>* use_node)
+    : instruction_(old_record.instruction_), use_node_(use_node) {
+    DCHECK(instruction_ != nullptr);
+    DCHECK(use_node_ != nullptr);
+    DCHECK(old_record.use_node_ == nullptr);
+  }
+
+  HInstruction* GetInstruction() const { return instruction_; }
+  HUseListNode<T>* GetUseNode() const { return use_node_; }
+
+ private:
+  // Instruction used by the user.
+  HInstruction* instruction_;
+
+  // Corresponding entry in the use list kept by 'instruction_'.
+  HUseListNode<T>* use_node_;
+};
+
 // Represents the side effects an instruction may have.
 class SideEffects : public ValueObject {
  public:
@@ -831,46 +876,36 @@
      : vregs_(arena, number_of_vregs) {
     vregs_.SetSize(number_of_vregs);
     for (size_t i = 0; i < number_of_vregs; i++) {
-      vregs_.Put(i, VRegInfo(nullptr, nullptr));
+      vregs_.Put(i, HUserRecord<HEnvironment*>());
     }
   }
 
   void CopyFrom(HEnvironment* env);
 
   void SetRawEnvAt(size_t index, HInstruction* instruction) {
-    vregs_.Put(index, VRegInfo(instruction, nullptr));
-  }
-
-  // Record instructions' use entries of this environment for constant-time removal.
-  void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) {
-    DCHECK(env_use->GetUser() == this);
-    size_t index = env_use->GetIndex();
-    VRegInfo info = vregs_.Get(index);
-    DCHECK(info.vreg_ != nullptr);
-    DCHECK(info.node_ == nullptr);
-    vregs_.Put(index, VRegInfo(info.vreg_, env_use));
+    vregs_.Put(index, HUserRecord<HEnvironment*>(instruction));
   }
 
   HInstruction* GetInstructionAt(size_t index) const {
-    return vregs_.Get(index).vreg_;
+    return vregs_.Get(index).GetInstruction();
   }
 
-  HUseListNode<HEnvironment*>* GetInstructionEnvUseAt(size_t index) const {
-    return vregs_.Get(index).node_;
-  }
+  void RemoveAsUserOfInput(size_t index) const;
 
   size_t Size() const { return vregs_.Size(); }
 
  private:
-  struct VRegInfo {
-    HInstruction* vreg_;
-    HUseListNode<HEnvironment*>* node_;
+  // Record instructions' use entries of this environment for constant-time removal.
+  // It should only be called by HInstruction when a new environment use is added.
+  void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) {
+    DCHECK(env_use->GetUser() == this);
+    size_t index = env_use->GetIndex();
+    vregs_.Put(index, HUserRecord<HEnvironment*>(vregs_.Get(index), env_use));
+  }
 
-    VRegInfo(HInstruction* instruction, HUseListNode<HEnvironment*>* env_use)
-        : vreg_(instruction), node_(env_use) {}
-  };
+  GrowableArray<HUserRecord<HEnvironment*> > vregs_;
 
-  GrowableArray<VRegInfo> vregs_;
+  friend HInstruction;
 
   DISALLOW_COPY_AND_ASSIGN(HEnvironment);
 };
@@ -989,13 +1024,15 @@
   bool IsLoopHeaderPhi() { return IsPhi() && block_->IsLoopHeader(); }
 
   virtual size_t InputCount() const = 0;
-  virtual HInstruction* InputAt(size_t i) const = 0;
+  HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); }
 
   virtual void Accept(HGraphVisitor* visitor) = 0;
   virtual const char* DebugName() const = 0;
 
   virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; }
-  virtual void SetRawInputAt(size_t index, HInstruction* input) = 0;
+  void SetRawInputAt(size_t index, HInstruction* input) {
+    SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input));
+  }
 
   virtual bool NeedsEnvironment() const { return false; }
   virtual bool IsControlFlow() const { return false; }
@@ -1018,7 +1055,10 @@
   ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; }
 
   void AddUseAt(HInstruction* user, size_t index) {
-    uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
+    DCHECK(user != nullptr);
+    HUseListNode<HInstruction*>* use =
+        uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
+    user->SetRawInputRecordAt(index, HUserRecord<HInstruction*>(user->InputRecordAt(index), use));
   }
 
   void AddEnvUseAt(HEnvironment* user, size_t index) {
@@ -1028,11 +1068,13 @@
     user->RecordEnvUse(env_use);
   }
 
-  void RemoveUser(HInstruction* user, size_t index);
-  void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use);
+  void RemoveAsUserOfInput(size_t input) {
+    HUserRecord<HInstruction*> input_use = InputRecordAt(input);
+    input_use.GetInstruction()->uses_.Remove(input_use.GetUseNode());
+  }
 
-  const HUseList<HInstruction*>& GetUses() { return uses_; }
-  const HUseList<HEnvironment*>& GetEnvUses() { return env_uses_; }
+  const HUseList<HInstruction*>& GetUses() const { return uses_; }
+  const HUseList<HEnvironment*>& GetEnvUses() const { return env_uses_; }
 
   bool HasUses() const { return !uses_.IsEmpty() || !env_uses_.IsEmpty(); }
   bool HasEnvironmentUses() const { return !env_uses_.IsEmpty(); }
@@ -1126,7 +1168,13 @@
     return NeedsEnvironment() || IsLoadClass() || IsLoadString();
   }
 
+ protected:
+  virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
+  virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
+
  private:
+  void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use_node) { env_uses_.Remove(use_node); }
+
   HInstruction* previous_;
   HInstruction* next_;
   HBasicBlock* block_;
@@ -1164,7 +1212,9 @@
   // TODO: for primitive types this should be marked as invalid.
   ReferenceTypeInfo reference_type_info_;
 
+  friend class GraphChecker;
   friend class HBasicBlock;
+  friend class HEnvironment;
   friend class HGraph;
   friend class HInstructionList;
 
@@ -1284,15 +1334,16 @@
   virtual ~HTemplateInstruction() {}
 
   virtual size_t InputCount() const { return N; }
-  virtual HInstruction* InputAt(size_t i) const { return inputs_[i]; }
 
  protected:
-  virtual void SetRawInputAt(size_t i, HInstruction* instruction) {
-    inputs_[i] = instruction;
+  const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_[i]; }
+
+  void SetRawInputRecordAt(size_t i, const HUserRecord<HInstruction*>& input) OVERRIDE {
+    inputs_[i] = input;
   }
 
  private:
-  EmbeddedArray<HInstruction*, N> inputs_;
+  EmbeddedArray<HUserRecord<HInstruction*>, N> inputs_;
 
   friend class SsaBuilder;
 };
@@ -1848,7 +1899,6 @@
 class HInvoke : public HInstruction {
  public:
   virtual size_t InputCount() const { return inputs_.Size(); }
-  virtual HInstruction* InputAt(size_t i) const { return inputs_.Get(i); }
 
   // Runtime needs to walk the stack, so Dex -> Dex calls need to
   // know their environment.
@@ -1858,10 +1908,6 @@
     SetRawInputAt(index, argument);
   }
 
-  virtual void SetRawInputAt(size_t index, HInstruction* input) {
-    inputs_.Put(index, input);
-  }
-
   virtual Primitive::Type GetType() const { return return_type_; }
 
   uint32_t GetDexPc() const { return dex_pc_; }
@@ -1893,7 +1939,12 @@
     inputs_.SetSize(number_of_arguments);
   }
 
-  GrowableArray<HInstruction*> inputs_;
+  const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_.Get(i); }
+  void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE {
+    inputs_.Put(index, input);
+  }
+
+  GrowableArray<HUserRecord<HInstruction*> > inputs_;
   const Primitive::Type return_type_;
   const uint32_t dex_pc_;
   const uint32_t dex_method_index_;
@@ -2389,11 +2440,6 @@
   }
 
   size_t InputCount() const OVERRIDE { return inputs_.Size(); }
-  HInstruction* InputAt(size_t i) const OVERRIDE { return inputs_.Get(i); }
-
-  void SetRawInputAt(size_t index, HInstruction* input) OVERRIDE {
-    inputs_.Put(index, input);
-  }
 
   void AddInput(HInstruction* input);
 
@@ -2412,8 +2458,15 @@
 
   DECLARE_INSTRUCTION(Phi);
 
+ protected:
+  const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_.Get(i); }
+
+  void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE {
+    inputs_.Put(index, input);
+  }
+
  private:
-  GrowableArray<HInstruction*> inputs_;
+  GrowableArray<HUserRecord<HInstruction*> > inputs_;
   const uint32_t reg_number_;
   Primitive::Type type_;
   bool is_live_;
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index bfbe63f..54e62a5 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -48,7 +48,10 @@
         physical_core_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()),
         physical_fp_register_intervals_(allocator, codegen->GetNumberOfFloatingPointRegisters()),
         temp_intervals_(allocator, 4),
-        spill_slots_(allocator, kDefaultNumberOfSpillSlots),
+        int_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
+        long_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
+        float_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
+        double_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
         safepoints_(allocator, 0),
         processing_core_registers_(false),
         number_of_registers_(-1),
@@ -438,7 +441,7 @@
     }
   }
 
-  return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_,
+  return ValidateIntervals(intervals, GetNumberOfSpillSlots(), reserved_out_slots_, *codegen_,
                            allocator_, processing_core_registers_, log_fatal_on_failure);
 }
 
@@ -1133,41 +1136,62 @@
   }
   size_t end = last_sibling->GetEnd();
 
+  GrowableArray<size_t>* spill_slots = nullptr;
+  switch (interval->GetType()) {
+    case Primitive::kPrimDouble:
+      spill_slots = &double_spill_slots_;
+      break;
+    case Primitive::kPrimLong:
+      spill_slots = &long_spill_slots_;
+      break;
+    case Primitive::kPrimFloat:
+      spill_slots = &float_spill_slots_;
+      break;
+    case Primitive::kPrimNot:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimShort:
+      spill_slots = &int_spill_slots_;
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unexpected type for interval " << interval->GetType();
+  }
+
   // Find an available spill slot.
   size_t slot = 0;
-  for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
-    // We check if it is less rather than less or equal because the parallel move
-    // resolver does not work when a single spill slot needs to be exchanged with
-    // a double spill slot. The strict comparison avoids needing to exchange these
-    // locations at the same lifetime position.
-    if (spill_slots_.Get(slot) < parent->GetStart()
-        && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) {
+  for (size_t e = spill_slots->Size(); slot < e; ++slot) {
+    if (spill_slots->Get(slot) <= parent->GetStart()
+        && (slot == (e - 1) || spill_slots->Get(slot + 1) <= parent->GetStart())) {
       break;
     }
   }
 
   if (parent->NeedsTwoSpillSlots()) {
-    if (slot == spill_slots_.Size()) {
+    if (slot == spill_slots->Size()) {
       // We need a new spill slot.
-      spill_slots_.Add(end);
-      spill_slots_.Add(end);
-    } else if (slot == spill_slots_.Size() - 1) {
-      spill_slots_.Put(slot, end);
-      spill_slots_.Add(end);
+      spill_slots->Add(end);
+      spill_slots->Add(end);
+    } else if (slot == spill_slots->Size() - 1) {
+      spill_slots->Put(slot, end);
+      spill_slots->Add(end);
     } else {
-      spill_slots_.Put(slot, end);
-      spill_slots_.Put(slot + 1, end);
+      spill_slots->Put(slot, end);
+      spill_slots->Put(slot + 1, end);
     }
   } else {
-    if (slot == spill_slots_.Size()) {
+    if (slot == spill_slots->Size()) {
       // We need a new spill slot.
-      spill_slots_.Add(end);
+      spill_slots->Add(end);
     } else {
-      spill_slots_.Put(slot, end);
+      spill_slots->Put(slot, end);
     }
   }
 
-  parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
+  // Note that the exact spill slot location will be computed when we resolve,
+  // that is when we know the number of spill slots for each type.
+  parent->SetSpillSlot(slot);
 }
 
 static bool IsValidDestination(Location destination) {
@@ -1516,7 +1540,7 @@
 }
 
 void RegisterAllocator::Resolve() {
-  codegen_->InitializeCodeGeneration(spill_slots_.Size(),
+  codegen_->InitializeCodeGeneration(GetNumberOfSpillSlots(),
                                      maximum_number_of_live_core_registers_,
                                      maximum_number_of_live_fp_registers_,
                                      reserved_out_slots_,
@@ -1542,6 +1566,39 @@
       } else if (current->HasSpillSlot()) {
         current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
       }
+    } else if (current->HasSpillSlot()) {
+      // Adjust the stack slot, now that we know the number of them for each type.
+      // The way this implementation lays out the stack is the following:
+      // [parameter slots     ]
+      // [double spill slots  ]
+      // [long spill slots    ]
+      // [float spill slots   ]
+      // [int/ref values      ]
+      // [maximum out values  ] (number of arguments for calls)
+      // [art method          ].
+      uint32_t slot = current->GetSpillSlot();
+      switch (current->GetType()) {
+        case Primitive::kPrimDouble:
+          slot += long_spill_slots_.Size();
+          FALLTHROUGH_INTENDED;
+        case Primitive::kPrimLong:
+          slot += float_spill_slots_.Size();
+          FALLTHROUGH_INTENDED;
+        case Primitive::kPrimFloat:
+          slot += int_spill_slots_.Size();
+          FALLTHROUGH_INTENDED;
+        case Primitive::kPrimNot:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+        case Primitive::kPrimByte:
+        case Primitive::kPrimBoolean:
+        case Primitive::kPrimShort:
+          slot += reserved_out_slots_;
+          break;
+        case Primitive::kPrimVoid:
+          LOG(FATAL) << "Unexpected type for interval " << current->GetType();
+      }
+      current->SetSpillSlot(slot * kVRegSize);
     }
 
     Location source = current->ToLocation();
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index b8f70bd..ff2f106 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -75,7 +75,10 @@
   }
 
   size_t GetNumberOfSpillSlots() const {
-    return spill_slots_.Size();
+    return int_spill_slots_.Size()
+        + long_spill_slots_.Size()
+        + float_spill_slots_.Size()
+        + double_spill_slots_.Size();
   }
 
  private:
@@ -171,8 +174,14 @@
   // where an instruction requires a temporary.
   GrowableArray<LiveInterval*> temp_intervals_;
 
-  // The spill slots allocated for live intervals.
-  GrowableArray<size_t> spill_slots_;
+  // The spill slots allocated for live intervals. We ensure spill slots
+  // are typed to avoid (1) doing moves and swaps between two different kinds
+  // of registers, and (2) swapping between a single stack slot and a double
+  // stack slot. This simplifies the parallel move resolver.
+  GrowableArray<size_t> int_spill_slots_;
+  GrowableArray<size_t> long_spill_slots_;
+  GrowableArray<size_t> float_spill_slots_;
+  GrowableArray<size_t> double_spill_slots_;
 
   // Instructions that need a safepoint.
   GrowableArray<HInstruction*> safepoints_;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index f66a1c8..2f2e2d1 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -64,31 +64,33 @@
     HBasicBlock* block = it.Current();
     HInstruction* current = block->GetFirstPhi();
     HInstruction* next = nullptr;
+    HPhi* phi;
     while (current != nullptr) {
+      phi = current->AsPhi();
       next = current->GetNext();
-      if (current->AsPhi()->IsDead()) {
-        if (current->HasUses()) {
-          for (HUseIterator<HInstruction*> use_it(current->GetUses()); !use_it.Done();
+      if (phi->IsDead()) {
+        // Make sure the phi is only used by other dead phis.
+        if (kIsDebugBuild) {
+          for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
                use_it.Advance()) {
-            HUseListNode<HInstruction*>* user_node = use_it.Current();
-            HInstruction* user = user_node->GetUser();
+            HInstruction* user = use_it.Current()->GetUser();
             DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
             DCHECK(user->AsPhi()->IsDead()) << user->GetId();
-            // Just put itself as an input. The phi will be removed in this loop anyway.
-            user->SetRawInputAt(user_node->GetIndex(), user);
-            current->RemoveUser(user, user_node->GetIndex());
           }
         }
-        if (current->HasEnvironmentUses()) {
-          for (HUseIterator<HEnvironment*> use_it(current->GetEnvUses()); !use_it.Done();
-               use_it.Advance()) {
-            HUseListNode<HEnvironment*>* user_node = use_it.Current();
-            HEnvironment* user = user_node->GetUser();
-            user->SetRawEnvAt(user_node->GetIndex(), nullptr);
-            current->RemoveEnvironmentUser(user_node);
-          }
+        // Remove the phi from use lists of its inputs.
+        for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+          phi->RemoveAsUserOfInput(i);
         }
-        block->RemovePhi(current->AsPhi());
+        // Remove the phi from environments that use it.
+        for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
+             use_it.Advance()) {
+          HUseListNode<HEnvironment*>* user_node = use_it.Current();
+          HEnvironment* user = user_node->GetUser();
+          user->SetRawEnvAt(user_node->GetIndex(), nullptr);
+        }
+        // Delete it from the instruction list.
+        block->RemovePhi(phi, /*ensure_safety=*/ false);
       }
       current = next;
     }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index e607e15..0b1f14d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -36,6 +36,7 @@
 #include "arch/instruction_set_features.h"
 #include "arch/mips/instruction_set_features_mips.h"
 #include "base/dumpable.h"
+#include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/stringpiece.h"
 #include "base/timing_logger.h"
@@ -97,7 +98,7 @@
   va_end(ap);
 }
 
-[[noreturn]] static void Usage(const char* fmt, ...) {
+NO_RETURN static void Usage(const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
@@ -326,7 +327,7 @@
             message.c_str());
   }
 
-  [[noreturn]] static void Fatal(const std::string& message) {
+  NO_RETURN static void Fatal(const std::string& message) {
     Message('F', message);
     exit(1);
   }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 2059a96..3c6a23d 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -763,7 +763,7 @@
   va_end(ap);
 }
 
-[[noreturn]] static void Usage(const char *fmt, ...) {
+NO_RETURN static void Usage(const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc
index c181e43..5bd23d0 100644
--- a/runtime/arch/arm/context_arm.cc
+++ b/runtime/arch/arm/context_arm.cc
@@ -106,7 +106,7 @@
   fprs_[S15] = nullptr;
 }
 
-extern "C" void art_quick_do_long_jump(uint32_t*, uint32_t*);
+extern "C" NO_RETURN void art_quick_do_long_jump(uint32_t*, uint32_t*);
 
 void ArmContext::DoLongJump() {
   uintptr_t gprs[kNumberOfCoreRegisters];
diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h
index 1ca973e..5bdeda7 100644
--- a/runtime/arch/arm/context_arm.h
+++ b/runtime/arch/arm/context_arm.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_arm.h"
 
 namespace art {
@@ -76,7 +77,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pointers to register locations, initialized to NULL or the specific registers below.
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index 7fc0555..ec9c122 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -133,7 +133,7 @@
   fprs_[D31] = nullptr;
 }
 
-extern "C" void art_quick_do_long_jump(uint64_t*, uint64_t*);
+extern "C" NO_RETURN void art_quick_do_long_jump(uint64_t*, uint64_t*);
 
 void Arm64Context::DoLongJump() {
   uint64_t gprs[kNumberOfXRegisters];
diff --git a/runtime/arch/arm64/context_arm64.h b/runtime/arch/arm64/context_arm64.h
index 6a4485b..f486779 100644
--- a/runtime/arch/arm64/context_arm64.h
+++ b/runtime/arch/arm64/context_arm64.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_arm64.h"
 
 namespace art {
@@ -76,7 +77,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pointers to register locations, initialized to NULL or the specific registers below.
diff --git a/runtime/arch/context.h b/runtime/arch/context.h
index ed8cab0..f86f9ae 100644
--- a/runtime/arch/context.h
+++ b/runtime/arch/context.h
@@ -20,6 +20,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/macros.h"
 #include "base/mutex.h"
 
 namespace art {
@@ -78,7 +79,7 @@
   virtual void SmashCallerSaves() = 0;
 
   // Switches execution of the executing context to this context
-  virtual void DoLongJump() = 0;
+  NO_RETURN virtual void DoLongJump() = 0;
 
  protected:
   enum {
diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc
index 6c0ab98..3b525be 100644
--- a/runtime/arch/mips/context_mips.cc
+++ b/runtime/arch/mips/context_mips.cc
@@ -90,7 +90,7 @@
   gprs_[A3] = nullptr;
 }
 
-extern "C" void art_quick_do_long_jump(uint32_t*, uint32_t*);
+extern "C" NO_RETURN void art_quick_do_long_jump(uint32_t*, uint32_t*);
 
 void MipsContext::DoLongJump() {
   uintptr_t gprs[kNumberOfCoreRegisters];
diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h
index d8a0b67..cbad3f963 100644
--- a/runtime/arch/mips/context_mips.h
+++ b/runtime/arch/mips/context_mips.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_mips.h"
 
 namespace art {
@@ -75,7 +76,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pointers to registers in the stack, initialized to NULL except for the special cases below.
diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc
index 1c96bd4..ce99b40 100644
--- a/runtime/arch/mips64/context_mips64.cc
+++ b/runtime/arch/mips64/context_mips64.cc
@@ -121,7 +121,7 @@
   fprs_[F23] = nullptr;
 }
 
-extern "C" void art_quick_do_long_jump(uintptr_t*, uintptr_t*);
+extern "C" NO_RETURN void art_quick_do_long_jump(uintptr_t*, uintptr_t*);
 
 void Mips64Context::DoLongJump() {
   uintptr_t gprs[kNumberOfGpuRegisters];
diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h
index 1046723..2cc2b8d 100644
--- a/runtime/arch/mips64/context_mips64.h
+++ b/runtime/arch/mips64/context_mips64.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_mips64.h"
 
 namespace art {
@@ -75,7 +76,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pointers to registers in the stack, initialized to NULL except for the special cases below.
diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc
index 4ea4684..52a35dd 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -133,6 +133,7 @@
 #else
   UNIMPLEMENTED(FATAL);
 #endif
+  UNREACHABLE();
 }
 
 }  // namespace x86
diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h
index c66a9dc..ace4670 100644
--- a/runtime/arch/x86/context_x86.h
+++ b/runtime/arch/x86/context_x86.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_x86.h"
 
 namespace art {
@@ -75,7 +76,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pretend XMM registers are made of uin32_t pieces, because they are manipulated
diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index cdc2ec7..6336541 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -105,7 +105,7 @@
   *fprs_[reg] = value;
 }
 
-extern "C" void art_quick_do_long_jump(uintptr_t*, uintptr_t*);
+extern "C" NO_RETURN void art_quick_do_long_jump(uintptr_t*, uintptr_t*);
 
 void X86_64Context::DoLongJump() {
 #if defined(__x86_64__)
@@ -127,6 +127,7 @@
   art_quick_do_long_jump(gprs, fprs);
 #else
   UNIMPLEMENTED(FATAL);
+  UNREACHABLE();
 #endif
 }
 
diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h
index 0dda06e..d03aa45 100644
--- a/runtime/arch/x86_64/context_x86_64.h
+++ b/runtime/arch/x86_64/context_x86_64.h
@@ -19,6 +19,7 @@
 
 #include "arch/context.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "registers_x86_64.h"
 
 namespace art {
@@ -75,7 +76,7 @@
   void SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
-  void DoLongJump() OVERRIDE;
+  NO_RETURN void DoLongJump() OVERRIDE;
 
  private:
   // Pointers to register locations. Values are initialized to NULL or the special registers below.
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index f705469..3a9de5f 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -186,6 +186,9 @@
 // without the UNREACHABLE a return statement would be necessary.
 #define UNREACHABLE  __builtin_unreachable
 
+// Add the C++11 noreturn attribute.
+#define NO_RETURN [[ noreturn ]]  // NOLINT[whitespace/braces] [5]
+
 // The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
 // between switch labels:
 //  switch (x) {
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 261d3c2..d873e6d 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <sys/statvfs.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <random>
 
@@ -122,21 +123,50 @@
 // every zygote boot and delete it when the boot completes. If we find a file already
 // present, it usually means the boot didn't complete. We wipe the entire dalvik
 // cache if that's the case.
-static void MarkZygoteStart(const InstructionSet isa) {
+static void MarkZygoteStart(const InstructionSet isa, const uint32_t max_failed_boots) {
   const std::string isa_subdir = GetDalvikCacheOrDie(GetInstructionSetString(isa), false);
   const std::string boot_marker = isa_subdir + "/.booting";
+  const char* file_name = boot_marker.c_str();
 
-  if (OS::FileExists(boot_marker.c_str())) {
+  uint32_t num_failed_boots = 0;
+  std::unique_ptr<File> file(OS::OpenFileReadWrite(file_name));
+  if (file.get() == nullptr) {
+    file.reset(OS::CreateEmptyFile(file_name));
+
+    if (file.get() == nullptr) {
+      PLOG(WARNING) << "Failed to create boot marker.";
+      return;
+    }
+  } else {
+    if (!file->ReadFully(&num_failed_boots, sizeof(num_failed_boots))) {
+      PLOG(WARNING) << "Failed to read boot marker.";
+      file->Erase();
+      return;
+    }
+  }
+
+  if (max_failed_boots != 0 && num_failed_boots > max_failed_boots) {
     LOG(WARNING) << "Incomplete boot detected. Pruning dalvik cache";
     RealPruneDalvikCache(isa_subdir);
   }
 
-  VLOG(startup) << "Creating boot start marker: " << boot_marker;
-  std::unique_ptr<File> f(OS::CreateEmptyFile(boot_marker.c_str()));
-  if (f.get() != nullptr) {
-    if (f->FlushCloseOrErase() != 0) {
-      PLOG(WARNING) << "Failed to write boot marker.";
-    }
+  ++num_failed_boots;
+  VLOG(startup) << "Number of failed boots on : " << boot_marker << " = " << num_failed_boots;
+
+  if (lseek(file->Fd(), 0, SEEK_SET) == -1) {
+    PLOG(WARNING) << "Failed to write boot marker.";
+    file->Erase();
+    return;
+  }
+
+  if (!file->WriteFully(&num_failed_boots, sizeof(num_failed_boots))) {
+    PLOG(WARNING) << "Failed to write boot marker.";
+    file->Erase();
+    return;
+  }
+
+  if (file->FlushCloseOrErase() != 0) {
+    PLOG(WARNING) << "Failed to flush boot marker.";
   }
 }
 
@@ -450,7 +480,7 @@
                                              &has_cache, &is_global_cache);
 
   if (Runtime::Current()->IsZygote()) {
-    MarkZygoteStart(image_isa);
+    MarkZygoteStart(image_isa, Runtime::Current()->GetZygoteMaxFailedBoots());
   }
 
   ImageSpace* space;
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index ce7c1c3..06b809f 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -25,6 +25,7 @@
 #include <sstream>
 
 #include "base/logging.h"
+#include "base/macros.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
@@ -349,8 +350,8 @@
     uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame)
-  __attribute__((cold, noreturn))
+NO_RETURN void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame)
+  __attribute__((cold))
   SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index 97b17bf..84b18ab 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -20,6 +20,7 @@
 #include <limits.h>
 #include <unistd.h>
 
+#include "base/macros.h"
 #include "gc/heap.h"
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
@@ -39,7 +40,7 @@
   Runtime::Current()->GetHeap()->CollectGarbage(false);
 }
 
-[[noreturn]] static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
+NO_RETURN static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
   LOG(INFO) << "System.exit called, status: " << status;
   Runtime::Current()->CallExitHook(status);
   exit(status);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index daa4373..99369ca 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -238,6 +238,9 @@
       .Define("-XX:NativeBridge=_")
           .WithType<std::string>()
           .IntoKey(M::NativeBridge)
+      .Define("-Xzygote-max-failed-boots=_")
+          .WithType<unsigned int>()
+          .IntoKey(M::ZygoteMaxFailedBoots)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 85ec803..7bdf652 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -353,6 +353,7 @@
   context_->SetPC(handler_quick_frame_pc_);
   context_->SmashCallerSaves();
   context_->DoLongJump();
+  UNREACHABLE();
 }
 
 }  // namespace art
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index 31622de..162b1dc 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
 
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/mutex.h"
 #include "stack.h"  // StackReference
 
@@ -48,7 +49,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DeoptimizeStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  NO_RETURN void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetHandlerQuickFrame(StackReference<mirror::ArtMethod>* handler_quick_frame) {
     handler_quick_frame_ = handler_quick_frame;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0ccc97c..f38f65e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -173,7 +173,8 @@
       implicit_null_checks_(false),
       implicit_so_checks_(false),
       implicit_suspend_checks_(false),
-      is_native_bridge_loaded_(false) {
+      is_native_bridge_loaded_(false),
+      zygote_max_failed_boots_(0) {
   CheckAsmSupportOffsetsAndSizes();
 }
 
@@ -766,6 +767,8 @@
     GetInstrumentation()->ForceInterpretOnly();
   }
 
+  zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
+
   XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
   heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
                        runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 118c838..fb9ca40 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -28,6 +28,7 @@
 
 #include "arch/instruction_set.h"
 #include "base/allocator.h"
+#include "base/macros.h"
 #include "compiler_callbacks.h"
 #include "gc_root.h"
 #include "instrumentation.h"
@@ -185,7 +186,7 @@
 
   // Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most
   // callers should prefer.
-  [[noreturn]] static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
+  NO_RETURN static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
 
   // Returns the "main" ThreadGroup, used when attaching user threads.
   jobject GetMainThreadGroup() const;
@@ -516,6 +517,10 @@
     return target_sdk_version_;
   }
 
+  uint32_t GetZygoteMaxFailedBoots() const {
+    return zygote_max_failed_boots_;
+  }
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -682,6 +687,11 @@
   // that there's no native bridge.
   bool is_native_bridge_loaded_;
 
+  // The maximum number of failed boots we allow before pruning the dalvik cache
+  // and trying again. This option is only inspected when we're running as a
+  // zygote.
+  uint32_t zygote_max_failed_boots_;
+
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 1bdc980..71a0152 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -114,6 +114,7 @@
                                                                           // We don't call abort(3) by default; see
                                                                           // Runtime::Abort.
 RUNTIME_OPTIONS_KEY (void (*)(),          HookAbort,                      nullptr)
+RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           1)
 
 
 #undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/thread.cc b/runtime/thread.cc
index cb6ed64..3b48f49 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2044,8 +2044,6 @@
   }
   exception_handler.UpdateInstrumentationStack();
   exception_handler.DoLongJump();
-  LOG(FATAL) << "UNREACHABLE";
-  UNREACHABLE();
 }
 
 Context* Thread::GetLongJumpContext() {
diff --git a/runtime/thread.h b/runtime/thread.h
index 26b7b6f..83cedbb 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -353,7 +353,7 @@
   }
 
   // Find catch block and perform long jump to appropriate exception handle
-  void QuickDeliverException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  NO_RETURN void QuickDeliverException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Context* GetLongJumpContext();
   void ReleaseLongJumpContext(Context* context) {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 05a0bff..d0f014a 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -228,8 +228,7 @@
 
 #if HAVE_TIMED_RWLOCK
 // Attempt to rectify locks so that we dump thread list with required locks before exiting.
-static void UnsafeLogFatalForThreadSuspendAllTimeout() __attribute__((noreturn));
-static void UnsafeLogFatalForThreadSuspendAllTimeout() {
+NO_RETURN static void UnsafeLogFatalForThreadSuspendAllTimeout() {
   Runtime* runtime = Runtime::Current();
   std::ostringstream ss;
   ss << "Thread suspend timeout\n";
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 5a0e13b..ad4092b 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -46,6 +46,7 @@
     return primeCount;
   }
 
+
   // CHECK-START: void Main.narrow(int[], int) BCE (before)
   // CHECK: BoundsCheck
   // CHECK: ArraySet
@@ -61,8 +62,12 @@
   // CHECK: ArraySet
   // CHECK: BoundsCheck
   // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
 
-  static void narrow(int array[], int offset) {
+  static void narrow(int[] array, int offset) {
     if (offset < 0) {
       return;
     }
@@ -87,10 +92,386 @@
         // eliminate this bounds check.
         array[biased_offset2] = 1;
       }
+
+      // offset_sub1 won't underflow since offset is no less than 0.
+      int offset_sub1 = offset - Integer.MAX_VALUE;
+      if (offset_sub1 >= 0) {
+        array[offset_sub1] = 1;  // Bounds check can be eliminated.
+      }
+
+      // offset_sub2 can underflow.
+      int offset_sub2 = offset_sub1 - Integer.MAX_VALUE;
+      if (offset_sub2 >= 0) {
+        array[offset_sub2] = 1;  // Bounds check can't be eliminated.
+      }
     }
   }
 
+
+  // CHECK-START: void Main.constantIndexing(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.constantIndexing(int[]) BCE (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void constantIndexing(int[] array) {
+    array[5] = 1;
+    array[4] = 1;
+    array[6] = 1;
+  }
+
+
+  // CHECK-START: void Main.loopPattern1(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern1(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern1(int[] array) {
+    for (int i = 0; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 1; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 1; i < array.length - 1; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = -1; i < array.length; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = 0; i <= array.length; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = 0; i < array.length; i += 2) {
+      // We don't have any assumption on max array length yet.
+      // Bounds check can't be eliminated due to overflow concern.
+      array[i] = 1;
+    }
+
+    for (int i = 1; i < array.length; i += 2) {
+      // Bounds check can be eliminated since i is odd so the last
+      // i that's less than array.length is at most (Integer.MAX_VALUE - 2).
+      array[i] = 1;
+    }
+  }
+
+
+  // CHECK-START: void Main.loopPattern2(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern2(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern2(int[] array) {
+    for (int i = array.length - 1; i >= 0; i--) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length; i > 0; i--) {
+      array[i - 1] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length - 1; i > 0; i--) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = array.length; i >= 0; i--) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = array.length; i >= 0; i--) {
+      array[i - 1] = 1;  // Bounds check can't be eliminated.
+    }
+
+    for (int i = array.length; i > 0; i -= 20) {
+      // For i >= 0, (i - 20 - 1) is guaranteed not to underflow.
+      array[i - 1] = 1;  // Bounds check can be eliminated.
+    }
+  }
+
+
+  // CHECK-START: void Main.loopPattern3(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.loopPattern3(int[]) BCE (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void loopPattern3(int[] array) {
+    java.util.Random random = new java.util.Random();
+    for (int i = 0; ; i++) {
+      if (random.nextInt() % 1000 == 0 && i < array.length) {
+        // Can't eliminate the bound check since not every i++ is
+        // matched with a array length check, so there is some chance that i
+        // overflows and is negative.
+        array[i] = 1;
+      }
+    }
+  }
+
+
+  // CHECK-START: void Main.constantNewArray() BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.constantNewArray() BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  static void constantNewArray() {
+    int[] array = new int[10];
+    for (int i = 0; i < 10; i++) {
+      array[i] = 1;  // Bounds check can be eliminated.
+    }
+
+    for (int i = 0; i <= 10; i++) {
+      array[i] = 1;  // Bounds check can't be eliminated.
+    }
+
+    array[0] = 1;  // Bounds check can be eliminated.
+    array[9] = 1;  // Bounds check can be eliminated.
+    array[10] = 1; // Bounds check can't be eliminated.
+  }
+
+  // CHECK-START: void Main.pyramid1(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid1(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid1(int[] array) {
+    for (int i = 0; i < (array.length + 1) / 2; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // CHECK-START: void Main.pyramid2(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid2(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid2(int[] array) {
+    for (int i = 0; i < (array.length + 1) >> 1; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // CHECK-START: void Main.pyramid3(int[]) BCE (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.pyramid3(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
+  static void pyramid3(int[] array) {
+    for (int i = 0; i < (array.length + 1) >>> 1; i++) {
+      array[i] = i;
+      array[array.length - 1 - i] = i;
+    }
+  }
+
+
+  // TODO: bce on the array accesses in this method.
+  static boolean isPyramid(int[] array) {
+    int i = 0;
+    int j = array.length - 1;
+    while (i <= j) {
+      if (array[i] != i) {
+        return false;
+      }
+      if (array[j] != i) {
+        return false;
+      }
+      i++; j--;
+    }
+    return true;
+  }
+
+
+  // CHECK-START: void Main.bubbleSort(int[]) GVN (before)
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.bubbleSort(int[]) GVN (after)
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  // CHECK-START: void Main.bubbleSort(int[]) BCE (after)
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: ArrayGet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+  // CHECK-NOT: BoundsCheck
+  // CHECK: ArraySet
+
+  static void bubbleSort(int[] array) {
+    for (int i = 0; i < array.length - 1; i++) {
+      for (int j = 0; j < array.length - i - 1; j++) {
+        if (array[j] > array[j + 1]) {
+          int temp = array[j + 1];
+          array[j + 1] = array[j];
+          array[j] = temp;
+        }
+      }
+    }
+  }
+
+
   public static void main(String[] args) {
     sieve(20);
+
+    int[] array = {5, 2, 3, 7, 0, 1, 6, 4};
+    bubbleSort(array);
+    for (int i = 0; i < 8; i++) {
+      if (array[i] != i) {
+        System.out.println("bubble sort failed!");
+      }
+    }
+
+    array = new int[7];
+    pyramid1(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid1 failed!");
+    }
+
+    array = new int[8];
+    pyramid2(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid2 failed!");
+    }
+
+    java.util.Arrays.fill(array, -1);
+    pyramid3(array);
+    if (!isPyramid(array)) {
+      System.out.println("pyramid3 failed!");
+    }
   }
 }
diff --git a/test/451-regression-add-float/expected.txt b/test/451-regression-add-float/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/451-regression-add-float/expected.txt
diff --git a/test/451-regression-add-float/info.txt b/test/451-regression-add-float/info.txt
new file mode 100644
index 0000000..83a5f9d
--- /dev/null
+++ b/test/451-regression-add-float/info.txt
@@ -0,0 +1,2 @@
+Tests a regression in float addition for optimizing. The second argument
+could be now be a constant for floating point numbers.
diff --git a/test/451-regression-add-float/src/Main.java b/test/451-regression-add-float/src/Main.java
new file mode 100644
index 0000000..0d4bf06
--- /dev/null
+++ b/test/451-regression-add-float/src/Main.java
@@ -0,0 +1,72 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+public class Main {
+
+  public static void main(String[] args) {
+    assertEqual(4, add3(1));
+    assertEqual(4l, add3(1l));
+    assertEqual(4f, add3(1f));
+    assertEqual(4d, add3(1d));
+  }
+
+  public static int add3(int a) {
+    return 1 + a + 2;
+  }
+
+  public static long add3(long a) {
+    return 1l + a + 2l;
+  }
+
+  public static float add3(float a) {
+    return 1f + a + 2f;
+  }
+
+  public static double add3(double a) {
+    return 1d + a + 2d;
+  }
+
+  public static void assertEqual(int a, int b) {
+    if (a != b) {
+      throw new RuntimeException("Expected: " + a + " Found: " + b);
+    }
+  }
+
+  public static void assertEqual(long a, long b) {
+    if (a != b) {
+      throw new RuntimeException("Expected: " + a + " Found: " + b);
+    }
+  }
+
+  public static void assertEqual(float a, float b) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < 0.0001f)
+      : ((b - a) < 0.0001f);
+    if (!aproxEquals) {
+      throw new RuntimeException("Expected: " + a + " Found: " + b);
+    }
+  }
+
+  public static void assertEqual(double a, double b) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < 0.0001d)
+      : ((b - a) < 0.0001d);
+    if (!aproxEquals) {
+      throw new RuntimeException("Expected: " + a + " Found: " + b);
+    }
+  }
+}
diff --git a/test/451-spill-splot/expected.txt b/test/451-spill-splot/expected.txt
new file mode 100644
index 0000000..efc3f2e
--- /dev/null
+++ b/test/451-spill-splot/expected.txt
@@ -0,0 +1,6 @@
+85.0
+45.0
+20.0
+56.0
+20.0
+20.0
diff --git a/test/451-spill-splot/info.txt b/test/451-spill-splot/info.txt
new file mode 100644
index 0000000..1772ce7
--- /dev/null
+++ b/test/451-spill-splot/info.txt
@@ -0,0 +1,2 @@
+Regression test for the optimizing compiler and the
+way it spills intervals of different types.
diff --git a/test/451-spill-splot/src/Main.java b/test/451-spill-splot/src/Main.java
new file mode 100644
index 0000000..f631ebd
--- /dev/null
+++ b/test/451-spill-splot/src/Main.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    // Create a few local variables to make sure some get spilled, and we get
+    // a conflict of swapping a single entry stack slot (float) with a double entry
+    // stack slot (double).
+    double a = 0.0;
+    double b = 1.0;
+    double c = 2.0;
+    double d = 3.0;
+    double e = 4.0;
+    double f = 5.0;
+    double g = 6.0;
+    double h = 7.0;
+    double i = 8.0;
+    double j = 9.0;
+
+    float aa = 0;
+    float bb = 1;
+    float cc = 2;
+    float dd = 3;
+    float ee = 4;
+    float ff = 5;
+    float gg = 6;
+    float hh = 7;
+    float ii = 8;
+    float jj = 9;
+    float kk = 10;
+    float ll = 10;
+    float mm = 10;
+    float nn = 10;
+
+    for (int count = 0; count < 2; count++) {
+      System.out.println(aa + bb + cc + dd + ee + ff + gg + hh + ii + jj + kk + ll + mm + nn);
+      System.out.println(a + b + c + d + e + f + g + h + i + j);
+      a = computeDouble();
+      b = computeDouble();
+      c = computeDouble();
+      d = computeDouble();
+      e = computeDouble();
+      f = computeDouble();
+      g = computeDouble();
+      h = computeDouble();
+      i = computeDouble();
+      j = computeDouble();
+      System.out.println(a + b + c + d + e + f + g + h + i + j);
+      aa = computeFloat();
+      bb = computeFloat();
+      cc = computeFloat();
+      dd = computeFloat();
+      ee = computeFloat();
+      ff = computeFloat();
+      gg = computeFloat();
+      hh = computeFloat();
+      ii = computeFloat();
+      jj = computeFloat();
+      kk = computeFloat();
+      ll = computeFloat();
+      mm = computeFloat();
+      nn = computeFloat();
+    }
+  }
+
+  static boolean doThrow = false;
+
+  public static double computeDouble() {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
+    return 2.0;
+  }
+
+  public static float computeFloat() {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
+    return 4.0f;
+  }
+}