Reland "Remove unneeded debug use markers."

This reverts commit 7bfeea9e5bf5dcd2421d4d8363ba613137745afe.

Bug: 157466079
Bug: 142855947

Change-Id: I3fa9af1b2fcdc16d4fc49e1a3cc9f86c25c5fbbc
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 2c3d9a5..b0ef472 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -1292,36 +1292,17 @@
       builder.append(": ");
       builder.append(instruction.toString());
       if (DebugLocalInfo.PRINT_LEVEL != PrintLevel.NONE) {
-        List<Value> localEnds = new ArrayList<>(instruction.getDebugValues().size());
-        List<Value> localStarts = new ArrayList<>(instruction.getDebugValues().size());
-        List<Value> localLive = new ArrayList<>(instruction.getDebugValues().size());
-        for (Value value : instruction.getDebugValues()) {
-          if (value.getDebugLocalEnds().contains(instruction)) {
-            localEnds.add(value);
-          } else if (value.getDebugLocalStarts().contains(instruction)) {
-            localStarts.add(value);
-          } else {
-            assert value.debugUsers().contains(instruction);
-            localLive.add(value);
-          }
+        if (!instruction.getDebugValues().isEmpty()) {
+          builder.append(" [end: ");
+          StringUtils.append(builder, instruction.getDebugValues(), ", ", BraceType.NONE);
+          builder.append("]");
         }
-        printDebugValueSet("live", localLive, builder);
-        printDebugValueSet("end", localEnds, builder);
-        printDebugValueSet("start", localStarts, builder);
       }
       builder.append("\n");
     }
     return builder.toString();
   }
 
-  private void printDebugValueSet(String header, List<Value> locals, StringBuilder builder) {
-    if (!locals.isEmpty()) {
-      builder.append(" [").append(header).append(": ");
-      StringUtils.append(builder, locals, ", ", BraceType.NONE);
-      builder.append("]");
-    }
-  }
-
   public void print(CfgPrinter printer) {
     printer.begin("block");
     printer.print("name \"B").append(number).append("\"\n");
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index a0af5e2..32e5dea 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -245,10 +245,14 @@
             liveStack.addLast(use);
           }
         }
-        assert instruction.getDebugValues().stream().allMatch(Value::needsRegister);
-        assert instruction.getDebugValues().stream().allMatch(Value::hasLocalInfo);
-        live.addAll(instruction.getDebugValues());
-        liveLocals.addAll(instruction.getDebugValues());
+        if (!instruction.getDebugValues().isEmpty()) {
+          ArrayList<Value> sortedValues = new ArrayList<>(instruction.getDebugValues());
+          sortedValues.sort(Value::compareTo);
+          assert sortedValues.stream().allMatch(Value::needsRegister);
+          assert sortedValues.stream().allMatch(Value::hasLocalInfo);
+          live.addAll(sortedValues);
+          liveLocals.addAll(sortedValues);
+        }
       }
       for (Phi phi : block.getPhis()) {
         if (phi.isValueOnStack()) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 9e25dcf..6e5dfa3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -32,9 +32,9 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.StringUtils.BraceType;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
@@ -45,7 +45,7 @@
   protected final List<Value> inValues = new ArrayList<>();
   private BasicBlock block = null;
   private int number = -1;
-  private LinkedHashSet<Value> debugValues = null;
+  private Set<Value> debugValues = null;
   private Position position = null;
 
   protected Instruction(Value outValue) {
@@ -154,11 +154,9 @@
   public void addDebugValue(Value value) {
     assert value.hasLocalInfo();
     if (debugValues == null) {
-      debugValues = new LinkedHashSet<>();
+      debugValues = Sets.newIdentityHashSet();
     }
-    if (debugValues.add(value)) {
-      value.addDebugUser(this);
-    }
+    debugValues.add(value);
   }
 
   public static void clearUserInfo(Instruction instruction) {
@@ -197,17 +195,19 @@
   }
 
   public void replaceDebugValue(Value oldValue, Value newValue) {
-    if (debugValues.remove(oldValue)) {
-      assert newValue.getLocalInfo() == oldValue.getLocalInfo()
-          : "Replacing debug values with inconsistent locals "
-              + oldValue.getLocalInfo()
-              + " and "
-              + newValue.getLocalInfo()
-              + ". This is likely a code transformation bug "
-              + "that has not taken local information into account";
-      if (newValue.hasLocalInfo()) {
-        addDebugValue(newValue);
-      }
+    assert oldValue.hasLocalInfo();
+    assert newValue.hasLocalInfo();
+    assert newValue.getLocalInfo() == oldValue.getLocalInfo()
+        : "Replacing debug values with inconsistent locals "
+            + oldValue.getLocalInfo()
+            + " and "
+            + newValue.getLocalInfo()
+            + ". This is likely a code transformation bug "
+            + "that has not taken local information into account";
+    boolean removed = debugValues.remove(oldValue);
+    assert removed;
+    if (removed && newValue.hasLocalInfo()) {
+      newValue.addDebugLocalEnd(this);
     }
   }
 
@@ -221,12 +221,6 @@
     debugValues.clear();
   }
 
-  public void moveDebugValue(Value value, Instruction target) {
-    assert debugValues.contains(value);
-    value.replaceDebugUser(this, target);
-    debugValues.remove(value);
-  }
-
   public void removeDebugValue(Value value) {
     assert value.hasLocalInfo();
     if (debugValues != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index f49c1e3..4b9b2d1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -37,14 +37,10 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.ints.IntList;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -153,65 +149,13 @@
   private static class DebugData {
 
     final DebugLocalInfo local;
-    Map<Instruction, DebugUse> users = new HashMap<>();
+    Set<Instruction> users = Sets.newIdentityHashSet();
 
     DebugData(DebugLocalInfo local) {
       this.local = local;
     }
   }
 
-  // A debug-value user represents a point where the value is live, ends or starts.
-  // If a point is marked as both ending and starting then it is simply live, but we maintain
-  // the marker so as not to unintentionally end it if marked again.
-  // TODO(b/157466079): Clean/remove the use markers. With the current local construction in the
-  //   IRBuilder, the only needed markers should be 'end' markers.
-  private enum DebugUse {
-    LIVE, START, END, LIVE_FINAL;
-
-    DebugUse start() {
-      switch (this) {
-        case LIVE:
-        case START:
-          return START;
-        case END:
-        case LIVE_FINAL:
-          return LIVE_FINAL;
-        default:
-          throw new Unreachable();
-      }
-    }
-
-    DebugUse end() {
-      switch (this) {
-        case LIVE:
-        case END:
-          return END;
-        case START:
-        case LIVE_FINAL:
-          return LIVE_FINAL;
-        default:
-          throw new Unreachable();
-      }
-    }
-
-    static DebugUse join(DebugUse a, DebugUse b) {
-      if (a == LIVE_FINAL || b == LIVE_FINAL) {
-        return LIVE_FINAL;
-      }
-      if (a == b) {
-        return a;
-      }
-      if (a == LIVE) {
-        return b;
-      }
-      if (b == LIVE) {
-        return a;
-      }
-      assert (a == START && b == END) || (a == END && b == START);
-      return LIVE_FINAL;
-    }
-  }
-
   public static final int UNDEFINED_NUMBER = -1;
 
   public static final Value UNDEFINED = new Value(UNDEFINED_NUMBER, TypeElement.getBottom(), null);
@@ -328,62 +272,16 @@
     debugData = new DebugData(local);
   }
 
-  public void clearLocalInfo() {
-    assert debugData.users.isEmpty();
-    debugData = null;
-  }
-
-  public boolean hasSameOrNoLocal(Value other) {
-    assert other != null;
-    return hasLocalInfo()
-        ? other.getLocalInfo() == this.getLocalInfo()
-        : !other.hasLocalInfo();
-  }
-
-  public List<Instruction> getDebugLocalStarts() {
-    if (debugData == null) {
-      return Collections.emptyList();
-    }
-    List<Instruction> starts = new ArrayList<>(debugData.users.size());
-    for (Entry<Instruction, DebugUse> entry : debugData.users.entrySet()) {
-      if (entry.getValue() == DebugUse.START) {
-        starts.add(entry.getKey());
-      }
-    }
-    return starts;
-  }
-
-  public List<Instruction> getDebugLocalEnds() {
-    if (debugData == null) {
-      return Collections.emptyList();
-    }
-    List<Instruction> ends = new ArrayList<>(debugData.users.size());
-    for (Entry<Instruction, DebugUse> entry : debugData.users.entrySet()) {
-      if (entry.getValue() == DebugUse.END) {
-        ends.add(entry.getKey());
-      }
-    }
-    return ends;
-  }
-
-  public void addDebugLocalStart(Instruction start) {
-    assert start != null;
-    debugData.users.put(start, markStart(debugData.users.get(start)));
-  }
-
-  private DebugUse markStart(DebugUse use) {
-    assert use != null;
-    return use == null ? DebugUse.START : use.start();
+  public Set<Instruction> getDebugLocalEnds() {
+    return debugData == null
+        ? Collections.emptySet()
+        : Collections.unmodifiableSet(debugData.users);
   }
 
   public void addDebugLocalEnd(Instruction end) {
     assert end != null;
-    debugData.users.put(end, markEnd(debugData.users.get(end)));
-  }
-
-  private DebugUse markEnd(DebugUse use) {
-    assert use != null;
-    return use == null ? DebugUse.END : use.end();
+    debugData.users.add(end);
+    end.addDebugValue(this);
   }
 
   public void linkTo(Value other) {
@@ -493,7 +391,7 @@
   }
 
   public Set<Instruction> debugUsers() {
-    return debugData == null ? null : Collections.unmodifiableSet(debugData.users.keySet());
+    return debugData == null ? null : Collections.unmodifiableSet(debugData.users);
   }
 
   public boolean hasAnyUsers() {
@@ -620,11 +518,6 @@
     uniquePhiUsers = null;
   }
 
-  public void addDebugUser(Instruction user) {
-    assert hasLocalInfo();
-    debugData.users.putIfAbsent(user, DebugUse.LIVE);
-  }
-
   public boolean isUninitializedLocal() {
     return definition != null && definition.isDebugLocalUninitialized();
   }
@@ -686,7 +579,7 @@
       user.replaceOperand(this, newValue);
     }
     if (debugData != null) {
-      for (Entry<Instruction, DebugUse> user : debugData.users.entrySet()) {
+      for (Instruction user : debugData.users) {
         replaceUserInDebugData(user, newValue);
       }
       debugData.users.clear();
@@ -748,10 +641,10 @@
       }
     }
     if (debugData != null) {
-      Iterator<Entry<Instruction, DebugUse>> users = debugData.users.entrySet().iterator();
+      Iterator<Instruction> users = debugData.users.iterator();
       while (users.hasNext()) {
-        Entry<Instruction, DebugUse> user = users.next();
-        if (selectedInstructions.contains(user.getKey())) {
+        Instruction user = users.next();
+        if (selectedInstructions.contains(user)) {
           replaceUserInDebugData(user, newValue);
           users.remove();
         }
@@ -759,30 +652,18 @@
     }
   }
 
-  private void replaceUserInDebugData(Entry<Instruction, DebugUse> user, Value newValue) {
-    Instruction instruction = user.getKey();
-    DebugUse debugUse = user.getValue();
-    instruction.replaceDebugValue(this, newValue);
+  private void replaceUserInDebugData(Instruction user, Value newValue) {
+    user.replaceDebugValue(this, newValue);
     // If user is a DebugLocalRead and now has no debug values, we would like to remove it.
     // However, replaceUserInDebugData() is called in contexts where the instruction list is being
     // iterated, so we cannot remove user from the instruction list at this point.
-    if (newValue.hasLocalInfo()) {
-      DebugUse existing = newValue.debugData.users.get(instruction);
-      assert existing != null;
-      newValue.debugData.users.put(instruction, DebugUse.join(debugUse, existing));
-    }
   }
 
   public void replaceDebugUser(Instruction oldUser, Instruction newUser) {
-    DebugUse use = debugData.users.remove(oldUser);
-    if (use == DebugUse.START && newUser.outValue == this) {
-      // Register allocation requires that debug values are live at the entry to the instruction.
-      // Remove this debug use since it is starting at the instruction that defines it.
-      return;
-    }
-    if (use != null) {
-      newUser.addDebugValue(this);
-      debugData.users.put(newUser, use);
+    boolean removed = debugData.users.remove(oldUser);
+    assert removed;
+    if (removed) {
+      addDebugLocalEnd(newUser);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 0dd98e2..60fcec2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -2377,12 +2377,10 @@
     // Add a use if this instruction is overwriting a previous value of the same local.
     if (previousLocalValue != null && previousLocalValue.getLocalInfo() == ir.getLocalInfo()) {
       assert ir.outValue() != null;
-      ir.addDebugValue(previousLocalValue);
       previousLocalValue.addDebugLocalEnd(ir);
     }
     // Add reads of locals if any are pending.
     for (Value value : debugLocalEnds) {
-      ir.addDebugValue(value);
       value.addDebugLocalEnd(ir);
     }
     previousLocalValue = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 172a6b3..3181f66 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -2232,7 +2232,6 @@
             instruction.outValue().replaceUsers(inValue);
             Value overwrittenLocal = instruction.removeDebugValue(localInfo);
             if (overwrittenLocal != null) {
-              inValue.definition.addDebugValue(overwrittenLocal);
               overwrittenLocal.addDebugLocalEnd(inValue.definition);
             }
             if (prevInstruction != null &&
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 7eddfcc..7af08f9 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -347,6 +347,7 @@
       while (instructionIterator.hasNext()) {
         Instruction instruction = instructionIterator.next();
         if (!instructionIterator.hasNext()) {
+          instruction.clearDebugValues();
           break;
         }