Quick compiler: fix compile-time perf regression

The recent changes to the temp register liveness tracking
introduced a measureable compile-time performance regression.
This CL cleans it up.

Change-Id: Id698b93e957f0ecab7ddfab94727f85e49cf10cf
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index b5b50a4..2973e14 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -25,7 +25,8 @@
 
 /* Mark a temp register as dead.  Does not affect allocation state. */
 inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
-  if (p->IsTemp()) {
+  DCHECK(p->IsTemp());
+  if (!p->IsDead()) {
     DCHECK(!(p->IsLive() && p->IsDirty()))  << "Live & dirty temp in clobber";
     p->MarkDead();
     p->ResetDefBody();
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 0ffd189..77119a4 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -979,7 +979,7 @@
   }
 
   // Free temp registers and reset redundant store tracking.
-  ClobberAllRegs();
+  ClobberAllTemps();
 
   if (bb->block_type == kEntryBlock) {
     ResetRegPool();
@@ -994,7 +994,7 @@
   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
     ResetRegPool();
     if (cu_->disable_opt & (1 << kTrackLiveTemps)) {
-      ClobberAllRegs();
+      ClobberAllTemps();
       // Reset temp allocation to minimize differences when A/B testing.
       reg_pool_->ResetNextTemp();
     }
@@ -1074,7 +1074,7 @@
   // Free temp registers and reset redundant store tracking.
   ResetRegPool();
   ResetDefTracking();
-  ClobberAllRegs();
+  ClobberAllTemps();
 
   return GenSpecialCase(bb, mir, special);
 }
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 74245a4..eebd554 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -333,6 +333,9 @@
       bool InUse() { return (storage_mask_ & master_->used_storage_) != 0; }
       void MarkInUse() { master_->used_storage_ |= storage_mask_; }
       void MarkFree() { master_->used_storage_ &= ~storage_mask_; }
+      // No part of the containing storage is live in this view.
+      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 MarkDead() {
@@ -358,9 +361,13 @@
         master_ = master;
         if (master != this) {
           master_->aliased_ = true;
+          DCHECK(alias_chain_ == nullptr);
+          alias_chain_ = master_->alias_chain_;
+          master_->alias_chain_ = this;
         }
       }
       bool IsAliased() { return aliased_; }
+      RegisterInfo* GetAliasChain() { return alias_chain_; }
       uint32_t StorageMask() { return storage_mask_; }
       void SetStorageMask(uint32_t storage_mask) { storage_mask_ = storage_mask; }
       LIR* DefStart() { return def_start_; }
@@ -385,6 +392,7 @@
       uint32_t storage_mask_;      // Track allocation of sub-units.
       LIR *def_start_;             // Starting inst in last def sequence.
       LIR *def_end_;               // Ending inst in last def sequence.
+      RegisterInfo* alias_chain_;  // Chain of aliased registers.
     };
 
     class RegisterPool {
@@ -655,7 +663,7 @@
     void ResetDefLoc(RegLocation rl);
     void ResetDefLocWide(RegLocation rl);
     void ResetDefTracking();
-    void ClobberAllRegs();
+    void ClobberAllTemps();
     void FlushSpecificReg(RegisterInfo* info);
     void FlushAllRegs();
     bool RegClassMatches(int reg_class, RegStorage reg);
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index ca9a3ab..5e6e73b 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -40,7 +40,8 @@
 
 Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
   : reg_(r), is_temp_(false), wide_value_(false), dirty_(false), aliased_(false), partner_(r),
-    s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
+    s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this), def_start_(nullptr),
+    def_end_(nullptr), alias_chain_(nullptr) {
   switch (r.StorageSize()) {
     case 0: storage_mask_ = 0xffffffff; break;
     case 4: storage_mask_ = 0x00000001; break;
@@ -66,9 +67,13 @@
     next_sp_reg_(0), dp_regs_(arena, dp_regs.size()), next_dp_reg_(0), m2l_(m2l)  {
   // Initialize the fast lookup map.
   m2l_->reginfo_map_.Reset();
-  m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
-  for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
-    m2l_->reginfo_map_.Insert(nullptr);
+  if (kIsDebugBuild) {
+    m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
+    for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
+      m2l_->reginfo_map_.Insert(nullptr);
+    }
+  } else {
+    m2l_->reginfo_map_.SetSize(RegStorage::kMaxRegs);
   }
 
   // Construct the register pool.
@@ -139,29 +144,43 @@
 }
 
 void Mir2Lir::Clobber(RegStorage reg) {
-  if (reg.IsPair()) {
+  if (UNLIKELY(reg.IsPair())) {
     DCHECK(!GetRegInfo(reg.GetLow())->IsAliased());
-    ClobberBody(GetRegInfo(reg.GetLow()));
+    Clobber(reg.GetLow());
     DCHECK(!GetRegInfo(reg.GetHigh())->IsAliased());
-    ClobberBody(GetRegInfo(reg.GetHigh()));
+    Clobber(reg.GetHigh());
   } else {
     RegisterInfo* info = GetRegInfo(reg);
-    if (info->IsAliased()) {
-      ClobberAliases(info);
-    } else if (info != info->Master() && info->Master()->SReg() != INVALID_SREG) {
-      ClobberBody(info->Master());
+    if (info->IsTemp() && !info->IsDead()) {
+      ClobberBody(info);
+      if (info->IsAliased()) {
+        ClobberAliases(info);
+      } else {
+        RegisterInfo* master = info->Master();
+        if (info != master) {
+          ClobberBody(info->Master());
+        }
+      }
     }
-    ClobberBody(info);
   }
 }
 
 void Mir2Lir::ClobberAliases(RegisterInfo* info) {
-  DCHECK(info->IsAliased());
-  GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
-  for (RegisterInfo* tmpreg_info = iter.Next(); tmpreg_info != NULL; tmpreg_info = iter.Next()) {
-    if (tmpreg_info->Master() == info) {
-      // tmpreg_info is an alias of info.
-      ClobberBody(tmpreg_info);
+  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();
+        }
+      }
     }
   }
 }
@@ -185,11 +204,10 @@
     GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
     for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
       if (info->SReg() == s_reg) {
+        ClobberBody(info);
         if (info->IsAliased()) {
-          // TUNING: if this gets hot, we could add links to follow - aliasing is static.
           ClobberAliases(info);
         }
-        ClobberBody(info);
       }
     }
   }
@@ -645,7 +663,7 @@
   }
 }
 
-void Mir2Lir::ClobberAllRegs() {
+void Mir2Lir::ClobberAllTemps() {
   GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
   for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
     ClobberBody(info);
@@ -703,10 +721,9 @@
 void Mir2Lir::FlushAllRegs() {
   GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
-    if (info->IsLive() && info->IsDirty()) {
+    if (info->IsDirty() && info->IsLive()) {
       FlushSpecificReg(info);
     }
-    DCHECK(info->IsTemp());
     info->MarkDead();
     info->SetSReg(INVALID_SREG);
     info->ResetDefBody();