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;