Quick compiler, out of registers fix

It turns out that the register pool sanity checker was not
working as expected, leaving some inconsistencies unreported.
This could result in "out of registers" failures, as well
as other more subtle problems.

This CL fixes the sanity checker, adds a lot more check and cleans
up the previously undetected episodes of insanity.

Cherry-pick of internal change 468162

Change-Id: Id2da97e99105a4c272c5fd256205a94b904ecea8
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 1ee59c6..876419c 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -68,7 +68,6 @@
     void AdjustSpillMask();
     void ClobberCallerSave();
     void FreeCallTemps();
-    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
     void MarkPreservedSingle(int v_reg, RegStorage reg);
     void MarkPreservedDouble(int v_reg, RegStorage reg);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 2d4834c..384a008 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -284,10 +284,10 @@
     ccode = FlipComparisonOrder(ccode);
   }
   if (rl_src2.is_const) {
-    RegLocation rl_temp = UpdateLocWide(rl_src2);
+    rl_src2 = UpdateLocWide(rl_src2);
     // Do special compare/branch against simple const operand if not already in registers.
     int64_t val = mir_graph_->ConstantValueWide(rl_src2);
-    if ((rl_temp.location != kLocPhysReg) &&
+    if ((rl_src2.location != kLocPhysReg) &&
         ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
       GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
       return;
@@ -1092,6 +1092,8 @@
         DCHECK(!res_hi.Valid());
         DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
         DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
+        // Will force free src1_hi, so must clobber.
+        Clobber(rl_src1.reg);
         FreeTemp(rl_src1.reg.GetHigh());
         res_hi = AllocTemp();
       }
@@ -1103,9 +1105,7 @@
               tmp1.GetReg());
       NewLIR4(kThumb2AddRRR, res_hi.GetReg(), tmp1.GetReg(), res_hi.GetReg(), 0);
       if (reg_status == 2) {
-        // Clobber rl_src1 since it was corrupted.
-        FreeTemp(rl_src1.reg);
-        Clobber(rl_src1.reg);
+        FreeTemp(rl_src1.reg.GetLow());
       }
     }
 
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 8cf1f86..f7a7fe8 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -609,18 +609,6 @@
   reg_pool_->next_dp_reg_ = 0;
 }
 
-void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
-  DCHECK(rl_keep.wide);
-  DCHECK(rl_free.wide);
-  if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
-      (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
-      (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
-      (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
-    // No overlap, free.
-    FreeTemp(rl_free.reg);
-  }
-}
-
 /*
  * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
  * instructions might call out to C/assembly helper functions.  Until
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index b0211d6..86d32f4 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -853,7 +853,7 @@
         load = NewLIR4(kThumb2LdrdI8, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg(),
                        encoded_disp);
       }
-      if ((displacement & ~1020) != 0 && !r_dest.IsFloat()) {
+      if ((displacement & ~1020) != 0 && r_dest.IsFloat()) {
         FreeTemp(r_ptr);
       }
       already_generated = true;
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 418a989..6a27a7e 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -68,7 +68,6 @@
     void AdjustSpillMask();
     void ClobberCallerSave();
     void FreeCallTemps();
-    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
     void MarkPreservedSingle(int v_reg, RegStorage reg);
     void MarkPreservedDouble(int v_reg, RegStorage reg);
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 10be0d6..18e605c 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -632,10 +632,6 @@
   reg_pool_->next_dp_reg_ = 0;
 }
 
-void Arm64Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
-  LOG(FATAL) << "Unexpected call to FreeRegLocTemps for Arm64";
-}
-
 /*
  * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
  * instructions might call out to C/assembly helper functions.  Until
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 24ed4a3..3662592 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1368,6 +1368,7 @@
   OpRegRegReg(kOpAdc, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), sign_reg);
   OpRegReg(kOpXor, rl_result.reg.GetLow(), sign_reg);
   OpRegReg(kOpXor, rl_result.reg.GetHigh(), sign_reg);
+  FreeTemp(sign_reg);
   StoreValueWide(rl_dest, rl_result);
   return true;
 }
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index 8fcb09b..f5e7e63 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -145,10 +145,11 @@
       // Wrong register class, realloc, copy and transfer ownership.
       RegStorage new_reg = AllocTypedTemp(rl_src.fp, op_kind);
       OpRegCopy(new_reg, rl_src.reg);
-      // Associate the old sreg with the new register and clobber the old register.
-      GetRegInfo(new_reg)->SetSReg(GetRegInfo(rl_src.reg)->SReg());
+      // Clobber the old reg.
       Clobber(rl_src.reg);
+      // ...and mark the new one live.
       rl_src.reg = new_reg;
+      MarkLive(rl_src);
     }
     return rl_src;
   }
@@ -222,10 +223,11 @@
       // Wrong register class, realloc, copy and transfer ownership.
       RegStorage new_regs = AllocTypedTempWide(rl_src.fp, op_kind);
       OpRegCopyWide(new_regs, rl_src.reg);
-      // Associate the old sreg with the new register and clobber the old register.
-      GetRegInfo(new_regs)->SetSReg(GetRegInfo(rl_src.reg)->SReg());
+      // Clobber the old regs.
       Clobber(rl_src.reg);
+      // ...and mark the new ones live.
       rl_src.reg = new_regs;
+      MarkLive(rl_src);
     }
     return rl_src;
   }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index c5b40da..0c59465 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -68,7 +68,6 @@
     void AdjustSpillMask();
     void ClobberCallerSave();
     void FreeCallTemps();
-    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
     void MarkPreservedSingle(int v_reg, RegStorage reg);
     void MarkPreservedDouble(int v_reg, RegStorage reg);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 35345e8..7a3da71 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -492,17 +492,6 @@
   reg_pool_->next_dp_reg_ = 1;
 }
 
-void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
-  DCHECK(rl_keep.wide);
-  DCHECK(rl_free.wide);
-  if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
-      (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
-      (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
-      (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
-    // No overlap, free.
-    FreeTemp(rl_free.reg);
-  }
-}
 /*
  * In the Arm code a it is typical to use the link register
  * to hold the target address.  However, for Mips we must
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index 2973e14..ba6865d 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -26,10 +26,9 @@
 /* Mark a temp register as dead.  Does not affect allocation state. */
 inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
   DCHECK(p->IsTemp());
-  if (!p->IsDead()) {
+  if (p->SReg() != INVALID_SREG) {
     DCHECK(!(p->IsLive() && p->IsDirty()))  << "Live & dirty temp in clobber";
     p->MarkDead();
-    p->ResetDefBody();
     if (p->IsWide()) {
       p->SetIsWide(false);
       if (p->GetReg() != p->Partner()) {
@@ -37,7 +36,6 @@
         p = GetRegInfo(p->Partner());
         p->SetIsWide(false);
         p->MarkDead();
-        p->ResetDefBody();
       }
     }
   }
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 10c2459..ea8071d 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -318,6 +318,8 @@
   int opt_flags = mir->optimization_flags;
   uint32_t vB = mir->dalvikInsn.vB;
   uint32_t vC = mir->dalvikInsn.vC;
+  DCHECK(CheckCorePoolSanity()) << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " @ 0x:"
+                                << std::hex << current_dalvik_offset_;
 
   // Prep Src and Dest locations.
   int next_sreg = 0;
@@ -946,6 +948,7 @@
     default:
       LOG(FATAL) << "Unexpected opcode: " << opcode;
   }
+  DCHECK(CheckCorePoolSanity());
 }  // NOLINT(readability/fn_size)
 
 // Process extended MIR instructions
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 3201b60..687c41d 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -339,23 +339,35 @@
       bool IsDead() { return (master_->liveness_ & storage_mask_) == 0; }
       // Liveness of this view matches.  Note: not equivalent to !IsDead().
       bool IsLive() { return (master_->liveness_ & storage_mask_) == storage_mask_; }
-      void MarkLive() { master_->liveness_ |= storage_mask_; }
+      void MarkLive(int s_reg) {
+        // TODO: Anything useful to assert here?
+        s_reg_ = s_reg;
+        master_->liveness_ |= storage_mask_;
+      }
       void MarkDead() {
-        master_->liveness_ &= ~storage_mask_;
-        SetSReg(INVALID_SREG);
+        if (SReg() != INVALID_SREG) {
+          s_reg_ = INVALID_SREG;
+          master_->liveness_ &= ~storage_mask_;
+          ResetDefBody();
+        }
       }
       RegStorage GetReg() { return reg_; }
       void SetReg(RegStorage reg) { reg_ = reg; }
       bool IsTemp() { return is_temp_; }
       void SetIsTemp(bool val) { is_temp_ = val; }
       bool IsWide() { return wide_value_; }
-      void SetIsWide(bool val) { wide_value_ = val; }
+      void SetIsWide(bool val) {
+        wide_value_ = val;
+        if (!val) {
+          // If not wide, reset partner to self.
+          SetPartner(GetReg());
+        }
+      }
       bool IsDirty() { return dirty_; }
       void SetIsDirty(bool val) { dirty_ = val; }
       RegStorage Partner() { return partner_; }
       void SetPartner(RegStorage partner) { partner_ = partner; }
-      int SReg() { return s_reg_; }
-      void SetSReg(int s_reg) { s_reg_ = s_reg; }
+      int SReg() { return (!IsTemp() || IsLive()) ? s_reg_ : INVALID_SREG; }
       uint64_t DefUseMask() { return def_use_mask_; }
       void SetDefUseMask(uint64_t def_use_mask) { def_use_mask_ = def_use_mask; }
       RegisterInfo* Master() { return master_; }
@@ -653,6 +665,7 @@
     RegStorage AllocLiveReg(int s_reg, int reg_class, bool wide);
     RegStorage FindLiveReg(GrowableArray<RegisterInfo*> &regs, int s_reg);
     void FreeTemp(RegStorage reg);
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     bool IsLive(RegStorage reg);
     bool IsTemp(RegStorage reg);
     bool IsPromoted(RegStorage reg);
@@ -671,10 +684,10 @@
     void FlushAllRegs();
     bool RegClassMatches(int reg_class, RegStorage reg);
     void MarkLive(RegLocation loc);
-    void MarkLiveReg(RegStorage reg, int s_reg);
     void MarkTemp(RegStorage reg);
     void UnmarkTemp(RegStorage reg);
     void MarkWide(RegStorage reg);
+    void MarkNarrow(RegStorage reg);
     void MarkClean(RegLocation loc);
     void MarkDirty(RegLocation loc);
     void MarkInUse(RegStorage reg);
@@ -1074,7 +1087,6 @@
     virtual void AdjustSpillMask() = 0;
     virtual void ClobberCallerSave() = 0;
     virtual void FreeCallTemps() = 0;
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) = 0;
     virtual void LockCallTemps() = 0;
     virtual void MarkPreservedSingle(int v_reg, RegStorage reg) = 0;
     virtual void MarkPreservedDouble(int v_reg, RegStorage reg) = 0;
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index bcc077b..06d05e2 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -152,6 +152,9 @@
   } else {
     RegisterInfo* info = GetRegInfo(reg);
     if (info->IsTemp() && !info->IsDead()) {
+      if (info->GetReg() != info->Partner()) {
+        ClobberBody(GetRegInfo(info->Partner()));
+      }
       ClobberBody(info);
       if (info->IsAliased()) {
         ClobberAliases(info);
@@ -169,19 +172,7 @@
   for (RegisterInfo* alias = info->GetAliasChain(); alias != nullptr;
        alias = alias->GetAliasChain()) {
     DCHECK(!alias->IsAliased());  // Only the master should be marked as alised.
-    if (alias->SReg() != INVALID_SREG) {
-      alias->SetSReg(INVALID_SREG);
-      alias->ResetDefBody();
-      if (alias->IsWide()) {
-        alias->SetIsWide(false);
-        if (alias->GetReg() != alias->Partner()) {
-          RegisterInfo* p = GetRegInfo(alias->Partner());
-          p->SetIsWide(false);
-          p->MarkDead();
-          p->ResetDefBody();
-        }
-      }
-    }
+    ClobberBody(alias);
   }
 }
 
@@ -204,6 +195,11 @@
     GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
     for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
       if (info->SReg() == s_reg) {
+        if (info->GetReg() != info->Partner()) {
+          // Dealing with a pair - clobber the other half.
+          DCHECK(!info->IsAliased());
+          ClobberBody(GetRegInfo(info->Partner()));
+        }
         ClobberBody(info);
         if (info->IsAliased()) {
           ClobberAliases(info);
@@ -325,7 +321,7 @@
       next = 0;
     RegisterInfo* info = regs.Get(next);
     // Try to allocate a register that doesn't hold a live value.
-    if (info->IsTemp() && !info->InUse() && !info->IsLive()) {
+    if (info->IsTemp() && !info->InUse() && info->IsDead()) {
       Clobber(info->GetReg());
       info->MarkInUse();
       /*
@@ -349,7 +345,13 @@
       ClobberSReg(info->SReg());
       Clobber(info->GetReg());
       info->MarkInUse();
-      info->SetIsWide(false);
+      if (info->IsWide()) {
+        RegisterInfo* partner = GetRegInfo(info->Partner());
+        DCHECK_EQ(info->GetReg().GetRegNum(), partner->Partner().GetRegNum());
+        DCHECK(partner->IsWide());
+        info->SetIsWide(false);
+        partner->SetIsWide(false);
+      }
       *next_temp = next + 1;
       return info->GetReg();
     }
@@ -463,6 +465,20 @@
   }
 }
 
+void Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
+  DCHECK(rl_keep.wide);
+  DCHECK(rl_free.wide);
+  int free_low = rl_free.reg.GetLowReg();
+  int free_high = rl_free.reg.GetHighReg();
+  int keep_low = rl_keep.reg.GetLowReg();
+  int keep_high = rl_keep.reg.GetHighReg();
+  if ((free_low != keep_low) && (free_low != keep_high) &&
+      (free_high != keep_low) && (free_high != keep_high)) {
+    // No overlap, free both
+    FreeTemp(rl_free.reg);
+  }
+}
+
 bool Mir2Lir::IsLive(RegStorage reg) {
   bool res;
   if (reg.IsPair()) {
@@ -725,8 +741,6 @@
       FlushSpecificReg(info);
     }
     info->MarkDead();
-    info->SetSReg(INVALID_SREG);
-    info->ResetDefBody();
     info->SetIsWide(false);
   }
 }
@@ -742,35 +756,48 @@
   }
 }
 
-void Mir2Lir::MarkLiveReg(RegStorage reg, int s_reg) {
-  RegisterInfo* info = GetRegInfo(reg);
-  if ((info->SReg() == s_reg) && info->IsLive()) {
-    return;  // Already live.
-  }
-  if (s_reg != INVALID_SREG) {
-    ClobberSReg(s_reg);
-    if (info->IsTemp()) {
-      info->MarkLive();
-    }
-  } else {
-    // Can't be live if no associated s_reg.
-    DCHECK(info->IsTemp());
-    info->MarkDead();
-  }
-  info->SetSReg(s_reg);
-}
-
 void Mir2Lir::MarkLive(RegLocation loc) {
   RegStorage reg = loc.reg;
+  if (!IsTemp(reg)) {
+    return;
+  }
   int s_reg = loc.s_reg_low;
-  if (reg.IsPair()) {
-    MarkLiveReg(reg.GetLow(), s_reg);
-    MarkLiveReg(reg.GetHigh(), s_reg+1);
-  } else {
-    if (loc.wide) {
-      ClobberSReg(s_reg + 1);
+  if (s_reg == INVALID_SREG) {
+    // Can't be live if no associated sreg.
+    if (reg.IsPair()) {
+      GetRegInfo(reg.GetLow())->MarkDead();
+      GetRegInfo(reg.GetHigh())->MarkDead();
+    } else {
+      GetRegInfo(reg)->MarkDead();
     }
-    MarkLiveReg(reg, s_reg);
+  } else {
+    if (reg.IsPair()) {
+      RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
+      RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+      if (info_lo->IsLive() && (info_lo->SReg() == s_reg) && info_hi->IsLive() &&
+          (info_hi->SReg() == s_reg)) {
+        return;  // Already live.
+      }
+      ClobberSReg(s_reg);
+      ClobberSReg(s_reg + 1);
+      info_lo->MarkLive(s_reg);
+      info_hi->MarkLive(s_reg + 1);
+    } else {
+      RegisterInfo* info = GetRegInfo(reg);
+      if (info->IsLive() && (info->SReg() == s_reg)) {
+        return;  // Already live.
+      }
+      ClobberSReg(s_reg);
+      if (loc.wide) {
+        ClobberSReg(s_reg + 1);
+      }
+      info->MarkLive(s_reg);
+    }
+    if (loc.wide) {
+      MarkWide(reg);
+    } else {
+      MarkNarrow(reg);
+    }
   }
 }
 
@@ -792,6 +819,13 @@
   if (reg.IsPair()) {
     RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
     RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+    // Unpair any old partners.
+    if (info_lo->IsWide() && info_lo->Partner() != info_hi->GetReg()) {
+      GetRegInfo(info_lo->Partner())->SetIsWide(false);
+    }
+    if (info_hi->IsWide() && info_hi->Partner() != info_lo->GetReg()) {
+      GetRegInfo(info_hi->Partner())->SetIsWide(false);
+    }
     info_lo->SetIsWide(true);
     info_hi->SetIsWide(true);
     info_lo->SetPartner(reg.GetHigh());
@@ -803,6 +837,13 @@
   }
 }
 
+void Mir2Lir::MarkNarrow(RegStorage reg) {
+  DCHECK(!reg.IsPair());
+  RegisterInfo* info = GetRegInfo(reg);
+  info->SetIsWide(false);
+  info->SetPartner(reg);
+}
+
 void Mir2Lir::MarkClean(RegLocation loc) {
   if (loc.reg.IsPair()) {
     RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
@@ -842,16 +883,17 @@
 }
 
 bool Mir2Lir::CheckCorePoolSanity() {
-  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->core_regs_);
+  GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
-    RegStorage my_reg = info->GetReg();
-    if (info->IsWide() && my_reg.IsPair()) {
+    if (info->IsTemp() && info->IsLive() && info->IsWide()) {
+      RegStorage my_reg = info->GetReg();
       int my_sreg = info->SReg();
       RegStorage partner_reg = info->Partner();
       RegisterInfo* partner = GetRegInfo(partner_reg);
       DCHECK(partner != NULL);
       DCHECK(partner->IsWide());
       DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg());
+      DCHECK(partner->IsLive());
       int partner_sreg = partner->SReg();
       if (my_sreg == INVALID_SREG) {
         DCHECK_EQ(partner_sreg, INVALID_SREG);
@@ -859,13 +901,41 @@
         int diff = my_sreg - partner_sreg;
         DCHECK((diff == 0) || (diff == -1) || (diff == 1));
       }
-    } else {
-      // TODO: add whatever sanity checks might be useful for 64BitSolo regs here.
-      // TODO: sanity checks for floating point pools?
     }
-    if (!info->IsLive()) {
-      DCHECK(info->DefStart() == NULL);
-      DCHECK(info->DefEnd() == NULL);
+    if (info->Master() != info) {
+      // Aliased.
+      if (info->IsLive() && (info->SReg() != INVALID_SREG)) {
+        // If I'm live, master should not be live, but should show liveness in alias set.
+        DCHECK_EQ(info->Master()->SReg(), INVALID_SREG);
+        DCHECK(!info->Master()->IsDead());
+      } else if (!info->IsDead()) {
+        // If I'm not live, but there is liveness in the set master must be live.
+        DCHECK_EQ(info->SReg(), INVALID_SREG);
+        DCHECK(info->Master()->IsLive());
+      }
+    }
+    if (info->IsAliased()) {
+      // Has child aliases.
+      DCHECK_EQ(info->Master(), info);
+      if (info->IsLive() && (info->SReg() != INVALID_SREG)) {
+        // Master live, no child should be dead - all should show liveness in set.
+        for (RegisterInfo* p = info->GetAliasChain(); p != nullptr; p = p->GetAliasChain()) {
+          DCHECK(!p->IsDead());
+          DCHECK_EQ(p->SReg(), INVALID_SREG);
+        }
+      } else if (!info->IsDead()) {
+        // Master not live, one or more aliases must be.
+        bool live_alias = false;
+        for (RegisterInfo* p = info->GetAliasChain(); p != nullptr; p = p->GetAliasChain()) {
+          live_alias |= p->IsLive();
+        }
+        DCHECK(live_alias);
+      }
+    }
+    if (info->IsLive() && (info->SReg() == INVALID_SREG)) {
+      // If not fully live, should have INVALID_SREG and def's should be null.
+      DCHECK(info->DefStart() == nullptr);
+      DCHECK(info->DefEnd() == nullptr);
     }
   }
   return true;
@@ -956,11 +1026,12 @@
     if (!RegClassMatches(reg_class, loc.reg)) {
       // Wrong register class.  Reallocate and transfer ownership.
       RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class);
-      // Associate the old sreg with the new register and clobber the old register.
-      GetRegInfo(new_regs)->SetSReg(GetRegInfo(loc.reg)->SReg());
+      // Clobber the old regs.
       Clobber(loc.reg);
+      // ...and mark the new ones live.
       loc.reg = new_regs;
       MarkWide(loc.reg);
+      MarkLive(loc);
     }
     return loc;
   }
@@ -989,10 +1060,11 @@
     if (!RegClassMatches(reg_class, loc.reg)) {
       // Wrong register class.  Reallocate and transfer ownership.
       RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
-      // Associate the old sreg with the new register and clobber the old register.
-      GetRegInfo(new_reg)->SetSReg(GetRegInfo(loc.reg)->SReg());
+      // Clobber the old reg.
       Clobber(loc.reg);
+      // ...and mark the new one live.
       loc.reg = new_reg;
+      MarkLive(loc);
     }
     return loc;
   }
@@ -1220,19 +1292,9 @@
   RegLocation gpr_res = LocCReturnWide();
   RegLocation fpr_res = LocCReturnDouble();
   RegLocation res = is_double ? fpr_res : gpr_res;
-  if (res.reg.IsPair()) {
-    Clobber(res.reg);
-    LockTemp(res.reg);
-    // Does this wide value live in two registers or one vector register?
-    if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
-      // FIXME: I think we want to mark these as wide as well.
-      MarkWide(res.reg);
-    }
-  } else {
-    Clobber(res.reg);
-    LockTemp(res.reg);
-    MarkWide(res.reg);
-  }
+  Clobber(res.reg);
+  LockTemp(res.reg);
+  MarkWide(res.reg);
   return res;
 }
 
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index cc0e1f2..52c870b 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -68,7 +68,6 @@
     void AdjustSpillMask();
     void ClobberCallerSave();
     void FreeCallTemps();
-    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
     void MarkPreservedSingle(int v_reg, RegStorage reg);
     void MarkPreservedDouble(int v_reg, RegStorage reg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index fbb1785..71a3962 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1542,7 +1542,6 @@
         LoadConstant(rl_result.reg.GetLow(), 0);
       } else if (shift_amount > 31) {
         OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
-        FreeTemp(rl_src.reg.GetHigh());
         NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32);
         LoadConstant(rl_result.reg.GetLow(), 0);
       } else {
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 237c68c..8f06791 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -572,20 +572,6 @@
   reg_pool_->next_dp_reg_ = 1;
 }
 
-void X86Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
-  DCHECK(rl_keep.wide);
-  DCHECK(rl_free.wide);
-  int free_low = rl_free.reg.GetLowReg();
-  int free_high = rl_free.reg.GetHighReg();
-  int keep_low = rl_keep.reg.GetLowReg();
-  int keep_high = rl_keep.reg.GetHighReg();
-  if ((free_low != keep_low) && (free_low != keep_high) &&
-      (free_high != keep_low) && (free_high != keep_high)) {
-    // No overlap, free both
-    FreeTemp(rl_free.reg);
-  }
-}
-
 void X86Mir2Lir::SpillCoreRegs() {
   if (num_core_spills_ == 0) {
     return;