Allow detaching used out-value from instruction

This allows using instruction.clearOutValue() to detach an out-value that may have uses such that the value can be used as the out-value of another instruction that is subsequently inserted into the IR.

Issues caught by the removed assertions are caught by the existing isConsistentSSA() checks.

Change-Id: Iff5762ec8186989dcb372be767cdc56a6c55ff16
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup.java b/src/main/java/com/android/tools/r8/ir/code/Dup.java
index 070b8e9..3bdc40c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Dup.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup.java
@@ -37,14 +37,12 @@
   }
 
   @Override
-  public void setOutValue(Value value) {
-    assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
-        value instanceof StackValues;
-    this.outValue = value;
-    this.outValue.definition = this;
-    for (StackValue val : ((StackValues)value).getStackValues()) {
-      val.definition = this;
+  public Value setOutValue(Value newOutValue) {
+    assert newOutValue instanceof StackValues;
+    for (StackValue stackValue : ((StackValues) newOutValue).getStackValues()) {
+      stackValue.definition = this;
     }
+    return super.setOutValue(newOutValue);
   }
 
   private StackValue[] getStackValues() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup2.java b/src/main/java/com/android/tools/r8/ir/code/Dup2.java
index 7053383..a01b789 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Dup2.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup2.java
@@ -51,14 +51,12 @@
   }
 
   @Override
-  public void setOutValue(Value value) {
-    assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
-        value instanceof StackValues;
-    this.outValue = value;
-    this.outValue.definition = this;
-    for (StackValue val : ((StackValues)value).getStackValues()) {
-      val.definition = this;
+  public Value setOutValue(Value newOutValue) {
+    assert newOutValue instanceof StackValues;
+    for (StackValue stackValue : ((StackValues) newOutValue).getStackValues()) {
+      stackValue.definition = this;
     }
+    return super.setOutValue(newOutValue);
   }
 
   private StackValue[] getStackValues() {
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 a1c7d45..708ffcf 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
@@ -141,12 +141,18 @@
     return outValue;
   }
 
-  public void setOutValue(Value value) {
-    assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed();
-    outValue = value;
-    if (outValue != null) {
-      outValue.definition = this;
+  public Value clearOutValue() {
+    return setOutValue(null);
+  }
+
+  // Returns the previous out-value, if any.
+  public Value setOutValue(Value newOutValue) {
+    Value previousOutValue = outValue();
+    outValue = newOutValue;
+    if (newOutValue != null) {
+      newOutValue.definition = this;
     }
+    return previousOutValue;
   }
 
   public Value swapOutValue(Value newOutValue) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Swap.java b/src/main/java/com/android/tools/r8/ir/code/Swap.java
index 5dfa623..777eec1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Swap.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Swap.java
@@ -40,14 +40,12 @@
   }
 
   @Override
-  public void setOutValue(Value value) {
-    assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
-        value instanceof StackValues;
-    this.outValue = value;
-    this.outValue.definition = this;
-    for (StackValue val : ((StackValues)value).getStackValues()) {
-      val.definition = this;
+  public Value setOutValue(Value newOutValue) {
+    assert newOutValue instanceof StackValues;
+    for (StackValue stackValue : ((StackValues) newOutValue).getStackValues()) {
+      stackValue.definition = this;
     }
+    return super.setOutValue(newOutValue);
   }
 
   private StackValue[] getStackValues() {