ART: Fix Quick's DCE+GVN

DCE_GVN does not take into account the following case:
  mov a, b
  ...
  mov c, b
when optimization tries to replace a with c it must ensure that
for all uses of a there is no new definition of c before use.
Otherwise that use will incorrectly substituted with new c instead
of original b.

Bug: 23102860
Change-Id: I48ee0bd4386419b0f9c814c21b3537a392518cd1
Signed-off-by: Serguei Katkov <serguei.i.katkov@intel.com>
diff --git a/compiler/dex/gvn_dead_code_elimination.cc b/compiler/dex/gvn_dead_code_elimination.cc
index d29b865..4de3410 100644
--- a/compiler/dex/gvn_dead_code_elimination.cc
+++ b/compiler/dex/gvn_dead_code_elimination.cc
@@ -715,6 +715,7 @@
     // Try to find a MOVE to a vreg that wasn't changed since check_change.
     uint16_t value_name =
         data->wide_def ? lvn_->GetSregValueWide(dest_s_reg) : lvn_->GetSregValue(dest_s_reg);
+    uint32_t dest_v_reg = mir_graph_->SRegToVReg(dest_s_reg);
     for (size_t c = check_change + 1u, size = vreg_chains_.NumMIRs(); c != size; ++c) {
       MIRData* d = vreg_chains_.GetMIRData(c);
       if (d->is_move && d->wide_def == data->wide_def &&
@@ -731,8 +732,21 @@
           if (!vreg_chains_.IsVRegUsed(check_change + 1u, c, new_dest_v_reg, mir_graph_) &&
               (!d->wide_def ||
                !vreg_chains_.IsVRegUsed(check_change + 1u, c, new_dest_v_reg + 1, mir_graph_))) {
-            RecordPassKillMoveByRenamingSrcDef(check_change, c);
-            return;
+            // If the move's destination vreg changed, check if the vreg we're trying
+            // to rename is unused after that change.
+            uint16_t dest_change = vreg_chains_.FindFirstChangeAfter(new_dest_v_reg, c);
+            if (d->wide_def) {
+              uint16_t dest_change_high = vreg_chains_.FindFirstChangeAfter(new_dest_v_reg + 1, c);
+              if (dest_change_high != kNPos &&
+                  (dest_change == kNPos || dest_change_high < dest_change)) {
+                dest_change = dest_change_high;
+              }
+            }
+            if (dest_change == kNPos ||
+                !vreg_chains_.IsVRegUsed(dest_change + 1u, size, dest_v_reg, mir_graph_)) {
+              RecordPassKillMoveByRenamingSrcDef(check_change, c);
+              return;
+            }
           }
         }
       }