Quick compiler: debugging assists

A few minor assists to ease A/B debugging in the Quick
compiler:
   1.  To save time, the assemblers for some targets only
update the object code offsets on instructions involved with
pc-relative fixups.  We add code to fix up all offsets when
doing a verbose codegen listing.
   2.  Temp registers are normally allocated in a round-robin
fashion.  When disabling liveness tracking, we now reset the
round-robin pool to 0 on each instruction boundary.  This makes
it easier to spot real codegen differences.
   3.  Self-register copies were previously emitted, but
marked as nops.  Minor change to avoid generating them in the
first place and reduce clutter.

Change-Id: I7954bba3b9f16ee690d663be510eac7034c93723
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index a89b307..646859c 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -160,7 +160,7 @@
     LIR* OpMem(OpKind op, RegStorage r_base, int disp);
     LIR* OpPcRelLoad(RegStorage reg, LIR* target);
     LIR* OpReg(OpKind op, RegStorage r_dest_src);
-    LIR* OpRegCopy(RegStorage r_dest, RegStorage r_src);
+    void OpRegCopy(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegImm(OpKind op, RegStorage r_dest_src1, int value);
     LIR* OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index f47e693..a2d6373 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -361,37 +361,40 @@
   return res;
 }
 
-LIR* ArmMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
-  LIR* res = OpRegCopyNoInsert(r_dest, r_src);
-  AppendLIR(res);
-  return res;
+void ArmMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
+  if (r_dest != r_src) {
+    LIR* res = OpRegCopyNoInsert(r_dest, r_src);
+    AppendLIR(res);
+  }
 }
 
 void ArmMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
-  bool dest_fp = ARM_FPREG(r_dest.GetLowReg());
-  bool src_fp = ARM_FPREG(r_src.GetLowReg());
-  if (dest_fp) {
-    if (src_fp) {
-      // FIXME: handle 64-bit solo's here.
-      OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
-    } else {
-      NewLIR3(kThumb2Fmdrr, S2d(r_dest.GetLowReg(), r_dest.GetHighReg()),
-              r_src.GetLowReg(), r_src.GetHighReg());
-    }
-  } else {
-    if (src_fp) {
-      NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), S2d(r_src.GetLowReg(),
-              r_src.GetHighReg()));
-    } else {
-      // Handle overlap
-      if (r_src.GetHighReg() == r_dest.GetLowReg()) {
-        DCHECK_NE(r_src.GetLowReg(), r_dest.GetHighReg());
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+  if (r_dest != r_src) {
+    bool dest_fp = ARM_FPREG(r_dest.GetLowReg());
+    bool src_fp = ARM_FPREG(r_src.GetLowReg());
+    if (dest_fp) {
+      if (src_fp) {
+        // FIXME: handle 64-bit solo's here.
+        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
+                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
       } else {
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        NewLIR3(kThumb2Fmdrr, S2d(r_dest.GetLowReg(), r_dest.GetHighReg()),
+                r_src.GetLowReg(), r_src.GetHighReg());
+      }
+    } else {
+      if (src_fp) {
+        NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), S2d(r_src.GetLowReg(),
+                r_src.GetHighReg()));
+      } else {
+        // Handle overlap
+        if (r_src.GetHighReg() == r_dest.GetLowReg()) {
+          DCHECK_NE(r_src.GetLowReg(), r_dest.GetHighReg());
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+        } else {
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        }
       }
     }
   }
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 677ee15..501e4e20 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -274,6 +274,19 @@
   }
 }
 
+void Mir2Lir::UpdateLIROffsets() {
+  // Only used for code listings.
+  size_t offset = 0;
+  for (LIR* lir = first_lir_insn_; lir != nullptr; lir = lir->next) {
+    lir->offset = offset;
+    if (!lir->flags.is_nop && !IsPseudoLirOp(lir->opcode)) {
+      offset += GetInsnSize(lir);
+    } else if (lir->opcode == kPseudoPseudoAlign4) {
+      offset += (offset & 0x2);
+    }
+  }
+}
+
 /* Dump instructions and constant pool contents */
 void Mir2Lir::CodegenDump() {
   LOG(INFO) << "Dumping LIR insns for "
@@ -293,6 +306,7 @@
   LOG(INFO) << "expansion factor: "
             << static_cast<float>(total_size_) / static_cast<float>(insns_size * 2);
   DumpPromotionMap();
+  UpdateLIROffsets();
   for (lir_insn = first_lir_insn_; lir_insn != NULL; lir_insn = lir_insn->next) {
     DumpLIRInsn(lir_insn, 0);
   }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index da65f34..81d6782 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -159,7 +159,7 @@
     LIR* OpMem(OpKind op, RegStorage r_base, int disp);
     LIR* OpPcRelLoad(RegStorage reg, LIR* target);
     LIR* OpReg(OpKind op, RegStorage r_dest_src);
-    LIR* OpRegCopy(RegStorage r_dest, RegStorage r_src);
+    void OpRegCopy(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegImm(OpKind op, RegStorage r_dest_src1, int value);
     LIR* OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 88d5d2b..7c0becd 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -177,37 +177,40 @@
   return res;
 }
 
-LIR* MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
-  LIR *res = OpRegCopyNoInsert(r_dest, r_src);
-  AppendLIR(res);
-  return res;
+void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
+  if (r_dest != r_src) {
+    LIR *res = OpRegCopyNoInsert(r_dest, r_src);
+    AppendLIR(res);
+  }
 }
 
 void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
-  bool dest_fp = MIPS_FPREG(r_dest.GetLowReg());
-  bool src_fp = MIPS_FPREG(r_src.GetLowReg());
-  if (dest_fp) {
-    if (src_fp) {
-      // FIXME: handle this here - reserve OpRegCopy for 32-bit copies.
-      OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+  if (r_dest != r_src) {
+    bool dest_fp = MIPS_FPREG(r_dest.GetLowReg());
+    bool src_fp = MIPS_FPREG(r_src.GetLowReg());
+    if (dest_fp) {
+      if (src_fp) {
+        // FIXME: handle this here - reserve OpRegCopy for 32-bit copies.
+        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
+                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+        } else {
+          /* note the operands are swapped for the mtc1 instr */
+          NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
+          NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
+      }
     } else {
-       /* note the operands are swapped for the mtc1 instr */
-      NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
-      NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
-    }
-  } else {
-    if (src_fp) {
-      NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
-      NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
-    } else {
-      // Handle overlap
-      if (r_src.GetHighReg() == r_dest.GetLowReg()) {
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+      if (src_fp) {
+        NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
+        NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
       } else {
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        // Handle overlap
+        if (r_src.GetHighReg() == r_dest.GetLowReg()) {
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+        } else {
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        }
       }
     }
   }
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6d38488..b8ab609 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -990,6 +990,9 @@
     ResetRegPool();
     if (cu_->disable_opt & (1 << kTrackLiveTemps)) {
       ClobberAllRegs();
+      // Reset temp allocation to minimize differences when A/B testing.
+      reg_pool_->next_core_reg = 0;
+      reg_pool_->next_fp_reg = 0;
     }
 
     if (cu_->disable_opt & (1 << kSuppressLoads)) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 8d593ae..2b6d78b 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -811,6 +811,8 @@
     bool MethodBlockCodeGen(BasicBlock* bb);
     bool SpecialMIR2LIR(const InlineMethod& special);
     void MethodMIR2LIR();
+    // Update LIR for verbose listings.
+    void UpdateLIROffsets();
 
     /*
      * @brief Load the address of the dex method into the register.
@@ -1050,7 +1052,7 @@
     virtual LIR* OpMem(OpKind op, RegStorage r_base, int disp) = 0;
     virtual LIR* OpPcRelLoad(RegStorage reg, LIR* target) = 0;
     virtual LIR* OpReg(OpKind op, RegStorage r_dest_src) = 0;
-    virtual LIR* OpRegCopy(RegStorage r_dest, RegStorage r_src) = 0;
+    virtual void OpRegCopy(RegStorage r_dest, RegStorage r_src) = 0;
     virtual LIR* OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) = 0;
     virtual LIR* OpRegImm(OpKind op, RegStorage r_dest_src1, int value) = 0;
     virtual LIR* OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset) = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index fb61627..760290c 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -232,7 +232,7 @@
     LIR* OpMem(OpKind op, RegStorage r_base, int disp);
     LIR* OpPcRelLoad(RegStorage reg, LIR* target);
     LIR* OpReg(OpKind op, RegStorage r_dest_src);
-    LIR* OpRegCopy(RegStorage r_dest, RegStorage r_src);
+    void OpRegCopy(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src);
     LIR* OpRegImm(OpKind op, RegStorage r_dest_src1, int value);
     LIR* OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 5ba9709..3bff497 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -116,52 +116,55 @@
   return res;
 }
 
-LIR* X86Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
-  LIR *res = OpRegCopyNoInsert(r_dest, r_src);
-  AppendLIR(res);
-  return res;
+void X86Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
+  if (r_dest != r_src) {
+    LIR *res = OpRegCopyNoInsert(r_dest, r_src);
+    AppendLIR(res);
+  }
 }
 
 void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
-  // FIXME: handle k64BitSolo when we start using them.
-  DCHECK(r_dest.IsPair());
-  DCHECK(r_src.IsPair());
-  bool dest_fp = X86_FPREG(r_dest.GetLowReg());
-  bool src_fp = X86_FPREG(r_src.GetLowReg());
-  if (dest_fp) {
-    if (src_fp) {
-      // TODO: we ought to handle this case here - reserve OpRegCopy for 32-bit copies.
-      OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
-    } else {
-      // TODO: Prevent this from happening in the code. The result is often
-      // unused or could have been loaded more easily from memory.
-      NewLIR2(kX86MovdxrRR, r_dest.GetLowReg(), r_src.GetLowReg());
-      RegStorage r_tmp = AllocTempDouble();
-      NewLIR2(kX86MovdxrRR, r_tmp.GetLowReg(), r_src.GetHighReg());
-      NewLIR2(kX86PunpckldqRR, r_dest.GetLowReg(), r_tmp.GetLowReg());
-      FreeTemp(r_tmp);
-    }
-  } else {
-    if (src_fp) {
-      NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetLowReg());
-      NewLIR2(kX86PsrlqRI, r_src.GetLowReg(), 32);
-      NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetLowReg());
-    } else {
-      // Handle overlap
-      if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) {
-        // Deal with cycles.
-        RegStorage temp_reg = AllocTemp();
-        OpRegCopy(temp_reg, r_dest.GetHigh());
-        OpRegCopy(r_dest.GetHigh(), r_dest.GetLow());
-        OpRegCopy(r_dest.GetLow(), temp_reg);
-        FreeTemp(temp_reg);
-      } else if (r_src.GetHighReg() == r_dest.GetLowReg()) {
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+  if (r_dest != r_src) {
+    // FIXME: handle k64BitSolo when we start using them.
+    DCHECK(r_dest.IsPair());
+    DCHECK(r_src.IsPair());
+    bool dest_fp = X86_FPREG(r_dest.GetLowReg());
+    bool src_fp = X86_FPREG(r_src.GetLowReg());
+    if (dest_fp) {
+      if (src_fp) {
+        // TODO: we ought to handle this case here - reserve OpRegCopy for 32-bit copies.
+        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
+                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
       } else {
-        OpRegCopy(r_dest.GetLow(), r_src.GetLow());
-        OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        // TODO: Prevent this from happening in the code. The result is often
+        // unused or could have been loaded more easily from memory.
+        NewLIR2(kX86MovdxrRR, r_dest.GetLowReg(), r_src.GetLowReg());
+        RegStorage r_tmp = AllocTempDouble();
+        NewLIR2(kX86MovdxrRR, r_tmp.GetLowReg(), r_src.GetHighReg());
+        NewLIR2(kX86PunpckldqRR, r_dest.GetLowReg(), r_tmp.GetLowReg());
+        FreeTemp(r_tmp);
+      }
+    } else {
+      if (src_fp) {
+        NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetLowReg());
+        NewLIR2(kX86PsrlqRI, r_src.GetLowReg(), 32);
+        NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetLowReg());
+      } else {
+        // Handle overlap
+        if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) {
+          // Deal with cycles.
+          RegStorage temp_reg = AllocTemp();
+          OpRegCopy(temp_reg, r_dest.GetHigh());
+          OpRegCopy(r_dest.GetHigh(), r_dest.GetLow());
+          OpRegCopy(r_dest.GetLow(), temp_reg);
+          FreeTemp(temp_reg);
+        } else if (r_src.GetHighReg() == r_dest.GetLowReg()) {
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+        } else {
+          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
+          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
+        }
       }
     }
   }
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 00bebd2..4d45055 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -426,7 +426,8 @@
         RegStorage t_reg = AllocTemp();
         OpRegCopy(t_reg, r_src1);
         OpRegReg(op, t_reg, r_src2);
-        LIR* res = OpRegCopy(r_dest, t_reg);
+        LIR* res = OpRegCopyNoInsert(r_dest, t_reg);
+        AppendLIR(res);
         FreeTemp(t_reg);
         return res;
       }