Merge "Workaround for range ops spanning vreg gap"
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 7ce8f69..8ef80fa 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -1004,6 +1004,11 @@
     return false;
   }
 
+  // Contains a pattern we don't want to compile?
+  if (punt_to_interpreter_) {
+    return true;
+  }
+
   if (compiler_filter == CompilerOptions::kInterpretOnly) {
     LOG(WARNING) << "InterpretOnly should ideally be filtered out prior to parsing.";
     return true;
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index e4550d1..2bfc154 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -86,7 +86,8 @@
       forward_branches_(0),
       compiler_temps_(arena, 6, kGrowableArrayMisc),
       num_non_special_compiler_temps_(0),
-      max_available_non_special_compiler_temps_(0) {
+      max_available_non_special_compiler_temps_(0),
+      punt_to_interpreter_(false) {
   try_block_addr_ = new (arena_) ArenaBitVector(arena_, 0, true /* expandable */);
   max_available_special_compiler_temps_ = std::abs(static_cast<int>(kVRegNonSpecialTempBaseReg))
       - std::abs(static_cast<int>(kVRegTempBaseReg));
@@ -610,6 +611,7 @@
     }
 
     int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
+    int verify_flags = Instruction::VerifyFlagsOf(insn->dalvikInsn.opcode);
 
     uint64_t df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode];
 
@@ -676,6 +678,19 @@
     } else if (flags & Instruction::kSwitch) {
       cur_block = ProcessCanSwitch(cur_block, insn, current_offset_, width, flags);
     }
+    if (verify_flags & Instruction::kVerifyVarArgRange) {
+      /*
+       * The Quick backend's runtime model includes a gap between a method's
+       * argument ("in") vregs and the rest of its vregs.  Handling a range instruction
+       * which spans the gap is somewhat complicated, and should not happen
+       * in normal usage of dx.  Punt to the interpreter.
+       */
+      int first_reg_in_range = insn->dalvikInsn.vC;
+      int last_reg_in_range = first_reg_in_range + insn->dalvikInsn.vA - 1;
+      if (IsInVReg(first_reg_in_range) != IsInVReg(last_reg_in_range)) {
+        punt_to_interpreter_ = true;
+      }
+    }
     current_offset_ += width;
     BasicBlock *next_block = FindBlock(current_offset_, /* split */ false, /* create */
                                       false, /* immed_pred_block_p */ NULL);
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index d344055..28e9470 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -684,6 +684,11 @@
     return opcode >= static_cast<int>(kMirOpFirst);
   }
 
+  // Is this vreg in the in set?
+  bool IsInVReg(int vreg) {
+    return (vreg >= cu_->num_regs);
+  }
+
   void DumpCheckStats();
   MIR* FindMoveResult(BasicBlock* bb, MIR* mir);
   int SRegToVReg(int ssa_reg) const;
@@ -917,6 +922,7 @@
   size_t num_non_special_compiler_temps_;
   size_t max_available_non_special_compiler_temps_;
   size_t max_available_special_compiler_temps_;
+  bool punt_to_interpreter_;                    // Difficult or not worthwhile - just interpret.
 
   friend class LocalValueNumberingTest;
 };
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index c434cdd..4352c4a 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -422,6 +422,11 @@
     return kInstructionFlags[opcode];
   }
 
+  // Return the verify flags for the given opcode.
+  static int VerifyFlagsOf(Code opcode) {
+    return kInstructionVerifyFlags[opcode];
+  }
+
   // Returns true if this instruction is a branch.
   bool IsBranch() const {
     return (kInstructionFlags[Opcode()] & kBranch) != 0;