Remove unneeded methods on imprecise types and computeOutType from Phi.

Change-Id: I9d61e9e647611168686a01fdbd44bf794b2ee270
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 8fb77c1..ec38ea9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -32,7 +32,7 @@
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     Slot array = state.pop();
-    assert array.type.isObjectOrNull();
+    assert array.type.isObject();
     builder.addArrayLength(state.push(builder.getFactory().intType).register, array.register);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index c0b1a07..811a00c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -71,7 +71,7 @@
     Slot index = state.pop();
     Slot array = state.pop();
     Slot value;
-    assert array.type.isObjectOrNull();
+    assert array.type.isObject();
     ValueType memberType = ValueType.fromMemberType(type);
     if (array.preciseType != null) {
       value = state.push(array.preciseType.toArrayElementType(builder.getFactory()));
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 0b85683..a721955 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -35,8 +35,8 @@
   public ArrayPut(MemberType type, Value array, Value index, Value value) {
     super(null, Arrays.asList(array, index, value));
     assert type != null;
-    assert array.type.isObjectOrNull();
-    assert index.type.isSingleOrZero();
+    assert array.type.isObject();
+    assert index.type.isSingle();
     this.type = type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index f2d0974..71f1bec 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -281,7 +281,7 @@
     if (outType().isSingle() || outType().isWide()) {
       return PrimitiveTypeLatticeElement.getInstance();
     }
-    assert outType().isObjectOrNull();
+    assert outType().isObject();
     return Top.getInstance();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 8ed38ed..ededf98 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -28,8 +28,8 @@
 
   public InstancePut(MemberType type, DexField field, Value object, Value value) {
     super(type, field, null, Arrays.asList(object, value));
-    assert object().type.isObjectOrNull();
-    assert value().type.compatible(ValueType.fromDexType(field.type));
+    assert object().type.isObject();
+    assert value().type.verifyCompatible(ValueType.fromDexType(field.type));
   }
 
   public Value object() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index 70a9e11..186839b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -245,11 +245,7 @@
     }
     builder.append(" <- phi");
     StringUtils.append(builder, ListUtils.map(operands, Value::toString));
-    ValueType computed = computeOutType(null);
     builder.append(" : ").append(type);
-    if (type != computed) {
-      builder.append(" / ").append(computed);
-    }
     return builder.toString();
   }
 
@@ -312,56 +308,6 @@
     return true;
   }
 
-  private ValueType computeOutType(Set<Phi> active) {
-    // Go through non-phi operands first to determine if we have an operand that dictates the type.
-    for (Value operand : operands) {
-      // Since a constant zero can be either an integer or an Object (null) we skip them
-      // when computing types and rely on other operands to specify the actual type.
-      if (!operand.isPhi()) {
-        if (operand.outType() != ValueType.INT_OR_FLOAT_OR_NULL) {
-          return operand.outType();
-        }
-        assert operand.isZero();
-      }
-    }
-    // We did not find a non-phi operand that dictates the type. Recurse on phi arguments.
-    if (active == null) {
-      active = new HashSet<>();
-    }
-    active.add(this);
-    for (Value operand : operands) {
-      if (operand.isPhi() && !active.contains(operand.asPhi())) {
-        ValueType phiType = operand.asPhi().computeOutType(active);
-        if (phiType != ValueType.INT_OR_FLOAT_OR_NULL) {
-          return phiType;
-        }
-      }
-    }
-    // All operands were the constant zero or phis with out type INT_OR_FLOAT_OR_NULL.
-    return ValueType.INT_OR_FLOAT_OR_NULL;
-  }
-
-  private static boolean verifyUnknownOrCompatible(ValueType known, ValueType computed) {
-    assert computed == ValueType.INT_OR_FLOAT_OR_NULL || known.compatible(computed);
-    return true;
-  }
-
-  @Override
-  public ValueType outType() {
-    if (type != ValueType.INT_OR_FLOAT_OR_NULL) {
-      assert verifyUnknownOrCompatible(type, computeOutType(null));
-      return type;
-    }
-    // If the phi has unknown type (ie, INT_OR_FLOAT_OR_NULL) then it must be computed. This is
-    // because of the type confusion around null and constant zero. The null object can be used in
-    // a single context (if tests) and the single 0 can be used as null. If the instruction
-    // triggering the creation of a phi does not determine the type (eg, a move can be of int,
-    // float or zero/null) we need to compute the actual type based on the operands.
-    ValueType computedType = computeOutType(null);
-    assert computedType.isObjectOrSingle();
-    return computedType;
-  }
-
   @Override
   public boolean isConstant() {
     return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 1dc0864..6d3a85b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -54,10 +54,10 @@
       int register = builder.allocatedRegister(returnValue(), getNumber());
       switch (MoveType.fromValueType(returnType)) {
         case OBJECT:
-          assert returnValue().outType().isObjectOrNull();
+          assert returnValue().outType().isObject();
           return new ReturnObject(register);
         case SINGLE:
-          assert returnValue().outType().isSingleOrZero();
+          assert returnValue().outType().isSingle();
           return new com.android.tools.r8.code.Return(register);
         case WIDE:
           assert returnValue().outType().isWide();
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index e49cac6..c414342 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -35,14 +35,6 @@
     return !isWide();
   }
 
-  public boolean isObjectOrNull() {
-    return isObject() || this == INT_OR_FLOAT_OR_NULL;
-  }
-
-  public boolean isSingleOrZero() {
-    return isSingle() || this == INT_OR_FLOAT_OR_NULL;
-  }
-
   public boolean isPreciseType() {
     return this != ValueType.INT_OR_FLOAT
         && this != ValueType.LONG_OR_DOUBLE
@@ -107,8 +99,10 @@
     throw new CompilationError("Cannot compute meet of types: " + this + " and " + other);
   }
 
-  public boolean compatible(ValueType other) {
-    return isWide() == other.isWide();
+  public boolean verifyCompatible(ValueType other) {
+    // Computing meet will throw on incompatible types.
+    assert meet(other) != null;
+    return true;
   }
 
   public int requiredRegisters() {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfState.java b/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
index 2ac8e60..8174797 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
@@ -127,7 +127,7 @@
     for (int i = 0; i < current.stack.length; i++) {
       ValueType currentType = current.stack[i].getImprecise();
       ValueType updateType = update.stack[i].getImprecise();
-      if (!currentType.compatible(updateType)) {
+      if (currentType != updateType) {
         throw new CompilationError(
             "Incompatible types in stack position "
                 + i
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 9fb873c..5be54f5 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
@@ -1368,7 +1368,7 @@
 
   public void addReturn(ValueType type, int value) {
     ValueType returnType = ValueType.fromDexType(method.method.proto.returnType);
-    assert returnType.compatible(type);
+    assert returnType.verifyCompatible(type);
     Value in = readRegister(value, returnType);
     addReturn(new Return(in, returnType));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index b5f0a05..5c25fba 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -319,7 +319,6 @@
       }
       int localRegister = state.getLocalRegister(local.index, localType);
       ValueType existingLocalType = initializedLocals.get(localRegister);
-      assert existingLocalType == null || existingLocalType.compatible(localValueType);
       if (existingLocalType == null) {
         // For uninitialized entries write the local to ensure it exists in the local state.
         int writeRegister = state.writeLocal(local.index, localType);
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 692ac48..9cff141 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
@@ -1034,8 +1034,7 @@
                 if (argumentIndex != -1 && checkArgumentType(invoke, target.method,
                     argumentIndex)) {
                   Value argument = invoke.arguments().get(argumentIndex);
-                  assert invoke.outType().compatible(argument.outType())
-                      || (options.isGeneratingDex() && verifyCompatibleFromDex(invoke, argument));
+                  assert invoke.outType() == argument.outType();
                   invoke.outValue().replaceUsers(argument);
                   invoke.setOutValue(null);
                 }
@@ -1048,15 +1047,6 @@
     assert code.isConsistentGraph();
   }
 
-  private static boolean verifyCompatibleFromDex(Invoke invoke, Value argument) {
-    ValueType invokeType = invoke.outType();
-    ValueType argumentType = argument.outType();
-    assert argument.isZero();
-    assert (invokeType.isObject() && argumentType.isObjectOrNull())
-        || (invokeType.isSingle() && argumentType.isSingleOrZero());
-    return true;
-  }
-
   /**
    * For supporting assert javac adds the static field $assertionsDisabled to all classes which
    * have methods with assertions. This is used to support the Java VM -ea flag.