Jit: Fix for 2542488 JIT codegen bug with overlapping wide operands

Change-Id: I7b922e223fe1f5242d1f3db1fa18f54aaed725af
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 11d8268..54a5060 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -688,7 +688,7 @@
             dvmCompilerAbort(cUnit);
     }
     if (!callOut) {
-        genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
+        genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
     } else {
         // Adjust return regs in to handle case of rem returning r2/r3
         dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c
index 6d83e73..e357ba6 100644
--- a/vm/compiler/codegen/arm/RallocUtil.c
+++ b/vm/compiler/codegen/arm/RallocUtil.c
@@ -771,18 +771,28 @@
 {
     assert(loc.wide);
     if (loc.location == kLocDalvikFrame) {
+        // Are the dalvik regs already live in physical registers?
         RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
         RegisterInfo *infoHi = allocLive(cUnit,
               dvmCompilerSRegHi(loc.sRegLow), kAnyReg);
         bool match = true;
         match = match && (infoLo != NULL);
         match = match && (infoHi != NULL);
+        // Are they both core or both FP?
         match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+        // If a pair of floating point singles, are they properly aligned?
         if (match && FPREG(infoLo->reg)) {
             match &= ((infoLo->reg & 0x1) == 0);
             match &= ((infoHi->reg - infoLo->reg) == 1);
         }
+        // If previously used as a pair, it is the same pair?
+        if (match && (infoLo->pair || infoHi->pair)) {
+            match = (infoLo->pair == infoHi->pair);
+            match &= ((infoLo->reg == infoHi->partner) &&
+                      (infoHi->reg == infoLo->partner));
+        }
         if (match) {
+            // Can reuse - update the register usage info
             loc.lowReg = infoLo->reg;
             loc.highReg = infoHi->reg;
             loc.location = kLocPhysReg;
@@ -790,7 +800,7 @@
             assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
             return loc;
         }
-        /* Can't easily reuse - just clobber any overlaps */
+        // Can't easily reuse - clobber any overlaps
         if (infoLo) {
             dvmCompilerClobber(cUnit, infoLo->reg);
             if (infoLo->pair)
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.c b/vm/compiler/codegen/arm/Thumb/Gen.c
index ea5c1bc..aca68ef 100644
--- a/vm/compiler/codegen/arm/Thumb/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb/Gen.c
@@ -60,12 +60,22 @@
     storeValueWide(cUnit, rlDest, rlResult);
 }
 
-static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+static void partialOverlap(int sreg1, int sreg2)
+{
+    return abs(sreg1 - sreg2) == 1;
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
                          OpKind secondOp, RegLocation rlDest,
                          RegLocation rlSrc1, RegLocation rlSrc2)
 {
     RegLocation rlResult;
-   if (rlDest.sRegLow == rlSrc1.sRegLow) {
+    if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+        partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+        partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+        // Rare case - not enough registers to properly handle
+        genInterpSingleStep(cUnit, mir);
+    } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
         // Already 2-operand
         rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
         rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index 8a574b3..93120d6 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -71,7 +71,7 @@
     storeValueWide(cUnit, rlDest, rlResult);
 }
 
-static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
                          OpKind secondOp, RegLocation rlDest,
                          RegLocation rlSrc1, RegLocation rlSrc2)
 {