Merge "ART: Some conditions should be stricter in GenInlinedMinMax()"
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 4fe7a43..91168c7 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -863,22 +863,29 @@
RegLocation rl_src1 = info->args[0];
RegLocation rl_src2 = info->args[2];
RegLocation rl_dest = InlineTargetWide(info);
- int res_vreg, src1_vreg, src2_vreg;
if (rl_dest.s_reg_low == INVALID_SREG) {
// Result is unused, the code is dead. Inlining successful, no code generated.
return true;
}
+ if (PartiallyIntersects(rl_src1, rl_dest) &&
+ PartiallyIntersects(rl_src2, rl_dest)) {
+ // A special case which we don't want to handle.
+ // This is when src1 is mapped on v0 and v1,
+ // src2 is mapped on v2, v3,
+ // result is mapped on v1, v2
+ return false;
+ }
+
+
/*
* If the result register is the same as the second element, then we
* need to be careful. The reason is that the first copy will
* inadvertently clobber the second element with the first one thus
* yielding the wrong result. Thus we do a swap in that case.
*/
- res_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
- src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
- if (res_vreg == src2_vreg) {
+ if (Intersects(rl_src2, rl_dest)) {
std::swap(rl_src1, rl_src2);
}
@@ -893,19 +900,30 @@
* nothing else to do because they are equal and we have already
* moved one into the result.
*/
- src1_vreg = mir_graph_->SRegToVReg(rl_src1.s_reg_low);
- src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
- if (src1_vreg == src2_vreg) {
+ if (mir_graph_->SRegToVReg(rl_src1.s_reg_low) ==
+ mir_graph_->SRegToVReg(rl_src2.s_reg_low)) {
StoreValueWide(rl_dest, rl_result);
return true;
}
// Free registers to make some room for the second operand.
- // But don't try to free ourselves or promoted registers.
- if (res_vreg != src1_vreg &&
- IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
- FreeTemp(rl_src1.reg);
+ // But don't try to free part of a source which intersects
+ // part of result or promoted registers.
+
+ if (IsTemp(rl_src1.reg.GetLow()) &&
+ (rl_src1.reg.GetLowReg() != rl_result.reg.GetHighReg()) &&
+ (rl_src1.reg.GetLowReg() != rl_result.reg.GetLowReg())) {
+ // Is low part temporary and doesn't intersect any parts of result?
+ FreeTemp(rl_src1.reg.GetLow());
}
+
+ if (IsTemp(rl_src1.reg.GetHigh()) &&
+ (rl_src1.reg.GetHighReg() != rl_result.reg.GetLowReg()) &&
+ (rl_src1.reg.GetHighReg() != rl_result.reg.GetHighReg())) {
+ // Is high part temporary and doesn't intersect any parts of result?
+ FreeTemp(rl_src1.reg.GetHigh());
+ }
+
rl_src2 = LoadValueWide(rl_src2, kCoreReg);
// Do we have a free register for intermediate calculations?
@@ -939,12 +957,15 @@
// Let's put pop 'edi' here to break a bit the dependency chain.
if (tmp == rs_rDI) {
NewLIR1(kX86Pop32R, tmp.GetReg());
+ } else {
+ FreeTemp(tmp);
}
// Conditionally move the other integer into the destination register.
ConditionCode cc = is_min ? kCondGe : kCondLt;
OpCondRegReg(kOpCmov, cc, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
OpCondRegReg(kOpCmov, cc, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
+ FreeTemp(rl_src2.reg);
StoreValueWide(rl_dest, rl_result);
return true;
}