Replace MoveType by ValueType in IR.

The additional type information is needed to support the Java bytecode backend.

Change-Id: I5bf19ad3dd53b85a5673d94df59182d9862196d0
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index 5613421..1d51bab 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -4,15 +4,15 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.code.ConstType;
+import com.android.tools.r8.ir.code.ValueType;
 import org.objectweb.asm.MethodVisitor;
 
 public class CfConstNumber extends CfInstruction {
 
   private final long value;
-  private final ConstType type;
+  private final ValueType type;
 
-  public CfConstNumber(long value, ConstType type) {
+  public CfConstNumber(long value, ValueType type) {
     this.value = value;
     this.type = type;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 0d63eaf..af053a8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -4,25 +4,25 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
+import com.android.tools.r8.ir.code.ValueType;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
 public class CfLoad extends CfInstruction {
 
   private final int var;
-  private final LocalType type;
+  private final ValueType type;
 
-  public CfLoad(LocalType type, int var) {
+  public CfLoad(ValueType type, int var) {
     this.var = var;
     this.type = type;
   }
 
   private int getLoadType() {
     switch (type) {
-      case REFERENCE:
+      case OBJECT:
         return Opcodes.ALOAD;
-      case INTEGER:
+      case INT:
         return Opcodes.ILOAD;
       case FLOAT:
         return Opcodes.FLOAD;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index c18ae55..0074abc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -4,25 +4,25 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
+import com.android.tools.r8.ir.code.ValueType;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
 public class CfStore extends CfInstruction {
 
   private final int var;
-  private final LocalType type;
+  private final ValueType type;
 
-  public CfStore(LocalType type, int var) {
+  public CfStore(ValueType type, int var) {
     this.var = var;
     this.type = type;
   }
 
   private int getStoreType() {
     switch (type) {
-      case REFERENCE:
+      case OBJECT:
         return Opcodes.ASTORE;
-      case INTEGER:
+      case INT:
         return Opcodes.ISTORE;
       case FLOAT:
         return Opcodes.FSTORE;
diff --git a/src/main/java/com/android/tools/r8/code/Const.java b/src/main/java/com/android/tools/r8/code/Const.java
index 4976dc2..7f9d8b8 100644
--- a/src/main/java/com/android/tools/r8/code/Const.java
+++ b/src/main/java/com/android/tools/r8/code/Const.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.SingleConstant;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.SINGLE, AA, decodedValue());
+    builder.addConst(ValueType.INT_OR_FLOAT, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Const16.java b/src/main/java/com/android/tools/r8/code/Const16.java
index b63844c..baa51ea 100644
--- a/src/main/java/com/android/tools/r8/code/Const16.java
+++ b/src/main/java/com/android/tools/r8/code/Const16.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.SingleConstant;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
@@ -51,6 +51,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.SINGLE, AA, decodedValue());
+    builder.addConst(ValueType.INT_OR_FLOAT, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Const4.java b/src/main/java/com/android/tools/r8/code/Const4.java
index f1c80a8..31364ea 100644
--- a/src/main/java/com/android/tools/r8/code/Const4.java
+++ b/src/main/java/com/android/tools/r8/code/Const4.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.SingleConstant;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.SINGLE, A, decodedValue());
+    builder.addConst(ValueType.INT_OR_FLOAT, A, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstHigh16.java b/src/main/java/com/android/tools/r8/code/ConstHigh16.java
index a28bfbc..6cf0851 100644
--- a/src/main/java/com/android/tools/r8/code/ConstHigh16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstHigh16.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.SingleConstant;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.SINGLE, AA, decodedValue());
+    builder.addConst(ValueType.INT_OR_FLOAT, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide.java b/src/main/java/com/android/tools/r8/code/ConstWide.java
index bf26761..509b00b 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.WideConstant;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.WIDE, AA, decodedValue());
+    builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide16.java b/src/main/java/com/android/tools/r8/code/ConstWide16.java
index d416c43..4b74eb4 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.WideConstant;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.WIDE, AA, decodedValue());
+    builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide32.java b/src/main/java/com/android/tools/r8/code/ConstWide32.java
index bc564dd..f09fd14 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide32.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide32.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.WideConstant;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.WIDE, AA, decodedValue());
+    builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java b/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
index ceb154b..762e2ee 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.WideConstant;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addConst(MoveType.WIDE, AA, decodedValue());
+    builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Move.java b/src/main/java/com/android/tools/r8/code/Move.java
index 2efffb7..0dc06f9 100644
--- a/src/main/java/com/android/tools/r8/code/Move.java
+++ b/src/main/java/com/android/tools/r8/code/Move.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class Move extends Format12x {
@@ -37,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.SINGLE, A, B);
+    builder.addMove(ValueType.INT_OR_FLOAT, A, B);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Move16.java b/src/main/java/com/android/tools/r8/code/Move16.java
index b061674..aae6740 100644
--- a/src/main/java/com/android/tools/r8/code/Move16.java
+++ b/src/main/java/com/android/tools/r8/code/Move16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class Move16 extends Format32x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.SINGLE, AAAA, BBBB);
+    builder.addMove(ValueType.INT_OR_FLOAT, AAAA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveFrom16.java b/src/main/java/com/android/tools/r8/code/MoveFrom16.java
index 28d5463..7d33a0b 100644
--- a/src/main/java/com/android/tools/r8/code/MoveFrom16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveFrom16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class MoveFrom16 extends Format22x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.SINGLE, AA, BBBB);
+    builder.addMove(ValueType.INT_OR_FLOAT, AA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveObject.java b/src/main/java/com/android/tools/r8/code/MoveObject.java
index fde4992..a308ab1 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObject.java
+++ b/src/main/java/com/android/tools/r8/code/MoveObject.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class MoveObject extends Format12x {
@@ -37,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.OBJECT, A, B);
+    builder.addMove(ValueType.OBJECT, A, B);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveObject16.java b/src/main/java/com/android/tools/r8/code/MoveObject16.java
index 481bdfc..a7eb12c 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObject16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveObject16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class MoveObject16 extends Format32x {
@@ -37,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.OBJECT, AAAA, BBBB);
+    builder.addMove(ValueType.OBJECT, AAAA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java b/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java
index 71d4ca8..8b32125 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class MoveObjectFrom16 extends Format22x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.OBJECT, AA, BBBB);
+    builder.addMove(ValueType.OBJECT, AA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveResult.java b/src/main/java/com/android/tools/r8/code/MoveResult.java
index 5d8ce33..6b75941 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResult.java
+++ b/src/main/java/com/android/tools/r8/code/MoveResult.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class MoveResult extends Format11x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMoveResult(MoveType.SINGLE, AA);
+    builder.addMoveResult(ValueType.INT_OR_FLOAT, AA);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveResultObject.java b/src/main/java/com/android/tools/r8/code/MoveResultObject.java
index 1c01c99..a3334b8 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResultObject.java
+++ b/src/main/java/com/android/tools/r8/code/MoveResultObject.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class MoveResultObject extends Format11x {
@@ -37,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMoveResult(MoveType.OBJECT, AA);
+    builder.addMoveResult(ValueType.OBJECT, AA);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveResultWide.java b/src/main/java/com/android/tools/r8/code/MoveResultWide.java
index 143a256..92dde3e 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResultWide.java
+++ b/src/main/java/com/android/tools/r8/code/MoveResultWide.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class MoveResultWide extends Format11x {
@@ -37,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMoveResult(MoveType.WIDE, AA);
+    builder.addMoveResult(ValueType.LONG_OR_DOUBLE, AA);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveType.java b/src/main/java/com/android/tools/r8/code/MoveType.java
new file mode 100644
index 0000000..6ade361
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/code/MoveType.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.code;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.code.ValueType;
+
+public enum  MoveType {
+  SINGLE,
+  WIDE,
+  OBJECT;
+
+  public static MoveType fromValueType(ValueType type) {
+    switch (type) {
+      case OBJECT:
+        return OBJECT;
+      case INT:
+      case FLOAT:
+      case INT_OR_FLOAT:
+        return SINGLE;
+      case LONG:
+      case DOUBLE:
+      case LONG_OR_DOUBLE:
+        return WIDE;
+      default:
+        throw new Unreachable("Unexpected value type: " + type);
+    }
+  }
+
+  public ValueType toValueType() {
+    switch (this) {
+      case SINGLE:
+        return ValueType.INT_OR_FLOAT;
+      case WIDE:
+        return ValueType.LONG_OR_DOUBLE;
+      case OBJECT:
+        return ValueType.OBJECT;
+      default:
+        throw new Unreachable("Unexpected move type: " + this);
+    }
+  }
+
+  public int requiredRegisters() {
+    return this == WIDE ? 2 : 1;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/code/MoveWide.java b/src/main/java/com/android/tools/r8/code/MoveWide.java
index 2907fda..d6d1cb2 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWide.java
+++ b/src/main/java/com/android/tools/r8/code/MoveWide.java
@@ -3,8 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
+
 public class MoveWide extends Format12x {
 
   public static final int OPCODE = 0x4;
@@ -36,6 +37,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.WIDE, A, B);
+    builder.addMove(ValueType.LONG_OR_DOUBLE, A, B);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveWide16.java b/src/main/java/com/android/tools/r8/code/MoveWide16.java
index 9cb519f..d128b8e 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWide16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveWide16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class MoveWide16 extends Format32x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.WIDE, AAAA, BBBB);
+    builder.addMove(ValueType.LONG_OR_DOUBLE, AAAA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java b/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java
index 0688a7f..bb248d0 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 public class MoveWideFrom16 extends Format22x {
 
@@ -36,6 +36,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addMove(MoveType.WIDE, AA, BBBB);
+    builder.addMove(ValueType.LONG_OR_DOUBLE, AA, BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Return.java b/src/main/java/com/android/tools/r8/code/Return.java
index 7215eff..8efab4d 100644
--- a/src/main/java/com/android/tools/r8/code/Return.java
+++ b/src/main/java/com/android/tools/r8/code/Return.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class Return extends Format11x {
@@ -42,6 +42,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addReturn(MoveType.SINGLE, AA);
+    builder.addReturn(ValueType.INT_OR_FLOAT, AA);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ReturnObject.java b/src/main/java/com/android/tools/r8/code/ReturnObject.java
index 3d752c0..c5726df 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnObject.java
+++ b/src/main/java/com/android/tools/r8/code/ReturnObject.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class ReturnObject extends Format11x {
@@ -42,6 +42,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addReturn(MoveType.OBJECT, AA);
+    builder.addReturn(ValueType.OBJECT, AA);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ReturnWide.java b/src/main/java/com/android/tools/r8/code/ReturnWide.java
index b8237fb..f204e16 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnWide.java
+++ b/src/main/java/com/android/tools/r8/code/ReturnWide.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.code;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 public class ReturnWide extends Format11x {
@@ -42,6 +42,6 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addReturn(MoveType.WIDE, AA);
+    builder.addReturn(ValueType.LONG_OR_DOUBLE, AA);
   }
 }
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
index 7bfa534..c51e6e3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.google.common.collect.ImmutableMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -69,7 +69,7 @@
       DexString name = factory.thisName;
       DexType type = method.method.getHolder();
       startArgument(argumentRegister, name, type);
-      argumentRegister += MoveType.fromDexType(type).requiredRegisters();
+      argumentRegister += ValueType.fromDexType(type).requiredRegisters();
     }
     DexType[] types = method.method.proto.parameters.values;
     DexString[] names = info.parameters;
@@ -78,7 +78,7 @@
       if (names[i] != null) {
         startArgument(argumentRegister, names[i], types[i]);
       }
-      argumentRegister += MoveType.fromDexType(types[i]).requiredRegisters();
+      argumentRegister += ValueType.fromDexType(types[i]).requiredRegisters();
     }
     currentLine = info.startLine;
     for (DexDebugEvent event : info.events) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 8b5b0a6..c8932be 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -24,8 +24,8 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -391,7 +391,7 @@
     }
     int requiredArgRegisters = accessFlags.isStatic() ? 0 : 1;
     for (DexType type : method.proto.parameters.values) {
-      requiredArgRegisters += MoveType.fromDexType(type).requiredRegisters();
+      requiredArgRegisters += ValueType.fromDexType(type).requiredRegisters();
     }
     // Passing null as highestSortingString is save, as ConstString instructions are not allowed.
     return new DexCode(Math.max(numberOfRegisters, requiredArgRegisters), requiredArgRegisters,
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 415775d..48dc873 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.ConstType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.utils.EncodedValueUtils;
@@ -234,7 +234,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.INT, dest, value);
+          : new ConstNumber(ValueType.INT, dest, value);
     }
   }
 
@@ -282,7 +282,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.INT, dest, value);
+          : new ConstNumber(ValueType.INT, dest, value);
     }
   }
 
@@ -334,7 +334,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.INT, dest, value);
+          : new ConstNumber(ValueType.INT, dest, value);
     }
   }
 
@@ -382,7 +382,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.INT, dest, value);
+          : new ConstNumber(ValueType.INT, dest, value);
     }
   }
 
@@ -430,7 +430,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.LONG, dest, value);
+          : new ConstNumber(ValueType.LONG, dest, value);
     }
   }
 
@@ -869,7 +869,7 @@
     public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
       return (this == DEFAULT && hasClassInitializer)
           ? null
-          : new ConstNumber(ConstType.INT, dest, value ? 1 : 0);
+          : new ConstNumber(ValueType.INT, dest, value ? 1 : 0);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
index 20a7580..957c092 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
@@ -60,27 +60,27 @@
       int left = leftValue().getConstInstruction().asConstNumber().getIntValue();
       int right = rightValue().getConstInstruction().asConstNumber().getIntValue();
       int result = foldIntegers(left, right);
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.INT, value, result);
+      Value value = code.createValue(ValueType.INT, getLocalInfo());
+      return new ConstNumber(ValueType.INT, value, result);
     } else if (type == NumericType.LONG) {
       long left = leftValue().getConstInstruction().asConstNumber().getLongValue();
       long right = rightValue().getConstInstruction().asConstNumber().getLongValue();
       long result = foldLongs(left, right);
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.LONG, value, result);
+      Value value = code.createValue(ValueType.LONG, getLocalInfo());
+      return new ConstNumber(ValueType.LONG, value, result);
     } else if (type == NumericType.FLOAT) {
       float left = leftValue().getConstInstruction().asConstNumber().getFloatValue();
       float right = rightValue().getConstInstruction().asConstNumber().getFloatValue();
       float result = foldFloat(left, right);
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.FLOAT, value, Float.floatToIntBits(result));
+      Value value = code.createValue(ValueType.FLOAT, getLocalInfo());
+      return new ConstNumber(ValueType.FLOAT, value, Float.floatToIntBits(result));
     } else {
       assert type == NumericType.DOUBLE;
       double left = leftValue().getConstInstruction().asConstNumber().getDoubleValue();
       double right = rightValue().getConstInstruction().asConstNumber().getDoubleValue();
       double result = foldDouble(left, right);
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.DOUBLE, value, Double.doubleToLongBits(result));
+      Value value = code.createValue(ValueType.DOUBLE, getLocalInfo());
+      return new ConstNumber(ValueType.DOUBLE, value, Double.doubleToLongBits(result));
     }
   }
 
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 37b3119..974f425 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
@@ -1257,7 +1257,7 @@
       newBlock.setNumber(nextBlockNumber++);
       newPredecessors.add(newBlock);
       if (hasMoveException) {
-        Value value = new Value(valueNumberGenerator.next(), MoveType.OBJECT, move.getLocalInfo());
+        Value value = new Value(valueNumberGenerator.next(), ValueType.OBJECT, move.getLocalInfo());
         values.add(value);
         MoveException newMove = new MoveException(value);
         newBlock.add(newMove);
@@ -1277,7 +1277,7 @@
     // Insert a phi for the move-exception value.
     if (hasMoveException) {
       Phi phi = new Phi(valueNumberGenerator.next(),
-          this, MoveType.OBJECT, move.getLocalInfo());
+          this, ValueType.OBJECT, move.getLocalInfo());
       phi.addOperands(values);
       move.outValue().replaceUsers(phi);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index 7bf8ec1..b089e46 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -365,7 +365,7 @@
       if ((i == 0) && (downcast != null)) {
         Value invokeValue = invoke.inValues().get(0);
         Value receiverValue = arguments.get(0);
-        Value value = code.createValue(MoveType.OBJECT);
+        Value value = code.createValue(ValueType.OBJECT);
         castInstruction = new CheckCast(value, invokeValue, downcast);
         castInstruction.setPosition(invoke.getPosition());
         receiverValue.replaceUsers(value);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index 09c1dd6..a39e268 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -180,8 +180,8 @@
       }
     }
     assert result == -1 || result == 0 || result == 1;
-    Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-    return new ConstNumber(ConstType.INT, value, result);
+    Value value = code.createValue(ValueType.INT, getLocalInfo());
+    return new ConstNumber(ValueType.INT, value, result);
   }
 
   @Override
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 22374a5..fa49996 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
@@ -14,17 +14,16 @@
 import com.android.tools.r8.code.ConstWideHigh16;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.conversion.CfBuilder.StackHelper;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.utils.NumberUtils;
 
 public class ConstNumber extends ConstInstruction {
 
-  public final ConstType type;
+  public final ValueType type;
   private final long value;
 
-  public ConstNumber(ConstType type, Value dest, long value) {
+  public ConstNumber(ValueType type, Value dest, long value) {
     super(dest);
     // We create const numbers after register allocation for rematerialization of values. Those
     // are all for fixed register values. All other values that are used as the destination for
@@ -41,7 +40,7 @@
   }
 
   private boolean preciseTypeUnknown() {
-    return type == ConstType.INT_OR_FLOAT || type == ConstType.LONG_OR_DOUBLE;
+    return type == ValueType.INT_OR_FLOAT || type == ValueType.LONG_OR_DOUBLE;
   }
 
   public Value dest() {
@@ -53,22 +52,22 @@
   }
 
   public int getIntValue() {
-    assert type == ConstType.INT || type == ConstType.INT_OR_FLOAT || type == ConstType.OBJECT;
+    assert type == ValueType.INT || type == ValueType.INT_OR_FLOAT || type == ValueType.OBJECT;
     return (int) value;
   }
 
   public long getLongValue() {
-    assert type == ConstType.LONG || type == ConstType.LONG_OR_DOUBLE;
+    assert type == ValueType.LONG || type == ValueType.LONG_OR_DOUBLE;
     return value;
   }
 
   public float getFloatValue() {
-    assert type == ConstType.FLOAT || type == ConstType.INT_OR_FLOAT;
+    assert type == ValueType.FLOAT || type == ValueType.INT_OR_FLOAT;
     return Float.intBitsToFloat((int) value);
   }
 
   public double getDoubleValue() {
-    assert type == ConstType.DOUBLE || type == ConstType.LONG_OR_DOUBLE;
+    assert type == ValueType.DOUBLE || type == ValueType.LONG_OR_DOUBLE;
     return Double.longBitsToDouble(value);
   }
 
@@ -81,11 +80,11 @@
   }
 
   public boolean isIntegerZero() {
-    return type == ConstType.INT && getIntValue() == 0;
+    return type == ValueType.INT && getIntValue() == 0;
   }
 
   public boolean isIntegerOne() {
-    return type == ConstType.INT && getIntValue() == 1;
+    return type == ValueType.INT && getIntValue() == 1;
   }
 
   public boolean isIntegerNegativeOne(NumericType type) {
@@ -105,7 +104,7 @@
     }
 
     int register = builder.allocatedRegister(dest(), getNumber());
-    if (MoveType.fromConstType(type) == MoveType.SINGLE || type == ConstType.OBJECT) {
+    if (type.isSingle() || type.isObject()) {
       assert NumberUtils.is32Bit(value);
       if ((register & 0xf) == register && NumberUtils.is4Bit(value)) {
         builder.add(this, new Const4(register, (int) value));
@@ -117,7 +116,7 @@
         builder.add(this, new Const(register, (int) value));
       }
     } else {
-      assert MoveType.fromConstType(type) == MoveType.WIDE;
+      assert type.isWide();
       if (NumberUtils.is16Bit(value)) {
         builder.add(this, new ConstWide16(register, (int) value));
       } else if ((value & 0x0000ffffffffffffL) == 0) {
@@ -132,17 +131,17 @@
 
   @Override
   public void insertLoadAndStores(InstructionListIterator it, StackHelper stack) {
-    stack.storeOutValue(this, LocalType.fromConstType(type), it);
+    stack.storeOutValue(this, it);
   }
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfConstNumber(value, type));
+    builder.add(new CfConstNumber(value, outType()));
   }
 
   // Estimated size of the resulting dex instruction in code units.
-  public static int estimatedDexSize(ConstType type, long value) {
-    if (MoveType.fromConstType(type) == MoveType.SINGLE) {
+  public static int estimatedDexSize(ValueType type, long value) {
+    if (type.isSingle()) {
       assert NumberUtils.is32Bit(value);
       if (NumberUtils.is4Bit(value)) {
         return Const4.SIZE;
@@ -154,7 +153,7 @@
         return Const.SIZE;
       }
     } else {
-      assert MoveType.fromConstType(type) == MoveType.WIDE;
+      assert type.isWide();
       if (NumberUtils.is16Bit(value)) {
         return ConstWide16.SIZE;
       } else if ((value & 0x0000ffffffffffffL) == 0) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index fe90f84..5ddca3f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.conversion.CfBuilder.StackHelper;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
@@ -84,7 +83,7 @@
 
   @Override
   public void insertLoadAndStores(InstructionListIterator it, StackHelper stack) {
-    stack.storeOutValue(this, LocalType.REFERENCE, it);
+    stack.storeOutValue(this, it);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstType.java b/src/main/java/com/android/tools/r8/ir/code/ConstType.java
deleted file mode 100644
index c6f9d73..0000000
--- a/src/main/java/com/android/tools/r8/ir/code/ConstType.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.code;
-
-import com.android.tools.r8.errors.Unreachable;
-
-public enum ConstType {
-  INT,
-  LONG,
-  FLOAT,
-  DOUBLE,
-  OBJECT,
-  INT_OR_FLOAT,
-  LONG_OR_DOUBLE;
-
-  public static ConstType fromNumericType(NumericType type) {
-    switch (type) {
-      case BYTE:
-      case CHAR:
-      case SHORT:
-      case INT:
-        return INT;
-      case LONG:
-        return LONG;
-      case FLOAT:
-        return FLOAT;
-      case DOUBLE:
-        return DOUBLE;
-      default:
-        throw new Unreachable("Invalid numeric type '" + type + "'");
-    }
-  }
-
-  public static ConstType fromMoveType(MoveType moveType) {
-    switch (moveType) {
-      case SINGLE:
-        return INT_OR_FLOAT;
-      case WIDE:
-        return LONG_OR_DOUBLE;
-      case OBJECT:
-        // Currently constants never have type OBJECT even when it is the null object.
-        return INT;
-      default:
-        throw new Unreachable("Invalid move type '" + moveType + "'");
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalUninitialized.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalUninitialized.java
index beaf508..fb86708 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalUninitialized.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalUninitialized.java
@@ -17,8 +17,8 @@
  */
 public class DebugLocalUninitialized extends ConstNumber {
 
-  public DebugLocalUninitialized(ConstType type, Value value) {
-    super(type == ConstType.OBJECT ? ConstType.INT : type, value, 0);
+  public DebugLocalUninitialized(ValueType type, Value value) {
+    super(type == ValueType.OBJECT ? ValueType.INT : type, value, 0);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java b/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
index c5a7bbb..c0e156c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import com.android.tools.r8.code.MoveType;
+
 // Value that has a fixed register allocated. These are used for inserting spill, restore, and phi
 // moves in the spilling register allocator.
 public class FixedRegisterValue extends Value {
@@ -10,7 +12,7 @@
 
   public FixedRegisterValue(MoveType type, int register) {
     // Set local info to null since these values are never representatives of live-ranges.
-    super(-1, type, null);
+    super(-1, type.toValueType(), null);
     setNeedsRegister(true);
     this.register = register;
   }
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 e5fb6ed..490370e 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
@@ -473,24 +473,24 @@
     return arguments;
   }
 
-  public Value createValue(MoveType moveType, DebugLocalInfo local) {
-    return new Value(valueNumberGenerator.next(), moveType, local);
+  public Value createValue(ValueType valueType, DebugLocalInfo local) {
+    return new Value(valueNumberGenerator.next(), valueType, local);
   }
 
-  public Value createValue(MoveType moveType) {
-    return createValue(moveType, null);
+  public Value createValue(ValueType valueType) {
+    return createValue(valueType, null);
   }
 
   public ConstNumber createIntConstant(int value) {
-    return new ConstNumber(ConstType.INT, createValue(MoveType.SINGLE), value);
+    return new ConstNumber(ValueType.INT, createValue(ValueType.INT), value);
   }
 
   public ConstNumber createTrue() {
-    return new ConstNumber(ConstType.INT, createValue(MoveType.SINGLE), 1);
+    return new ConstNumber(ValueType.INT, createValue(ValueType.INT), 1);
   }
 
   public ConstNumber createFalse() {
-    return new ConstNumber(ConstType.INT, createValue(MoveType.SINGLE), 0);
+    return new ConstNumber(ValueType.INT, createValue(ValueType.INT), 0);
   }
 
   public final int getHighestBlockNumber() {
@@ -499,7 +499,7 @@
 
   public Instruction createConstNull(Instruction from) {
     Value newValue = createValue(from.outType());
-    return new ConstNumber(ConstType.fromMoveType(from.outType()), newValue, 0);
+    return new ConstNumber(from.outType(), newValue, 0);
   }
 
   public boolean doAllThrowingInstructionsHavePositions() {
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 6e5a893..e7b82d6 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
@@ -127,7 +127,7 @@
     }
   }
 
-  public final MoveType outType() {
+  public final ValueType outType() {
     return outValue.outType();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 14104d7..bdbcc5a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.code.MoveResult;
 import com.android.tools.r8.code.MoveResultObject;
 import com.android.tools.r8.code.MoveResultWide;
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -137,9 +138,10 @@
 
   protected void addInvokeAndMoveResult(com.android.tools.r8.code.Instruction instruction, DexBuilder builder) {
     if (outValue != null && outValue.needsRegister()) {
+      MoveType moveType = MoveType.fromValueType(outType());
       int register = builder.allocatedRegister(outValue, getNumber());
       com.android.tools.r8.code.Instruction moveResult;
-      switch (outType()) {
+      switch (moveType) {
         case SINGLE:
           moveResult = new MoveResult(register);
           break;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 75a449b..ff4d876 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -9,12 +9,10 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.conversion.CfBuilder.StackHelper;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
 import com.android.tools.r8.ir.optimize.InliningOracle;
-import java.util.ArrayList;
 import java.util.List;
 
 public abstract class InvokeMethod extends Invoke {
@@ -82,25 +80,14 @@
 
   @Override
   public void insertLoadAndStores(InstructionListIterator it, StackHelper stack) {
-    List<LocalType> types;
-    if (isInvokeMethodWithReceiver()) {
-      types = new ArrayList<>(method.getArity() + 1);
-      types.add(LocalType.REFERENCE);
-    } else {
-      types = new ArrayList<>(method.getArity());
-    }
-    for (DexType type : method.proto.parameters.values) {
-      types.add(LocalType.fromDexType(type));
-    }
-    stack.loadInValues(this, inValues, types, it);
+    stack.loadInValues(this, it);
     if (method.proto.returnType.isVoidType()) {
       return;
     }
     if (outValue == null) {
-      stack.popOutValue(this, MoveType.fromDexType(method.proto.returnType), it);
+      stack.popOutValue(this, it);
     } else {
-      LocalType returnType = LocalType.fromDexType(getInvokedMethod().proto.returnType);
-      stack.storeOutValue(this, returnType, it);
+      stack.storeOutValue(this, it);
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Load.java b/src/main/java/com/android/tools/r8/ir/code/Load.java
index e82149a..a8bb95c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Load.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Load.java
@@ -8,16 +8,12 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class Load extends Instruction {
 
-  private final LocalType type;
-
-  public Load(LocalType type, StackValue dest, Value src) {
+  public Load(StackValue dest, Value src) {
     super(dest, src);
-    this.type = type;
   }
 
   @Override
@@ -48,6 +44,6 @@
   @Override
   public void buildCf(CfBuilder builder) {
     Value value = inValues.get(0);
-    builder.add(new CfLoad(type, value.getNumber()));
+    builder.add(new CfLoad(value.outType(), value.getNumber()));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
index 3d6a3a0..2481025 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
@@ -37,8 +37,8 @@
       int left = leftValue().getConstInstruction().asConstNumber().getIntValue();
       int right = rightValue().getConstInstruction().asConstNumber().getIntValue();
       int result = foldIntegers(left, right);
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.INT, value, result);
+      Value value = code.createValue(ValueType.INT, getLocalInfo());
+      return new ConstNumber(ValueType.INT, value, result);
     } else {
       assert type == NumericType.LONG;
       long left = leftValue().getConstInstruction().asConstNumber().getLongValue();
@@ -50,8 +50,8 @@
         right = rightValue().getConstInstruction().asConstNumber().getLongValue();
       }
       long result = foldLongs(left, right);
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.LONG, value, result);
+      Value value = code.createValue(ValueType.LONG, getLocalInfo());
+      return new ConstNumber(ValueType.LONG, value, result);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/MemberType.java b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
index 5a992ab..28ae7ac 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MemberType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
@@ -17,18 +17,19 @@
   CHAR,
   SHORT;
 
-  public static MoveType moveTypeFor(MemberType type) {
+  public static ValueType moveTypeFor(MemberType type) {
     switch (type) {
       case BOOLEAN:
       case BYTE:
       case CHAR:
       case SHORT:
+        return ValueType.INT;
       case SINGLE:
-        return MoveType.SINGLE;
+        return ValueType.INT_OR_FLOAT;
       case WIDE:
-        return MoveType.WIDE;
+        return ValueType.LONG_OR_DOUBLE;
       case OBJECT:
-        return MoveType.OBJECT;
+        return ValueType.OBJECT;
     }
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveType.java b/src/main/java/com/android/tools/r8/ir/code/MoveType.java
deleted file mode 100644
index 18f5632..0000000
--- a/src/main/java/com/android/tools/r8/ir/code/MoveType.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.code;
-
-import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.DexType;
-
-public enum MoveType {
-  SINGLE,
-  WIDE,
-  OBJECT;
-
-  public int requiredRegisters() {
-    return this == MoveType.WIDE ? 2 : 1;
-  }
-
-  public static MoveType fromMemberType(MemberType type) {
-    switch (type) {
-      case BOOLEAN:
-      case BYTE:
-      case CHAR:
-      case SHORT:
-      case SINGLE:
-        return MoveType.SINGLE;
-      case WIDE:
-        return MoveType.WIDE;
-      case OBJECT:
-        return MoveType.OBJECT;
-    }
-    assert false;
-    return null;
-  }
-
-  public static MoveType fromTypeDescriptorChar(char descriptor) {
-    switch (descriptor) {
-      case 'L':  // object
-      case '[':  // array
-        return MoveType.OBJECT;
-      case 'Z':  // boolean
-      case 'B':  // byte
-      case 'S':  // short
-      case 'C':  // char
-      case 'I':  // int
-      case 'F':  // float
-        return MoveType.SINGLE;
-      case 'J':  // long
-      case 'D':  // double
-        return MoveType.WIDE;
-      case 'V':
-        throw new InternalCompilerError("No move type for void type.");
-      default:
-        throw new Unreachable("Invalid descriptor char '" + descriptor + "'");
-    }
-  }
-
-  public static MoveType fromDexType(DexType type) {
-    return fromTypeDescriptorChar((char) type.descriptor.content[0]);
-  }
-
-  public static MoveType fromConstType(ConstType type) {
-    switch (type) {
-      case INT:
-      case FLOAT:
-      case INT_OR_FLOAT:
-        return MoveType.SINGLE;
-      case OBJECT:
-        return MoveType.OBJECT;
-      case LONG:
-      case DOUBLE:
-      case LONG_OR_DOUBLE:
-        return MoveType.WIDE;
-      default:
-        throw new Unreachable("Invalid const type '" + type + "'");
-    }
-  }
-
-  public static MoveType fromNumericType(NumericType type) {
-    switch (type) {
-      case BYTE:
-      case CHAR:
-      case SHORT:
-      case INT:
-      case FLOAT:
-        return MoveType.SINGLE;
-      case LONG:
-      case DOUBLE:
-        return MoveType.WIDE;
-      default:
-        throw new Unreachable("Invalid numeric type '" + type + "'");
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Neg.java b/src/main/java/com/android/tools/r8/ir/code/Neg.java
index dc0be38..9fb215f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Neg.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Neg.java
@@ -29,23 +29,24 @@
   @Override
   public ConstInstruction fold(IRCode code) {
     assert canBeFolded();
+    ValueType valueType = ValueType.fromNumericType(type);
     if (type == NumericType.INT) {
       int result = -source().getConstInstruction().asConstNumber().getIntValue();
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.INT, value, result);
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, result);
     } else if (type == NumericType.LONG) {
       long result = -source().getConstInstruction().asConstNumber().getLongValue();
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.LONG, value, result);
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, result);
     } else if (type == NumericType.FLOAT) {
       float result = -source().getConstInstruction().asConstNumber().getFloatValue();
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.FLOAT, value, Float.floatToIntBits(result));
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, Float.floatToIntBits(result));
     } else {
       assert type == NumericType.DOUBLE;
       double result = -source().getConstInstruction().asConstNumber().getDoubleValue();
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.DOUBLE, value, Double.doubleToLongBits(result));
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, Double.doubleToLongBits(result));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Not.java b/src/main/java/com/android/tools/r8/ir/code/Not.java
index 98e2207..ec941c0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Not.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Not.java
@@ -25,15 +25,16 @@
   @Override
   public ConstInstruction fold(IRCode code) {
     assert canBeFolded();
+    ValueType valueType = ValueType.fromNumericType(type);
     if (type == NumericType.INT) {
       int result = ~(source().getConstInstruction().asConstNumber().getIntValue());
-      Value value = code.createValue(MoveType.SINGLE, getLocalInfo());
-      return new ConstNumber(ConstType.INT, value, result);
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, result);
     } else {
       assert type == NumericType.LONG;
       long result = ~source().getConstInstruction().asConstNumber().getLongValue();
-      Value value = code.createValue(MoveType.WIDE, getLocalInfo());
-      return new ConstNumber(ConstType.LONG, value, result);
+      Value value = code.createValue(valueType, getLocalInfo());
+      return new ConstNumber(valueType, value, result);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/NumericType.java b/src/main/java/com/android/tools/r8/ir/code/NumericType.java
index 765bfe1..a8cdf50 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NumericType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NumericType.java
@@ -16,13 +16,6 @@
   FLOAT,
   DOUBLE;
 
-  public MoveType moveTypeFor() {
-    if (this == NumericType.DOUBLE || this == NumericType.LONG) {
-      return MoveType.WIDE;
-    }
-    return MoveType.SINGLE;
-  }
-
   public DexType dexTypeFor(DexItemFactory factory) {
     switch (this) {
       case BYTE:
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 dc6d500..5a9673f 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
@@ -36,9 +36,9 @@
   // have either of the creation types 'single' and 'object' depending on the use that
   // triggered the creation of the phi. We therefore have to delay the output type
   // computation of the phi until all operands are known.
-  private MoveType outType = null;
+  private ValueType outType = null;
 
-  public Phi(int number, BasicBlock block, MoveType type, DebugLocalInfo local) {
+  public Phi(int number, BasicBlock block, ValueType type, DebugLocalInfo local) {
     super(number, type, local);
     this.block = block;
     block.addPhi(this);
@@ -274,7 +274,7 @@
 
   private boolean isSingleConstZero(Value value) {
     return value.definition != null
-        && value.outType() == MoveType.SINGLE
+        && value.outType().isSingle()
         && value.isZero();
   }
 
@@ -313,7 +313,7 @@
     return true;
   }
 
-  private MoveType computeOutType(Set<Phi> active) {
+  private ValueType computeOutType(Set<Phi> active) {
     if (outType != null) {
       return outType;
     }
@@ -329,23 +329,21 @@
     // We did not find a non-phi operand that dictates the type. Recurse on phi arguments.
     for (Value operand : operands) {
       if (operand.isPhi() && !active.contains(operand.asPhi())) {
-        MoveType phiType = operand.asPhi().computeOutType(active);
-        // TODO(zerny): If we had a CONST_ZERO type element, we could often avoid going through
-        // all phis. We would only have to recurse until we got a non CONST_ZERO out type.
-        if (phiType != MoveType.SINGLE) {
+        ValueType phiType = operand.asPhi().computeOutType(active);
+        if (phiType != ValueType.INT_OR_FLOAT) {
           return phiType;
         }
       }
     }
-    // All operands were the constant zero or phis with out type SINGLE and the out type is either
-    // object or single depending on the use. Since all inputs have out type SINGLE it is safe to
-    // return MoveType.SINGLE here.
-    assert type == MoveType.SINGLE || type == MoveType.OBJECT;
-    return MoveType.SINGLE;
+    // All operands were the constant zero or phis with out type INT_OR_FLOAT and the DEX move type
+    // is either object or single depending on the use. Since all inputs have out type INT_OF_FLOAT
+    // it is safe to return ValueType.INT_OR_FLOAT here.
+    assert type.isSingle() || type.isObject();
+    return ValueType.INT_OR_FLOAT;
   }
 
   @Override
-  public MoveType outType() {
+  public ValueType outType() {
     if (outType != null) {
       return outType;
     }
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 e16cf95..6561d27 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
@@ -4,6 +4,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.code.ReturnObject;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.code.ReturnWide;
@@ -12,7 +13,6 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.conversion.CfBuilder.StackHelper;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -20,14 +20,14 @@
 public class Return extends JumpInstruction {
 
   // Need to keep track of the original return type, as a null value will have MoveType.SINGLE.
-  final private MoveType returnType;
+  final private ValueType returnType;
 
   public Return() {
     super(null);
     returnType = null;
   }
 
-  public Return(Value value, MoveType returnType) {
+  public Return(Value value, ValueType returnType) {
     super(null, value);
     this.returnType = returnType;
   }
@@ -36,7 +36,7 @@
     return inValues.size() == 0;
   }
 
-  public MoveType getReturnType() {
+  public ValueType getReturnType() {
     return returnType;
   }
 
@@ -49,19 +49,16 @@
     if (isReturnVoid()) {
       return new ReturnVoid();
     } else {
-      switch (returnValue().type) {
+      switch (MoveType.fromValueType(returnType)) {
         case OBJECT:
-          assert returnType == MoveType.OBJECT;
+          assert returnValue().outType().isObject() || returnValue().outType().isSingle();
           return new ReturnObject(builder.allocatedRegister(returnValue(), getNumber()));
         case SINGLE:
-          if (returnType == MoveType.OBJECT) {
-            return new ReturnObject(builder.allocatedRegister(returnValue(), getNumber()));
-          } else {
-            assert returnType == MoveType.SINGLE;
-            return new com.android.tools.r8.code.Return(builder.allocatedRegister(returnValue(), getNumber()));
-          }
+          assert returnValue().outType().isSingle();
+          return new com.android.tools.r8.code.Return(
+              builder.allocatedRegister(returnValue(), getNumber()));
         case WIDE:
-          assert returnType == MoveType.WIDE;
+          assert returnValue().outType().isWide();
           return new ReturnWide(builder.allocatedRegister(returnValue(), getNumber()));
         default:
           throw new Unreachable();
@@ -120,18 +117,9 @@
 
   @Override
   public void insertLoadAndStores(InstructionListIterator it, StackHelper stack) {
-    if (isReturnVoid()) {
-      return;
+    if (!isReturnVoid()) {
+      stack.loadInValues(this, it);
     }
-    Value oldValue = returnValue();
-    StackValue stackValue = new StackValue(returnType);
-    replaceValue(oldValue, stackValue);
-    Load load =
-        new Load(LocalType.fromDexType(stack.method.proto.returnType), stackValue, oldValue);
-    load.setBlock(getBlock());
-    it.previous();
-    it.add(load);
-    it.next();
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValue.java b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
index f743e9e..f670621 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
@@ -5,7 +5,7 @@
 
 public class StackValue extends Value {
 
-  public StackValue(MoveType type) {
+  public StackValue(ValueType type) {
     super(Value.UNDEFINED_NUMBER, type, null);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 8338db5..af91d29 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.conversion.CfBuilder.StackHelper;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
@@ -119,7 +118,7 @@
 
   @Override
   public void insertLoadAndStores(InstructionListIterator it, StackHelper stack) {
-    stack.storeOutValue(this, LocalType.fromDexType(field.type), it);
+    stack.storeOutValue(this, it);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index 2124a40..e5b90a3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -8,16 +8,12 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.LocalType;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class Store extends Instruction {
 
-  private final LocalType type;
-
-  public Store(LocalType type, Value dest, StackValue src) {
+  public Store(Value dest, StackValue src) {
     super(dest, src);
-    this.type = type;
   }
 
   @Override
@@ -47,6 +43,6 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfStore(type, outValue.getNumber()));
+    builder.add(new CfStore(outType(), outValue.getNumber()));
   }
 }
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 4baf23f..b925b8b 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
@@ -70,10 +70,10 @@
 
   public static final int UNDEFINED_NUMBER = -1;
 
-  public static final Value UNDEFINED = new Value(UNDEFINED_NUMBER, MoveType.OBJECT, null);
+  public static final Value UNDEFINED = new Value(UNDEFINED_NUMBER, ValueType.OBJECT, null);
 
   protected final int number;
-  protected final MoveType type;
+  protected final ValueType type;
   public Instruction definition = null;
   private LinkedList<Instruction> users = new LinkedList<>();
   private Set<Instruction> uniqueUsers = null;
@@ -90,7 +90,7 @@
   private LongInterval valueRange;
   private DebugData debugData;
 
-  public Value(int number, MoveType type, DebugLocalInfo local) {
+  public Value(int number, ValueType type, DebugLocalInfo local) {
     this.number = number;
     this.type = type;
     this.debugData = local == null ? null : new DebugData(local);
@@ -463,7 +463,7 @@
       builder.append("(");
       if (isConstant) {
         ConstNumber constNumber = definition.asConstNumber();
-        if (constNumber.outType() == MoveType.SINGLE) {
+        if (constNumber.outType().isSingle()) {
           builder.append((int) constNumber.getRawValue());
         } else {
           builder.append(constNumber.getRawValue());
@@ -483,7 +483,7 @@
     return builder.toString();
   }
 
-  public MoveType outType() {
+  public ValueType outType() {
     return type;
   }
 
@@ -580,11 +580,11 @@
 
   public LongInterval getValueRange() {
     if (isConstNumber()) {
-      if (type == MoveType.SINGLE) {
+      if (type.isSingle()) {
         int value = getConstInstruction().asConstNumber().getIntValue();
         return new LongInterval(value, value);
       } else {
-        assert type == MoveType.WIDE;
+        assert type.isWide();
         long value = getConstInstruction().asConstNumber().getLongValue();
         return new LongInterval(value, value);
       }
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
new file mode 100644
index 0000000..231a82f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -0,0 +1,105 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexType;
+
+public enum ValueType {
+  OBJECT,
+  INT,
+  FLOAT,
+  INT_OR_FLOAT,
+  LONG,
+  DOUBLE,
+  LONG_OR_DOUBLE;
+
+  public boolean isObject() {
+    return this == OBJECT;
+  }
+
+  public boolean isSingle() {
+    return this == INT || this == FLOAT || this == INT_OR_FLOAT;
+  }
+
+  public boolean isWide() {
+    return this == LONG || this == DOUBLE || this == LONG_OR_DOUBLE;
+  }
+
+  public int requiredRegisters() {
+    return isWide() ? 2 : 1;
+  }
+
+  public boolean compatible(ValueType other) {
+    return (isObject() && other.isObject())
+        || (isSingle() && other.isSingle())
+        || (isWide() && other.isWide());
+  }
+
+  public static ValueType fromMemberType(MemberType type) {
+    switch (type) {
+      case BOOLEAN:
+      case BYTE:
+      case CHAR:
+      case SHORT:
+        return ValueType.INT;
+      case SINGLE:
+        return ValueType.INT_OR_FLOAT;
+      case WIDE:
+        return ValueType.LONG_OR_DOUBLE;
+      case OBJECT:
+        return ValueType.OBJECT;
+      default:
+        throw new Unreachable("Unexpected member type: " + type);
+    }
+  }
+
+  public static ValueType fromTypeDescriptorChar(char descriptor) {
+    switch (descriptor) {
+      case 'L':
+      case '[':
+        return ValueType.OBJECT;
+      case 'Z':
+      case 'B':
+      case 'S':
+      case 'C':
+      case 'I':
+        return ValueType.INT;
+      case 'F':
+        return ValueType.FLOAT;
+      case 'J':
+        return ValueType.LONG;
+      case 'D':
+        return ValueType.DOUBLE;
+      case 'V':
+        throw new InternalCompilerError("No value type for void type.");
+      default:
+        throw new Unreachable("Invalid descriptor char '" + descriptor + "'");
+    }
+  }
+
+  public static ValueType fromDexType(DexType type) {
+    return fromTypeDescriptorChar((char) type.descriptor.content[0]);
+  }
+
+  public static ValueType fromNumericType(NumericType type) {
+    switch (type) {
+      case BYTE:
+      case CHAR:
+      case SHORT:
+      case INT:
+        return ValueType.INT;
+      case FLOAT:
+        return ValueType.FLOAT;
+      case LONG:
+        return ValueType.LONG;
+      case DOUBLE:
+        return ValueType.DOUBLE;
+      default:
+        throw new Unreachable("Invalid numeric type '" + type + "'");
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index f50747b..15b0f69 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -5,21 +5,17 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Load;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Pop;
 import com.android.tools.r8.ir.code.StackValue;
 import com.android.tools.r8.ir.code.Store;
@@ -29,57 +25,6 @@
 
 public class CfBuilder {
 
-  public enum LocalType {
-    REFERENCE,
-    INTEGER,
-    FLOAT,
-    LONG,
-    DOUBLE;
-
-    public static LocalType fromDexType(DexType type) {
-      switch (type.toShorty()) {
-        case 'Z':
-        case 'B':
-        case 'C':
-        case 'S':
-        case 'I':
-          return INTEGER;
-        case 'F':
-          return FLOAT;
-        case 'J':
-          return LONG;
-        case 'D':
-          return DOUBLE;
-        case 'L':
-          return REFERENCE;
-        default:
-          throw new Unreachable("Unexpected type " + type);
-      }
-    }
-
-    public static LocalType fromConstType(ConstType type) {
-      switch (type) {
-        case INT:
-          return INTEGER;
-        case DOUBLE:
-          return DOUBLE;
-        case FLOAT:
-          return FLOAT;
-        case OBJECT:
-          return REFERENCE;
-        case LONG:
-          return LONG;
-        case INT_OR_FLOAT:
-        case LONG_OR_DOUBLE:
-          throw new Unreachable("Const combination types not supported in cf backend");
-        default:
-          throw new Unreachable("Unexpected type " + type);
-      }
-    }
-
-  }
-
-
   private final DexEncodedMethod method;
   private final IRCode code;
   private List<CfInstruction> instructions;
@@ -92,31 +37,25 @@
       this.method = method;
     }
 
-    public void loadInValues(
-        Instruction instruction,
-        List<Value> values,
-        List<LocalType> types,
-        InstructionListIterator it) {
-      assert values.size() == types.size();
+    public void loadInValues(Instruction instruction, InstructionListIterator it) {
       it.previous();
-      for (int i = 0; i < values.size(); i++) {
-        Value value = values.get(i);
-        LocalType type = types.get(i);
+      for (int i = 0; i < instruction.inValues().size(); i++) {
+        Value value = instruction.inValues().get(i);
         StackValue stackValue = new StackValue(value.outType());
         instruction.replaceValue(value, stackValue);
-        add(new Load(type, stackValue, value), instruction, it);
+        add(new Load(stackValue, value), instruction, it);
       }
       it.next();
     }
 
-    public void storeOutValue(Instruction instruction, LocalType type, InstructionListIterator it) {
+    public void storeOutValue(Instruction instruction, InstructionListIterator it) {
       StackValue newOutValue = new StackValue(instruction.outType());
       Value oldOutValue = instruction.swapOutValue(newOutValue);
-      add(new Store(type, oldOutValue, newOutValue), instruction, it);
+      add(new Store(oldOutValue, newOutValue), instruction, it);
     }
 
-    public void popOutValue(Instruction instruction, MoveType type, InstructionListIterator it) {
-      StackValue newOutValue = new StackValue(type);
+    public void popOutValue(Instruction instruction, InstructionListIterator it) {
+      StackValue newOutValue = new StackValue(instruction.outType());
       instruction.swapOutValue(newOutValue);
       add(new Pop(newOutValue), instruction, it);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 2335f2b..43a91f3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.code.MoveObject;
 import com.android.tools.r8.code.MoveObject16;
 import com.android.tools.r8.code.MoveObjectFrom16;
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.code.MoveWide;
 import com.android.tools.r8.code.MoveWide16;
 import com.android.tools.r8.code.MoveWideFrom16;
@@ -1168,6 +1169,7 @@
     @Override
     public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
       Move move = getMove();
+      MoveType moveType = MoveType.fromValueType(move.outType());
       int dest = builder.allocatedRegister(move.dest(), move.getNumber());
       int src = builder.allocatedRegister(move.src(), move.getNumber());
       Instruction instruction = null;
@@ -1177,7 +1179,7 @@
             instruction = new Nop();
             break;
           }
-          switch (move.outType()) {
+          switch (moveType) {
             case SINGLE:
               instruction = new com.android.tools.r8.code.Move(dest, src);
               break;
@@ -1192,7 +1194,7 @@
           }
           break;
         case 2:
-          switch (move.outType()) {
+          switch (moveType) {
             case SINGLE:
               instruction = new MoveFrom16(dest, src);
               break;
@@ -1207,7 +1209,7 @@
           }
           break;
         case 3:
-          switch (move.outType()) {
+          switch (moveType) {
             case SINGLE:
               instruction = new Move16(dest, src);
               break;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 4bafe62..e353a70 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -41,8 +41,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.ir.code.CatchHandlers;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ValueType;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -70,7 +70,7 @@
   private Position currentPosition = null;
   private Map<Position, Position> canonicalPositions = null;
 
-  private final List<MoveType> argumentTypes;
+  private final List<ValueType> argumentTypes;
 
   private List<DexDebugEntry> debugEntries = null;
 
@@ -131,7 +131,7 @@
       builder.addThisArgument(register);
       ++register;
     }
-    for (MoveType type : argumentTypes) {
+    for (ValueType type : argumentTypes) {
       builder.addNonThisArgument(register, type);
       register += type.requiredRegisters();
     }
@@ -260,12 +260,12 @@
         arrayFilledDataPayloadResolver.getData(payloadOffset));
   }
 
-  private List<MoveType> computeArgumentTypes() {
-    List<MoveType> types = new ArrayList<>(proto.parameters.size());
+  private List<ValueType> computeArgumentTypes() {
+    List<ValueType> types = new ArrayList<>(proto.parameters.size());
     String shorty = proto.shorty.toString();
     for (int i = 1; i < proto.shorty.size; i++) {
-      MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
-      types.add(moveType);
+      ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
+      types.add(valueType);
     }
     return types;
   }
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 4a96ae6..68c3f08 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
@@ -36,7 +36,6 @@
 import com.android.tools.r8.ir.code.ConstMethodType;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.DebugLocalRead;
 import com.android.tools.r8.ir.code.DebugLocalUninitialized;
 import com.android.tools.r8.ir.code.DebugLocalWrite;
@@ -56,7 +55,6 @@
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.Monitor;
 import com.android.tools.r8.ir.code.MoveException;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Mul;
 import com.android.tools.r8.ir.code.Neg;
 import com.android.tools.r8.ir.code.NewArrayEmpty;
@@ -80,6 +78,7 @@
 import com.android.tools.r8.ir.code.Ushr;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.Xor;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
@@ -529,7 +528,7 @@
     int moveExceptionDest = source.getMoveExceptionRegister();
     assert moveExceptionDest >= 0;
     int targetIndex = source.instructionIndex(moveExceptionItem.targetOffset);
-    Value out = writeRegister(moveExceptionDest, MoveType.OBJECT, ThrowingInfo.NO_THROW, null);
+    Value out = writeRegister(moveExceptionDest, ValueType.OBJECT, ThrowingInfo.NO_THROW, null);
     Position position = source.getDebugPositionAtOffset(moveExceptionItem.targetOffset);
     MoveException moveException = new MoveException(out);
     moveException.setPosition(position);
@@ -564,35 +563,34 @@
 
   public void addThisArgument(int register) {
     DebugLocalInfo local = getCurrentLocal(register);
-    Value value = writeRegister(register, MoveType.OBJECT, ThrowingInfo.NO_THROW, local);
+    Value value = writeRegister(register, ValueType.OBJECT, ThrowingInfo.NO_THROW, local);
     addInstruction(new Argument(value));
     value.markAsThis();
   }
 
-  public void addNonThisArgument(int register, MoveType moveType) {
+  public void addNonThisArgument(int register, ValueType valueType) {
     DebugLocalInfo local = getCurrentLocal(register);
-    Value value = writeRegister(register, moveType, ThrowingInfo.NO_THROW, local);
+    Value value = writeRegister(register, valueType, ThrowingInfo.NO_THROW, local);
     addInstruction(new Argument(value));
   }
 
   public void addBooleanNonThisArgument(int register) {
     DebugLocalInfo local = getCurrentLocal(register);
-    Value value = writeRegister(register, MoveType.SINGLE, ThrowingInfo.NO_THROW, local);
+    Value value = writeRegister(register, ValueType.INT, ThrowingInfo.NO_THROW, local);
     value.setKnownToBeBoolean(true);
     addInstruction(new Argument(value));
   }
 
-  public void addDebugUninitialized(int register, ConstType type) {
+  public void addDebugUninitialized(int register, ValueType type) {
     if (!options.debug) {
       return;
     }
-    Value value = writeRegister(register, MoveType.fromConstType(type), ThrowingInfo.NO_THROW,
-        null);
+    Value value = writeRegister(register, type, ThrowingInfo.NO_THROW, null);
     assert !value.hasLocalInfo();
     addInstruction(new DebugLocalUninitialized(type, value));
   }
 
-  private void addDebugLocalWrite(MoveType type, int dest, Value in) {
+  private void addDebugLocalWrite(ValueType type, int dest, Value in) {
     assert options.debug;
     Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
     DebugLocalWrite write = new DebugLocalWrite(out, in);
@@ -604,8 +602,8 @@
     assert options.debug;
     assert local != null;
     assert local == getCurrentLocal(register);
-    MoveType moveType = MoveType.fromDexType(local.type);
-    return readRegisterIgnoreLocal(register, moveType);
+    ValueType valueType = ValueType.fromDexType(local.type);
+    return readRegisterIgnoreLocal(register, valueType);
   }
 
   private static boolean isValidFor(Value value, DebugLocalInfo local) {
@@ -633,7 +631,7 @@
     // If the value is for a different local, introduce the new local. We cannot shortcut if the
     // local is defined by a phi as it could end up being trivial.
     if (value.isPhi() || value.getLocalInfo() != local) {
-      addDebugLocalWrite(MoveType.fromDexType(local.type), register, value);
+      addDebugLocalWrite(ValueType.fromDexType(local.type), register, value);
       return;
     }
 
@@ -735,9 +733,9 @@
   }
 
   public void addArrayGet(MemberType type, int dest, int array, int index) {
-    Value in1 = readRegister(array, MoveType.OBJECT);
-    Value in2 = readRegister(index, MoveType.SINGLE);
-    Value out = writeRegister(dest, MoveType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+    Value in1 = readRegister(array, ValueType.OBJECT);
+    Value in2 = readRegister(index, ValueType.INT);
+    Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
     out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
     ArrayGet instruction = new ArrayGet(type, out, in1, in2);
     assert instruction.instructionTypeCanThrow();
@@ -745,8 +743,8 @@
   }
 
   public void addArrayLength(int dest, int array) {
-    Value in = readRegister(array, MoveType.OBJECT);
-    Value out = writeRegister(dest, MoveType.SINGLE, ThrowingInfo.CAN_THROW);
+    Value in = readRegister(array, ValueType.OBJECT);
+    Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.CAN_THROW);
     ArrayLength instruction = new ArrayLength(out, in);
     assert instruction.instructionTypeCanThrow();
     add(instruction);
@@ -754,16 +752,16 @@
 
   public void addArrayPut(MemberType type, int value, int array, int index) {
     List<Value> ins = new ArrayList<>(3);
-    ins.add(readRegister(value, MoveType.fromMemberType(type)));
-    ins.add(readRegister(array, MoveType.OBJECT));
-    ins.add(readRegister(index, MoveType.SINGLE));
+    ins.add(readRegister(value, ValueType.fromMemberType(type)));
+    ins.add(readRegister(array, ValueType.OBJECT));
+    ins.add(readRegister(index, ValueType.INT));
     ArrayPut instruction = new ArrayPut(type, ins);
     add(instruction);
   }
 
   public void addCheckCast(int value, DexType type) {
-    Value in = readRegister(value, MoveType.OBJECT);
-    Value out = writeRegister(value, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value in = readRegister(value, ValueType.OBJECT);
+    Value out = writeRegister(value, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     CheckCast instruction = new CheckCast(out, in, type);
     assert instruction.instructionTypeCanThrow();
     add(instruction);
@@ -772,22 +770,15 @@
   public void addCmp(NumericType type, Bias bias, int dest, int left, int right) {
     Value in1 = readNumericRegister(left, type);
     Value in2 = readNumericRegister(right, type);
-    Value out = writeRegister(dest, MoveType.SINGLE, ThrowingInfo.NO_THROW);
+    Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.NO_THROW);
     Cmp instruction = new Cmp(type, bias, out, in1, in2);
     assert !instruction.instructionTypeCanThrow();
     add(instruction);
   }
 
-  public void addConst(MoveType type, int dest, long value) {
-    ConstNumber instruction;
-    if (type == MoveType.SINGLE) {
-      Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
-      instruction = new ConstNumber(ConstType.INT_OR_FLOAT, out, value);
-    } else {
-      assert type == MoveType.WIDE;
-      Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
-      instruction = new ConstNumber(ConstType.LONG_OR_DOUBLE, out, value);
-    }
+  public void addConst(ValueType type, int dest, long value) {
+    Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
+    ConstNumber instruction = new ConstNumber(type, out, value);
     assert !instruction.instructionTypeCanThrow();
     add(instruction);
   }
@@ -796,12 +787,12 @@
   // to disable constant canonicalization in debug builds to make sure we have separate values
   // for separate locals.
   private void canonicalizeAndAddConst(
-      ConstType type, int dest, long value, Long2ObjectMap<ConstNumber> table) {
+      ValueType type, int dest, long value, Long2ObjectMap<ConstNumber> table) {
     ConstNumber existing = table.get(value);
     if (existing != null) {
       currentBlock.writeCurrentDefinition(dest, existing.outValue(), ThrowingInfo.NO_THROW);
     } else {
-      Value out = writeRegister(dest, MoveType.fromConstType(type), ThrowingInfo.NO_THROW);
+      Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
       ConstNumber instruction = new ConstNumber(type, out, value);
       BasicBlock entryBlock = blocks.get(0);
       if (currentBlock != entryBlock) {
@@ -825,27 +816,27 @@
   }
 
   public void addLongConst(int dest, long value) {
-    canonicalizeAndAddConst(ConstType.LONG, dest, value, longConstants);
+    canonicalizeAndAddConst(ValueType.LONG, dest, value, longConstants);
   }
 
   public void addDoubleConst(int dest, long value) {
-    canonicalizeAndAddConst(ConstType.DOUBLE, dest, value, doubleConstants);
+    canonicalizeAndAddConst(ValueType.DOUBLE, dest, value, doubleConstants);
   }
 
   public void addIntConst(int dest, long value) {
-    canonicalizeAndAddConst(ConstType.INT, dest, value, intConstants);
+    canonicalizeAndAddConst(ValueType.INT, dest, value, intConstants);
   }
 
   public void addFloatConst(int dest, long value) {
-    canonicalizeAndAddConst(ConstType.FLOAT, dest, value, floatConstants);
+    canonicalizeAndAddConst(ValueType.FLOAT, dest, value, floatConstants);
   }
 
   public void addNullConst(int dest, long value) {
-    canonicalizeAndAddConst(ConstType.OBJECT, dest, value, nullConstants);
+    canonicalizeAndAddConst(ValueType.OBJECT, dest, value, nullConstants);
   }
 
   public void addConstClass(int dest, DexType type) {
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     ConstClass instruction = new ConstClass(out, type);
     assert instruction.instructionTypeCanThrow();
     add(instruction);
@@ -859,7 +850,7 @@
           "Const-method-handle",
           null /* sourceString */);
     }
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     ConstMethodHandle instruction = new ConstMethodHandle(out, methodHandle);
     add(instruction);
   }
@@ -872,13 +863,13 @@
           "Const-method-type",
           null /* sourceString */);
     }
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     ConstMethodType instruction = new ConstMethodType(out, methodType);
     add(instruction);
   }
 
   public void addConstString(int dest, DexString string) {
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     ConstString instruction = new ConstString(out, string);
     add(instruction);
   }
@@ -907,13 +898,13 @@
   }
 
   public Monitor addMonitor(Monitor.Type type, int monitor) {
-    Value in = readRegister(monitor, MoveType.OBJECT);
+    Value in = readRegister(monitor, ValueType.OBJECT);
     Monitor monitorEnter = new Monitor(type, in);
     add(monitorEnter);
     return monitorEnter;
   }
 
-  public void addMove(MoveType type, int dest, int src) {
+  public void addMove(ValueType type, int dest, int src) {
     Value in = readRegister(src, type);
     if (options.debug) {
       // If the move is writing to a different local we must construct a new value.
@@ -1013,8 +1004,8 @@
       addTrivialIf(trueTargetOffset, falseTargetOffset);
     } else {
       List<Value> values = new ArrayList<>(2);
-      values.add(readRegister(value1, MoveType.SINGLE));
-      values.add(readRegister(value2, MoveType.SINGLE));
+      values.add(readRegister(value1, ValueType.INT));
+      values.add(readRegister(value2, ValueType.INT));
       If instruction = new If(type, values);
       addNonTrivialIf(instruction, trueTargetOffset, falseTargetOffset);
     }
@@ -1024,7 +1015,7 @@
     if (trueTargetOffset == falseTargetOffset) {
       addTrivialIf(trueTargetOffset, falseTargetOffset);
     } else {
-      If instruction = new If(type, readRegister(value, MoveType.SINGLE));
+      If instruction = new If(type, readRegister(value, ValueType.INT));
       addNonTrivialIf(instruction, trueTargetOffset, falseTargetOffset);
     }
   }
@@ -1034,8 +1025,8 @@
       int dest,
       int object,
       DexField field) {
-    Value in = readRegister(object, MoveType.OBJECT);
-    Value out = writeRegister(dest, MoveType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+    Value in = readRegister(object, ValueType.OBJECT);
+    Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
     out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
     InstanceGet instruction = new InstanceGet(type, out, in, field);
     assert instruction.instructionTypeCanThrow();
@@ -1043,8 +1034,8 @@
   }
 
   public void addInstanceOf(int dest, int value, DexType type) {
-    Value in = readRegister(value, MoveType.OBJECT);
-    Value out = writeRegister(dest, MoveType.SINGLE, ThrowingInfo.CAN_THROW);
+    Value in = readRegister(value, ValueType.OBJECT);
+    Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.CAN_THROW);
     InstanceOf instruction = new InstanceOf(out, in, type);
     assert instruction.instructionTypeCanThrow();
     addInstruction(instruction);
@@ -1056,8 +1047,8 @@
       int object,
       DexField field) {
     List<Value> values = new ArrayList<>(2);
-    values.add(readRegister(value, MoveType.fromMemberType(type)));
-    values.add(readRegister(object, MoveType.OBJECT));
+    values.add(readRegister(value, ValueType.fromMemberType(type)));
+    values.add(readRegister(object, ValueType.OBJECT));
     InstancePut instruction = new InstancePut(type, values, field);
     add(instruction);
   }
@@ -1086,7 +1077,7 @@
       Invoke.Type type,
       DexItem item,
       DexProto callSiteProto,
-      List<MoveType> types,
+      List<ValueType> types,
       List<Integer> registers)
       throws ApiLevelException {
     assert types.size() == registers.size();
@@ -1104,16 +1095,16 @@
     List<Value> arguments = new ArrayList<>(argumentRegisterCount);
 
     if (!bootstrapMethod.isStaticHandle()) {
-      arguments.add(readRegister(argumentRegisters[registerIndex], MoveType.OBJECT));
-      registerIndex += MoveType.OBJECT.requiredRegisters();
+      arguments.add(readRegister(argumentRegisters[registerIndex], ValueType.OBJECT));
+      registerIndex += ValueType.OBJECT.requiredRegisters();
     }
 
     String shorty = callSite.methodProto.shorty.toString();
 
     for (int i = 1; i < shorty.length(); i++) {
-      MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
-      arguments.add(readRegister(argumentRegisters[registerIndex], moveType));
-      registerIndex += moveType.requiredRegisters();
+      ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
+      arguments.add(readRegister(argumentRegisters[registerIndex], valueType));
+      registerIndex += valueType.requiredRegisters();
     }
 
     add(new InvokeCustom(callSite, null, arguments));
@@ -1126,23 +1117,23 @@
 
     int register = firstArgumentRegister;
     if (!bootstrapMethod.isStaticHandle()) {
-      arguments.add(readRegister(register, MoveType.OBJECT));
-      register += MoveType.OBJECT.requiredRegisters();
+      arguments.add(readRegister(register, ValueType.OBJECT));
+      register += ValueType.OBJECT.requiredRegisters();
     }
 
     String shorty = callSite.methodProto.shorty.toString();
 
     for (int i = 1; i < shorty.length(); i++) {
-      MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
-      arguments.add(readRegister(register, moveType));
-      register += moveType.requiredRegisters();
+      ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
+      arguments.add(readRegister(register, valueType));
+      register += valueType.requiredRegisters();
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
     add(new InvokeCustom(callSite, null, arguments));
   }
 
   public void addInvokeCustom(
-      DexCallSite callSite, List<MoveType> types, List<Integer> registers) {
+      DexCallSite callSite, List<ValueType> types, List<Integer> registers) {
     assert types.size() == registers.size();
     List<Value> arguments = new ArrayList<>(types.size());
     for (int i = 0; i < types.size(); i++) {
@@ -1163,8 +1154,8 @@
     List<Value> arguments = new ArrayList<>(argumentRegisterCount);
     int registerIndex = 0;
     if (type != Invoke.Type.STATIC) {
-      arguments.add(readRegister(argumentRegisters[registerIndex], MoveType.OBJECT));
-      registerIndex += MoveType.OBJECT.requiredRegisters();
+      arguments.add(readRegister(argumentRegisters[registerIndex], ValueType.OBJECT));
+      registerIndex += ValueType.OBJECT.requiredRegisters();
     }
     DexString methodShorty;
     if (type == Invoke.Type.POLYMORPHIC) {
@@ -1176,9 +1167,9 @@
     }
     String shorty = methodShorty.toString();
     for (int i = 1; i < methodShorty.size; i++) {
-      MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
-      arguments.add(readRegister(argumentRegisters[registerIndex], moveType));
-      registerIndex += moveType.requiredRegisters();
+      ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
+      arguments.add(readRegister(argumentRegisters[registerIndex], valueType));
+      registerIndex += valueType.requiredRegisters();
     }
     checkInvokeArgumentRegisters(registerIndex, argumentRegisterCount);
     addInvoke(type, method, callSiteProto, arguments);
@@ -1189,16 +1180,16 @@
     String descriptor = type.descriptor.toString();
     assert descriptor.charAt(0) == '[';
     assert descriptor.length() >= 2;
-    MoveType moveType = MoveType.fromTypeDescriptorChar(descriptor.charAt(1));
-    List<Value> arguments = new ArrayList<>(argumentCount / moveType.requiredRegisters());
+    ValueType valueType = ValueType.fromTypeDescriptorChar(descriptor.charAt(1));
+    List<Value> arguments = new ArrayList<>(argumentCount / valueType.requiredRegisters());
     int registerIndex = 0;
     while (registerIndex < argumentCount) {
-      arguments.add(readRegister(argumentRegisters[registerIndex], moveType));
-      if (moveType == MoveType.WIDE) {
+      arguments.add(readRegister(argumentRegisters[registerIndex], valueType));
+      if (valueType.isWide()) {
         assert registerIndex < argumentCount - 1;
         assert argumentRegisters[registerIndex] == argumentRegisters[registerIndex + 1] + 1;
       }
-      registerIndex += moveType.requiredRegisters();
+      registerIndex += valueType.requiredRegisters();
     }
     checkInvokeArgumentRegisters(registerIndex, argumentCount);
     addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments);
@@ -1216,8 +1207,8 @@
     List<Value> arguments = new ArrayList<>(argumentCount);
     int register = firstArgumentRegister;
     if (type != Invoke.Type.STATIC) {
-      arguments.add(readRegister(register, MoveType.OBJECT));
-      register += MoveType.OBJECT.requiredRegisters();
+      arguments.add(readRegister(register, ValueType.OBJECT));
+      register += ValueType.OBJECT.requiredRegisters();
     }
     DexString methodShorty;
     if (type == Invoke.Type.POLYMORPHIC) {
@@ -1229,9 +1220,9 @@
     }
     String shorty = methodShorty.toString();
     for (int i = 1; i < methodShorty.size; i++) {
-      MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
-      arguments.add(readRegister(register, moveType));
-      register += moveType.requiredRegisters();
+      ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
+      arguments.add(readRegister(register, valueType));
+      register += valueType.requiredRegisters();
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
     addInvoke(type, method, callSiteProto, arguments);
@@ -1242,12 +1233,12 @@
     String descriptor = type.descriptor.toString();
     assert descriptor.charAt(0) == '[';
     assert descriptor.length() >= 2;
-    MoveType moveType = MoveType.fromTypeDescriptorChar(descriptor.charAt(1));
-    List<Value> arguments = new ArrayList<>(argumentCount / moveType.requiredRegisters());
+    ValueType valueType = ValueType.fromTypeDescriptorChar(descriptor.charAt(1));
+    List<Value> arguments = new ArrayList<>(argumentCount / valueType.requiredRegisters());
     int register = firstArgumentRegister;
     while (register < firstArgumentRegister + argumentCount) {
-      arguments.add(readRegister(register, moveType));
-      register += moveType.requiredRegisters();
+      arguments.add(readRegister(register, valueType));
+      register += valueType.requiredRegisters();
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
     addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments);
@@ -1262,7 +1253,7 @@
   }
 
   public void addMoveException(int dest) {
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.NO_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.NO_THROW);
     assert !out.hasLocalInfo();
     MoveException instruction = new MoveException(out);
     assert !instruction.instructionTypeCanThrow();
@@ -1283,7 +1274,7 @@
     addInstruction(instruction);
   }
 
-  public void addMoveResult(MoveType type, int dest) {
+  public void addMoveResult(ValueType type, int dest) {
     List<Instruction> instructions = currentBlock.getInstructions();
     Invoke invoke = instructions.get(instructions.size() - 1).asInvoke();
     assert invoke.outValue() == null;
@@ -1291,7 +1282,7 @@
     invoke.setOutValue(writeRegister(dest, type, ThrowingInfo.CAN_THROW));
   }
 
-  public void addBooleanMoveResult(MoveType type, int dest) {
+  public void addBooleanMoveResult(ValueType type, int dest) {
     List<Instruction> instructions = currentBlock.getInstructions();
     Invoke invoke = instructions.get(instructions.size() - 1).asInvoke();
     assert invoke.outValue() == null;
@@ -1319,25 +1310,25 @@
 
   public void addNewArrayEmpty(int dest, int size, DexType type) {
     assert type.isArrayType();
-    Value in = readRegister(size, MoveType.SINGLE);
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value in = readRegister(size, ValueType.INT);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     NewArrayEmpty instruction = new NewArrayEmpty(out, in, type);
     assert instruction.instructionTypeCanThrow();
     addInstruction(instruction);
   }
 
   public void addNewArrayFilledData(int arrayRef, int elementWidth, long size, short[] data) {
-    add(new NewArrayFilledData(readRegister(arrayRef, MoveType.OBJECT), elementWidth, size, data));
+    add(new NewArrayFilledData(readRegister(arrayRef, ValueType.OBJECT), elementWidth, size, data));
   }
 
   public void addNewInstance(int dest, DexType type) {
-    Value out = writeRegister(dest, MoveType.OBJECT, ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
     NewInstance instruction = new NewInstance(type, out);
     assert instruction.instructionTypeCanThrow();
     addInstruction(instruction);
   }
 
-  public void addReturn(MoveType type, int value) {
+  public void addReturn(ValueType type, int value) {
     Value in = readRegister(value, type);
     addReturn(new Return(in, type));
   }
@@ -1355,7 +1346,7 @@
   }
 
   public void addStaticGet(MemberType type, int dest, DexField field) {
-    Value out = writeRegister(dest, MoveType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+    Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
     out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
     StaticGet instruction = new StaticGet(type, out, field);
     assert instruction.instructionTypeCanThrow();
@@ -1363,7 +1354,7 @@
   }
 
   public void addStaticPut(MemberType type, int value, DexField field) {
-    Value in = readRegister(value, MoveType.fromMemberType(type));
+    Value in = readRegister(value, ValueType.fromMemberType(type));
     add(new StaticPut(type, in, field));
   }
 
@@ -1388,22 +1379,6 @@
     addInstruction(instruction);
   }
 
-  private void addSwitchIf(int key, int value, int caseOffset, int fallthroughOffset) {
-    if (key == 0) {
-      addIfZero(If.Type.EQ, value, caseOffset, fallthroughOffset);
-    } else {
-      if (caseOffset == fallthroughOffset) {
-        addTrivialIf(caseOffset, fallthroughOffset);
-      } else {
-        List<Value> values = new ArrayList<>(2);
-        values.add(readRegister(value, MoveType.SINGLE));
-        values.add(readLiteral(NumericType.INT, key));
-        If instruction = new If(If.Type.EQ, values);
-        addNonTrivialIf(instruction, caseOffset, fallthroughOffset);
-      }
-    }
-  }
-
   public void addSwitch(int value, int[] keys, int fallthroughOffset, int[] labelOffsets) {
     int numberOfTargets = labelOffsets.length;
     assert (keys.length == 1) || (keys.length == numberOfTargets);
@@ -1414,7 +1389,7 @@
       return;
     }
 
-    Value switchValue = readRegister(value, MoveType.SINGLE);
+    Value switchValue = readRegister(value, ValueType.INT);
 
     // Find the keys not targeting the fallthrough.
     IntList nonFallthroughKeys = new IntArrayList(numberOfTargets);
@@ -1494,7 +1469,7 @@
   }
 
   public void addThrow(int value) {
-    Value in = readRegister(value, MoveType.OBJECT);
+    Value in = readRegister(value, ValueType.OBJECT);
     addInstruction(new Throw(in));
     closeCurrentBlock();
   }
@@ -1522,7 +1497,7 @@
   public void addShl(NumericType type, int dest, int left, int right) {
     assert isIntegerType(type);
     Value in1 = readNumericRegister(left, type);
-    Value in2 = readRegister(right, MoveType.SINGLE);
+    Value in2 = readRegister(right, ValueType.INT);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Shl instruction = new Shl(type, out, in1, in2);
     assert !instruction.instructionTypeCanThrow();
@@ -1542,7 +1517,7 @@
   public void addShr(NumericType type, int dest, int left, int right) {
     assert isIntegerType(type);
     Value in1 = readNumericRegister(left, type);
-    Value in2 = readRegister(right, MoveType.SINGLE);
+    Value in2 = readRegister(right, ValueType.INT);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Shr instruction = new Shr(type, out, in1, in2);
     assert !instruction.instructionTypeCanThrow();
@@ -1562,7 +1537,7 @@
   public void addUshr(NumericType type, int dest, int left, int right) {
     assert isIntegerType(type);
     Value in1 = readNumericRegister(left, type);
-    Value in2 = readRegister(right, MoveType.SINGLE);
+    Value in2 = readRegister(right, ValueType.INT);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Ushr instruction = new Ushr(type, out, in1, in2);
     assert !instruction.instructionTypeCanThrow();
@@ -1621,7 +1596,7 @@
 
   // Value abstraction methods.
 
-  public Value readRegister(int register, MoveType type) {
+  public Value readRegister(int register, ValueType type) {
     DebugLocalInfo local = getCurrentLocal(register);
     Value value = readRegister(register, type, currentBlock, EdgeType.NON_EDGE, local);
     // Check that any information about a current-local is consistent with the read.
@@ -1640,12 +1615,12 @@
     return value;
   }
 
-  public Value readRegisterIgnoreLocal(int register, MoveType type) {
+  public Value readRegisterIgnoreLocal(int register, ValueType type) {
     DebugLocalInfo local = getCurrentLocal(register);
     return readRegister(register, type, currentBlock, EdgeType.NON_EDGE, local);
   }
 
-  public Value readRegister(int register, MoveType type, BasicBlock block, EdgeType readingEdge,
+  public Value readRegister(int register, ValueType type, BasicBlock block, EdgeType readingEdge,
       DebugLocalInfo local) {
     checkRegister(register);
     Value value = block.readCurrentDefinition(register, readingEdge);
@@ -1653,7 +1628,7 @@
   }
 
   private Value readRegisterRecursive(
-      int register, BasicBlock block, EdgeType readingEdge, MoveType type, DebugLocalInfo local) {
+      int register, BasicBlock block, EdgeType readingEdge, ValueType type, DebugLocalInfo local) {
     Value value;
     if (!block.isSealed()) {
       assert !blocks.isEmpty() : "No write to " + register;
@@ -1680,33 +1655,33 @@
   }
 
   public Value readNumericRegister(int register, NumericType type) {
-    return readRegister(register, type.moveTypeFor());
+    return readRegister(register, ValueType.fromNumericType(type));
   }
 
   public Value readLiteral(NumericType type, long constant) {
-    Value value = new Value(valueNumberGenerator.next(), MoveType.fromNumericType(type), null);
-    add(new ConstNumber(ConstType.fromNumericType(type), value, constant));
+    Value value = new Value(valueNumberGenerator.next(), ValueType.fromNumericType(type), null);
+    add(new ConstNumber(ValueType.fromNumericType(type), value, constant));
     return value;
   }
 
   // This special write register is needed when changing the scoping of a local variable.
   // See addDebugLocalStart and addDebugLocalEnd.
   private Value writeRegister(
-      int register, MoveType type, ThrowingInfo throwing, DebugLocalInfo local) {
+      int register, ValueType type, ThrowingInfo throwing, DebugLocalInfo local) {
     checkRegister(register);
     Value value = new Value(valueNumberGenerator.next(), type, local);
     currentBlock.writeCurrentDefinition(register, value, throwing);
     return value;
   }
 
-  public Value writeRegister(int register, MoveType type, ThrowingInfo throwing) {
+  public Value writeRegister(int register, ValueType type, ThrowingInfo throwing) {
     DebugLocalInfo local = getCurrentLocal(register);
     previousLocalValue = local == null ? null : readRegisterIgnoreLocal(register, type);
     return writeRegister(register, type, throwing, local);
   }
 
   public Value writeNumericRegister(int register, NumericType type, ThrowingInfo throwing) {
-    return writeRegister(register, type.moveTypeFor(), throwing);
+    return writeRegister(register, ValueType.fromNumericType(type), throwing);
   }
 
   private DebugLocalInfo getCurrentLocal(int register) {
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 3cd2b57..c966690 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
@@ -22,14 +22,13 @@
 import com.android.tools.r8.graph.JarApplicationReader;
 import com.android.tools.r8.ir.code.CatchHandlers;
 import com.android.tools.r8.ir.code.Cmp.Bias;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.Monitor;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder.BlockInfo;
 import com.android.tools.r8.ir.conversion.JarState.Local;
 import com.android.tools.r8.ir.conversion.JarState.Slot;
@@ -246,9 +245,9 @@
   @Override
   public void buildPrelude(IRBuilder builder) {
     // Record types for arguments.
-    Int2ReferenceMap<MoveType> argumentLocals = recordArgumentTypes();
-    Int2ReferenceMap<MoveType> initializedLocals = new Int2ReferenceOpenHashMap<>(argumentLocals);
-    Int2ReferenceMap<ConstType> uninitializedLocals = new Int2ReferenceOpenHashMap<>();
+    Int2ReferenceMap<ValueType> argumentLocals = recordArgumentTypes();
+    Int2ReferenceMap<ValueType> initializedLocals = new Int2ReferenceOpenHashMap<>(argumentLocals);
+    Int2ReferenceMap<ValueType> uninitializedLocals = new Int2ReferenceOpenHashMap<>();
     // Initialize all non-argument locals to ensure safe insertion of debug-local instructions.
     for (Object o : node.localVariables) {
       LocalVariableNode local = (LocalVariableNode) o;
@@ -271,13 +270,14 @@
           break;
       }
       int localRegister = state.getLocalRegister(local.index, localType);
-      MoveType existingLocalType = initializedLocals.get(localRegister);
-      assert existingLocalType == null || existingLocalType == moveType(localType);
+      ValueType existingLocalType = initializedLocals.get(localRegister);
+      ValueType localValueType = valueType(localType);
+      assert existingLocalType == null || existingLocalType.compatible(localValueType);
       if (existingLocalType == null) {
         int localRegister2 = state.writeLocal(local.index, localType);
         assert localRegister == localRegister2;
-        initializedLocals.put(localRegister, moveType(localType));
-        uninitializedLocals.put(localRegister, constType(localType));
+        initializedLocals.put(localRegister, localValueType);
+        uninitializedLocals.put(localRegister, localValueType);
       }
     }
 
@@ -295,7 +295,7 @@
     // for arguments.
     buildArgumentInstructions(builder);
 
-    for (Entry<ConstType> entry : uninitializedLocals.int2ReferenceEntrySet()) {
+    for (Entry<ValueType> entry : uninitializedLocals.int2ReferenceEntrySet()) {
       builder.addDebugUninitialized(entry.getIntKey(), entry.getValue());
     }
 
@@ -337,31 +337,31 @@
       builder.addThisArgument(slot.register);
     }
     for (Type type : parameterTypes) {
-      MoveType moveType = moveType(type);
+      ValueType valueType = valueType(type);
       Slot slot = state.readLocal(argumentRegister, type);
       if (type == Type.BOOLEAN_TYPE) {
         builder.addBooleanNonThisArgument(slot.register);
       } else {
-        builder.addNonThisArgument(slot.register, moveType);
+        builder.addNonThisArgument(slot.register, valueType);
       }
-      argumentRegister += moveType.requiredRegisters();
+      argumentRegister += valueType.requiredRegisters();
     }
   }
 
-  private Int2ReferenceMap<MoveType> recordArgumentTypes() {
-    Int2ReferenceMap<MoveType> initializedLocals =
+  private Int2ReferenceMap<ValueType> recordArgumentTypes() {
+    Int2ReferenceMap<ValueType> initializedLocals =
         new Int2ReferenceOpenHashMap<>(node.localVariables.size());
     int argumentRegister = 0;
     if (!isStatic()) {
       Type thisType = Type.getType(clazz.descriptor.toString());
       int register = state.writeLocal(argumentRegister++, thisType);
-      initializedLocals.put(register, moveType(thisType));
+      initializedLocals.put(register, valueType(thisType));
     }
     for (Type type : parameterTypes) {
-      MoveType moveType = moveType(type);
+      ValueType valueType = valueType(type);
       int register = state.writeLocal(argumentRegister, type);
-      argumentRegister += moveType.requiredRegisters();
-      initializedLocals.put(register, moveType);
+      argumentRegister += valueType.requiredRegisters();
+      initializedLocals.put(register, valueType);
     }
     return initializedLocals;
   }
@@ -804,49 +804,27 @@
 
   // Type conversion helpers.
 
-  private static MoveType moveType(Type type) {
+  private static ValueType valueType(Type type) {
     switch (type.getSort()) {
       case Type.ARRAY:
       case Type.OBJECT:
-        return MoveType.OBJECT;
+        return ValueType.OBJECT;
       case Type.BOOLEAN:
       case Type.BYTE:
       case Type.SHORT:
       case Type.CHAR:
       case Type.INT:
+        return ValueType.INT;
       case Type.FLOAT:
-        return MoveType.SINGLE;
+        return ValueType.FLOAT;
       case Type.LONG:
+        return ValueType.LONG;
       case Type.DOUBLE:
-        return MoveType.WIDE;
+        return ValueType.DOUBLE;
       case Type.VOID:
         // Illegal. Throws in fallthrough.
       default:
-        throw new Unreachable("Invalid type in moveType: " + type);
-    }
-  }
-
-  private static ConstType constType(Type type) {
-    switch (type.getSort()) {
-      case Type.ARRAY:
-      case Type.OBJECT:
-        return ConstType.OBJECT;
-      case Type.BOOLEAN:
-      case Type.BYTE:
-      case Type.SHORT:
-      case Type.CHAR:
-      case Type.INT:
-        return ConstType.INT;
-      case Type.FLOAT:
-        return ConstType.FLOAT;
-      case Type.LONG:
-        return ConstType.LONG;
-      case Type.DOUBLE:
-        return ConstType.DOUBLE;
-      case Type.VOID:
-        // Illegal. Throws in fallthrough.
-      default:
-        throw new Unreachable("Invalid type in constType: " + type);
+        throw new Unreachable("Invalid type in valueType: " + type);
     }
   }
 
@@ -1924,7 +1902,7 @@
         Slot value = state.peek();
         assert value.isCategory1();
         int copy = state.push(value.type);
-        builder.addMove(moveType(value.type), copy, value.register);
+        builder.addMove(valueType(value.type), copy, value.register);
         break;
       }
       case Opcodes.DUP_X1: {
@@ -1938,9 +1916,9 @@
         assert value2.register == stack2;
         assert value1.register == stack1;
         // stack0 is new top-of-stack.
-        builder.addMove(moveType(value1.type), stack0, stack1);
-        builder.addMove(moveType(value2.type), stack1, stack2);
-        builder.addMove(moveType(value1.type), stack2, stack0);
+        builder.addMove(valueType(value1.type), stack0, stack1);
+        builder.addMove(valueType(value2.type), stack1, stack2);
+        builder.addMove(valueType(value1.type), stack2, stack0);
         break;
       }
       case Opcodes.DUP_X2: {
@@ -1968,13 +1946,13 @@
           state.push(value1.type);
           int copy2 = state.push(value2.type);
           int copy1 = state.push(value1.type);
-          builder.addMove(moveType(value1.type), copy1, value1.register);
-          builder.addMove(moveType(value2.type), copy2, value2.register);
+          builder.addMove(valueType(value1.type), copy1, value1.register);
+          builder.addMove(valueType(value2.type), copy2, value2.register);
         } else {
           // Stack transformation: ..., w1 -> ..., w1, w1
           state.push(value1.type);
           int copy1 = state.push(value1.type);
-          builder.addMove(moveType(value1.type), copy1, value1.register);
+          builder.addMove(valueType(value1.type), copy1, value1.register);
         }
         break;
       }
@@ -2030,9 +2008,9 @@
         state.push(value1.type);
         state.push(value2.type);
         int tmp = state.push(value1.type);
-        builder.addMove(moveType(value1.type), tmp, value1.register);
-        builder.addMove(moveType(value2.type), value1.register, value2.register);
-        builder.addMove(moveType(value1.type), value2.register, tmp);
+        builder.addMove(valueType(value1.type), tmp, value1.register);
+        builder.addMove(valueType(value2.type), value1.register, value2.register);
+        builder.addMove(valueType(value1.type), value2.register, tmp);
         state.pop(); // Remove temp.
         break;
       }
@@ -2206,27 +2184,27 @@
       }
       case Opcodes.IRETURN: {
         Slot value = state.pop(Type.INT_TYPE);
-        addReturn(insn, MoveType.SINGLE, value.register, builder);
+        addReturn(insn, ValueType.INT, value.register, builder);
         break;
       }
       case Opcodes.LRETURN: {
         Slot value = state.pop(Type.LONG_TYPE);
-        addReturn(insn, MoveType.WIDE, value.register, builder);
+        addReturn(insn, ValueType.LONG, value.register, builder);
         break;
       }
       case Opcodes.FRETURN: {
         Slot value = state.pop(Type.FLOAT_TYPE);
-        addReturn(insn, MoveType.SINGLE, value.register, builder);
+        addReturn(insn, ValueType.FLOAT, value.register, builder);
         break;
       }
       case Opcodes.DRETURN: {
         Slot value = state.pop(Type.DOUBLE_TYPE);
-        addReturn(insn, MoveType.WIDE, value.register, builder);
+        addReturn(insn, ValueType.DOUBLE, value.register, builder);
         break;
       }
       case Opcodes.ARETURN: {
         Slot obj = state.pop(JarState.REFERENCE_TYPE);
-        addReturn(insn, MoveType.OBJECT, obj.register, builder);
+        addReturn(insn, ValueType.OBJECT, obj.register, builder);
         break;
       }
       case Opcodes.RETURN: {
@@ -2279,7 +2257,7 @@
     builder.addThrow(register);
   }
 
-  private void addReturn(InsnNode insn, MoveType type, int register, IRBuilder builder) {
+  private void addReturn(InsnNode insn, ValueType type, int register, IRBuilder builder) {
     processLocalVariablesAtExit(insn, builder);
     if (type == null) {
       assert register == -1;
@@ -2297,10 +2275,10 @@
     assert value3.register == stack3;
     assert value2.register == stack2;
     assert value1.register == stack1;
-    builder.addMove(moveType(value1.type), stack0, stack1);
-    builder.addMove(moveType(value2.type), stack1, stack2);
-    builder.addMove(moveType(value3.type), stack2, stack3);
-    builder.addMove(moveType(value1.type), stack3, stack0);
+    builder.addMove(valueType(value1.type), stack0, stack1);
+    builder.addMove(valueType(value2.type), stack1, stack2);
+    builder.addMove(valueType(value3.type), stack2, stack3);
+    builder.addMove(valueType(value1.type), stack3, stack0);
   }
 
   private void dupOneBelowOne(Slot value2, Slot value1, IRBuilder builder) {
@@ -2309,9 +2287,9 @@
     int stack0 = state.push(value1.type);
     assert value2.register == stack2;
     assert value1.register == stack1;
-    builder.addMove(moveType(value1.type), stack0, stack1);
-    builder.addMove(moveType(value2.type), stack1, stack2);
-    builder.addMove(moveType(value1.type), stack2, stack0);
+    builder.addMove(valueType(value1.type), stack0, stack1);
+    builder.addMove(valueType(value2.type), stack1, stack2);
+    builder.addMove(valueType(value1.type), stack2, stack0);
   }
 
   private void dupTwoBelowOne(Slot value3, Slot value2, Slot value1, IRBuilder builder) {
@@ -2323,11 +2301,11 @@
     assert value3.register == stack4;
     assert value2.register == stack3;
     assert value1.register == stack2;
-    builder.addMove(moveType(value1.type), stack0, stack2);
-    builder.addMove(moveType(value2.type), stack1, stack3);
-    builder.addMove(moveType(value3.type), stack2, stack4);
-    builder.addMove(moveType(value1.type), stack3, stack0);
-    builder.addMove(moveType(value2.type), stack4, stack1);
+    builder.addMove(valueType(value1.type), stack0, stack2);
+    builder.addMove(valueType(value2.type), stack1, stack3);
+    builder.addMove(valueType(value3.type), stack2, stack4);
+    builder.addMove(valueType(value1.type), stack3, stack0);
+    builder.addMove(valueType(value2.type), stack4, stack1);
   }
 
   private void dupTwoBelowTwo(Slot value4, Slot value3, Slot value2, Slot value1,
@@ -2342,12 +2320,12 @@
     assert value3.register == stack4;
     assert value2.register == stack3;
     assert value1.register == stack2;
-    builder.addMove(moveType(value1.type), stack0, stack2);
-    builder.addMove(moveType(value2.type), stack1, stack3);
-    builder.addMove(moveType(value3.type), stack2, stack4);
-    builder.addMove(moveType(value3.type), stack3, stack5);
-    builder.addMove(moveType(value1.type), stack4, stack0);
-    builder.addMove(moveType(value2.type), stack5, stack1);
+    builder.addMove(valueType(value1.type), stack0, stack2);
+    builder.addMove(valueType(value2.type), stack1, stack3);
+    builder.addMove(valueType(value3.type), stack2, stack4);
+    builder.addMove(valueType(value3.type), stack3, stack5);
+    builder.addMove(valueType(value1.type), stack4, stack0);
+    builder.addMove(valueType(value2.type), stack5, stack1);
   }
 
   private void buildConversion(Type from, Type to, IRBuilder builder) {
@@ -2411,12 +2389,12 @@
     if (Opcodes.ILOAD <= opcode && opcode <= Opcodes.ALOAD) {
       Slot src = state.readLocal(insn.var, expectedType);
       int dest = state.push(src.type);
-      builder.addMove(moveType(src.type), dest, src.register);
+      builder.addMove(valueType(src.type), dest, src.register);
     } else {
       assert Opcodes.ISTORE <= opcode && opcode <= Opcodes.ASTORE;
       Slot src = state.pop(expectedType);
       int dest = state.writeLocal(insn.var, src.type);
-      builder.addMove(moveType(src.type), dest, src.register);
+      builder.addMove(valueType(src.type), dest, src.register);
     }
   }
 
@@ -2511,7 +2489,7 @@
       Type methodOwner,
       boolean addImplicitReceiver,
       IRBuilder builder,
-      ThrowingBiConsumer<List<MoveType>, List<Integer>, ApiLevelException> creator)
+      ThrowingBiConsumer<List<ValueType>, List<Integer>, ApiLevelException> creator)
       throws ApiLevelException {
 
     // Build the argument list of the form [owner, param1, ..., paramN].
@@ -2519,7 +2497,7 @@
     Type[] parameterTypes = Type.getArgumentTypes(methodDesc);
     Slot[] parameterRegisters = state.popReverse(parameterTypes.length);
 
-    List<MoveType> types = new ArrayList<>(parameterTypes.length + 1);
+    List<ValueType> types = new ArrayList<>(parameterTypes.length + 1);
     List<Integer> registers = new ArrayList<>(parameterTypes.length + 1);
 
     // Add receiver argument for non-static calls.
@@ -2539,17 +2517,17 @@
     Type returnType = Type.getReturnType(methodDesc);
     if (returnType != Type.VOID_TYPE) {
       if (returnType == Type.BOOLEAN_TYPE) {
-        builder.addBooleanMoveResult(moveType(returnType), state.push(returnType));
+        builder.addBooleanMoveResult(valueType(returnType), state.push(returnType));
       } else {
-        builder.addMoveResult(moveType(returnType), state.push(returnType));
+        builder.addMoveResult(valueType(returnType), state.push(returnType));
       }
     }
   }
 
-  private static void addArgument(List<MoveType> types, List<Integer> registers, Type type,
+  private static void addArgument(List<ValueType> types, List<Integer> registers, Type type,
       Slot slot) {
     assert slot.isCompatibleWith(type);
-    types.add(moveType(type));
+    types.add(valueType(type));
     registers.add(slot.register);
   }
 
@@ -2787,7 +2765,7 @@
     }
     builder.addInvokeNewArray(dimArrayType, insn.dims, dimensions);
     int dimensionsDestTemp = state.push(INT_ARRAY_TYPE);
-    builder.addMoveResult(MoveType.OBJECT, dimensionsDestTemp);
+    builder.addMoveResult(ValueType.OBJECT, dimensionsDestTemp);
     // Push the class object for the member type of the array.
     int classDestTemp = state.push(CLASS_TYPE);
     builder.ensureBlockForThrowingInstruction();
@@ -2796,7 +2774,7 @@
     DexType reflectArrayClass = application.getTypeFromDescriptor(REFLECT_ARRAY_DESC);
     DexMethod newInstance = application.getMethod(reflectArrayClass,
         REFLECT_ARRAY_NEW_INSTANCE_NAME, REFLECT_ARRAY_NEW_INSTANCE_DESC);
-    List<MoveType> argumentTypes = Arrays.asList(moveType(CLASS_TYPE), moveType(INT_ARRAY_TYPE));
+    List<ValueType> argumentTypes = Arrays.asList(valueType(CLASS_TYPE), valueType(INT_ARRAY_TYPE));
     List<Integer> argumentRegisters = Arrays.asList(classDestTemp, dimensionsDestTemp);
     builder.ensureBlockForThrowingInstruction();
     builder.addInvoke(Invoke.Type.STATIC, newInstance, null, argumentTypes, argumentRegisters);
@@ -2804,7 +2782,7 @@
     state.pop(); // classDestTemp.
     state.pop(); // dimensionsDestTemp.
     int result = state.push(arrayType);
-    builder.addMoveResult(moveType(arrayType), result);
+    builder.addMoveResult(valueType(arrayType), result);
     // Insert cast check to satisfy verification.
     builder.ensureBlockForThrowingInstruction();
     builder.addCheckCast(result, dexArrayType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
index 2460798..551d629 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import java.util.ArrayList;
 import java.util.List;
@@ -88,39 +88,39 @@
     DexType[] accessorParams = proto.parameters.values;
 
     // Prepare call arguments.
-    List<MoveType> argMoveTypes = new ArrayList<>();
+    List<ValueType> argValueTypes = new ArrayList<>();
     List<Integer> argRegisters = new ArrayList<>();
 
     // If we are delegating to a constructor, we need to create the instance
     // first. This instance will be the first argument to the call.
     if (delegatingToConstructor()) {
-      int instance = nextRegister(MoveType.OBJECT);
+      int instance = nextRegister(ValueType.OBJECT);
       add(builder -> builder.addNewInstance(instance, implMethod.holder));
-      argMoveTypes.add(MoveType.OBJECT);
+      argValueTypes.add(ValueType.OBJECT);
       argRegisters.add(instance);
     }
 
     for (int i = 0; i < accessorParams.length; i++) {
       DexType param = accessorParams[i];
-      argMoveTypes.add(MoveType.fromDexType(param));
+      argValueTypes.add(ValueType.fromDexType(param));
       argRegisters.add(getParamRegister(i));
     }
 
     // Method call to the original impl-method.
     add(builder -> builder.addInvoke(inferInvokeType(),
-        implMethod, implMethod.proto, argMoveTypes, argRegisters));
+        implMethod, implMethod.proto, argValueTypes, argRegisters));
 
     // Does the method have return value?
     if (proto.returnType == factory().voidType) {
       add(IRBuilder::addReturn);
     } else if (delegatingToConstructor()) {
       // Return newly created instance
-      add(builder -> builder.addReturn(MoveType.OBJECT, argRegisters.get(0)));
+      add(builder -> builder.addReturn(ValueType.OBJECT, argRegisters.get(0)));
     } else {
-      MoveType moveType = MoveType.fromDexType(proto.returnType);
-      int tempValue = nextRegister(moveType);
-      add(builder -> builder.addMoveResult(moveType, tempValue));
-      add(builder -> builder.addReturn(moveType, tempValue));
+      ValueType valueType = ValueType.fromDexType(proto.returnType);
+      int tempValue = nextRegister(valueType);
+      add(builder -> builder.addMoveResult(valueType, tempValue));
+      add(builder -> builder.addReturn(valueType, tempValue));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
index cc4f1f2..20286a8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import java.util.ArrayList;
 import java.util.List;
@@ -28,33 +28,33 @@
     DexType[] enforcedParams = descriptor().enforcedProto.parameters.values;
 
     // Prepare call arguments.
-    List<MoveType> argMoveTypes = new ArrayList<>();
+    List<ValueType> argValueTypes = new ArrayList<>();
     List<Integer> argRegisters = new ArrayList<>();
 
     // Always add a receiver representing 'this' of the lambda class.
-    argMoveTypes.add(MoveType.OBJECT);
+    argValueTypes.add(ValueType.OBJECT);
     argRegisters.add(getReceiverRegister());
 
     // Prepare arguments.
     for (int i = 0; i < currentParams.length; i++) {
       DexType expectedParamType = enforcedParams[i];
-      argMoveTypes.add(MoveType.fromDexType(expectedParamType));
+      argValueTypes.add(ValueType.fromDexType(expectedParamType));
       argRegisters.add(enforceParameterType(
           getParamRegister(i), currentParams[i], expectedParamType));
     }
 
     // Method call to the main functional interface method.
     add(builder -> builder.addInvoke(Invoke.Type.VIRTUAL,
-        this.mainMethod, this.mainMethod.proto, argMoveTypes, argRegisters));
+        this.mainMethod, this.mainMethod.proto, argValueTypes, argRegisters));
 
     // Does the method have return value?
     if (proto.returnType == factory().voidType) {
       add(IRBuilder::addReturn);
     } else {
-      MoveType moveType = MoveType.fromDexType(proto.returnType);
-      int tempValue = nextRegister(moveType);
-      add(builder -> builder.addMoveResult(moveType, tempValue));
-      add(builder -> builder.addReturn(moveType, tempValue));
+      ValueType valueType = ValueType.fromDexType(proto.returnType);
+      int tempValue = nextRegister(valueType);
+      add(builder -> builder.addMoveResult(valueType, tempValue));
+      add(builder -> builder.addReturn(valueType, tempValue));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index 411ab4c..ea891ea 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import java.util.Collections;
 
@@ -22,11 +22,11 @@
   @Override
   protected void prepareInstructions() {
     // Create and initialize an instance.
-    int instance = nextRegister(MoveType.OBJECT);
+    int instance = nextRegister(ValueType.OBJECT);
     add(builder -> builder.addNewInstance(instance, lambda.type));
     add(builder -> builder.addInvoke(
         Invoke.Type.DIRECT, lambda.constructor, lambda.constructor.proto,
-        Collections.singletonList(MoveType.OBJECT), Collections.singletonList(instance)));
+        Collections.singletonList(ValueType.OBJECT), Collections.singletonList(instance)));
 
     // Assign to a field.
     add(builder -> builder.addStaticPut(MemberType.OBJECT, instance, lambda.instanceField));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index a4de54f..40911e5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -13,8 +13,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.google.common.collect.Lists;
 import java.util.ArrayList;
@@ -212,15 +212,15 @@
         constructorTarget ? target.callTarget.holder : implReturnType);
 
     // Prepare call arguments.
-    List<MoveType> argMoveTypes = new ArrayList<>();
+    List<ValueType> argValueTypes = new ArrayList<>();
     List<Integer> argRegisters = new ArrayList<>();
 
     // If the target is a constructor, we need to create the instance first.
     // This instance will be the first argument to the call.
     if (constructorTarget) {
-      int instance = nextRegister(MoveType.OBJECT);
+      int instance = nextRegister(ValueType.OBJECT);
       add(builder -> builder.addNewInstance(instance, methodToCall.holder));
-      argMoveTypes.add(MoveType.OBJECT);
+      argValueTypes.add(ValueType.OBJECT);
       argRegisters.add(instance);
     }
 
@@ -228,10 +228,10 @@
     int capturedValues = capturedTypes.length;
     for (int i = 0; i < capturedValues; i++) {
       MemberType memberType = MemberType.fromDexType(capturedTypes[i]);
-      MoveType moveType = MemberType.moveTypeFor(memberType);
-      int register = nextRegister(moveType);
+      ValueType valueType = MemberType.moveTypeFor(memberType);
+      int register = nextRegister(valueType);
 
-      argMoveTypes.add(moveType);
+      argValueTypes.add(valueType);
       argRegisters.add(register);
 
       // Read field into tmp local.
@@ -243,14 +243,14 @@
     // Prepare arguments.
     for (int i = 0; i < erasedParams.length; i++) {
       DexType expectedParamType = implReceiverAndArgs.get(i + capturedValues);
-      argMoveTypes.add(MoveType.fromDexType(expectedParamType));
+      argValueTypes.add(ValueType.fromDexType(expectedParamType));
       argRegisters.add(prepareParameterValue(
           getParamRegister(i), erasedParams[i], enforcedParams[i], expectedParamType));
     }
 
     // Method call to the method implementing lambda or method-ref.
     add(builder -> builder.addInvoke(target.invokeType,
-        methodToCall, methodToCall.proto, argMoveTypes, argRegisters));
+        methodToCall, methodToCall.proto, argValueTypes, argRegisters));
 
     // Does the method have return value?
     if (enforcedReturnType.isVoidType()) {
@@ -261,15 +261,15 @@
       int adjustedValue = prepareReturnValue(instanceRegister,
           erasedReturnType, enforcedReturnType, methodToCall.holder);
       add(builder -> builder.addReturn(
-          MoveType.fromDexType(erasedReturnType), adjustedValue));
+          ValueType.fromDexType(erasedReturnType), adjustedValue));
     } else {
-      MoveType implMoveType = MoveType.fromDexType(implReturnType);
-      int tempValue = nextRegister(implMoveType);
-      add(builder -> builder.addMoveResult(implMoveType, tempValue));
+      ValueType implValueType = ValueType.fromDexType(implReturnType);
+      int tempValue = nextRegister(implValueType);
+      add(builder -> builder.addMoveResult(implValueType, tempValue));
       int adjustedValue = prepareReturnValue(tempValue,
           erasedReturnType, enforcedReturnType, methodToCall.proto.returnType);
-      MoveType adjustedMoveType = MoveType.fromDexType(erasedReturnType);
-      add(builder -> builder.addReturn(adjustedMoveType, adjustedValue));
+      ValueType adjustedValueType = ValueType.fromDexType(erasedReturnType);
+      add(builder -> builder.addReturn(adjustedValueType, adjustedValue));
     }
   }
 
@@ -379,7 +379,7 @@
           if (from != NumericType.BYTE) {
             break; // Only BYTE can be converted to SHORT via widening conversion.
           }
-          int result = nextRegister(MoveType.SINGLE);
+          int result = nextRegister(ValueType.INT);
           add(builder -> builder.addConversion(to, NumericType.INT, result, register));
           return result;
         }
@@ -394,7 +394,7 @@
           if (from == NumericType.FLOAT || from == NumericType.DOUBLE) {
             break; // Not a widening conversion.
           }
-          int result = nextRegister(MoveType.WIDE);
+          int result = nextRegister(ValueType.LONG);
           add(builder -> builder.addConversion(to, NumericType.INT, result, register));
           return result;
         }
@@ -403,14 +403,14 @@
           if (from == NumericType.DOUBLE) {
             break; // Not a widening conversion.
           }
-          int result = nextRegister(MoveType.SINGLE);
+          int result = nextRegister(ValueType.FLOAT);
           NumericType type = (from == NumericType.LONG) ? NumericType.LONG : NumericType.INT;
           add(builder -> builder.addConversion(to, type, result, register));
           return result;
         }
 
         case DOUBLE: {
-          int result = nextRegister(MoveType.WIDE);
+          int result = nextRegister(ValueType.DOUBLE);
           NumericType type = (from == NumericType.FLOAT || from == NumericType.LONG)
               ? from : NumericType.INT;
           add(builder -> builder.addConversion(to, type, result, register));
@@ -462,14 +462,14 @@
   private int addPrimitiveUnboxing(int register, DexType primitiveType, DexType boxType) {
     DexMethod method = getUnboxMethod(primitiveType.descriptor.content[0], boxType);
 
-    List<MoveType> argMoveTypes = Collections.singletonList(MoveType.OBJECT);
+    List<ValueType> argValueTypes = Collections.singletonList(ValueType.OBJECT);
     List<Integer> argRegisters = Collections.singletonList(register);
     add(builder -> builder.addInvoke(Invoke.Type.VIRTUAL,
-        method, method.proto, argMoveTypes, argRegisters));
+        method, method.proto, argValueTypes, argRegisters));
 
-    MoveType moveType = MoveType.fromDexType(primitiveType);
-    int result = nextRegister(moveType);
-    add(builder -> builder.addMoveResult(moveType, result));
+    ValueType valueType = ValueType.fromDexType(primitiveType);
+    int result = nextRegister(valueType);
+    add(builder -> builder.addMoveResult(valueType, result));
     return result;
   }
 
@@ -484,14 +484,14 @@
     DexProto proto = factory.createProto(boxType, primitiveType);
     DexMethod method = factory.createMethod(boxType, proto, factory.valueOfMethodName);
 
-    MoveType moveType = MoveType.fromDexType(primitiveType);
-    List<MoveType> argMoveTypes = Collections.singletonList(moveType);
+    ValueType valueType = ValueType.fromDexType(primitiveType);
+    List<ValueType> argValueTypes = Collections.singletonList(valueType);
     List<Integer> argRegisters = Collections.singletonList(register);
     add(builder -> builder.addInvoke(Invoke.Type.STATIC,
-        method, method.proto, argMoveTypes, argRegisters));
+        method, method.proto, argValueTypes, argRegisters));
 
-    int result = nextRegister(MoveType.OBJECT);
-    add(builder -> builder.addMoveResult(MoveType.OBJECT, result));
+    int result = nextRegister(ValueType.OBJECT);
+    add(builder -> builder.addMoveResult(ValueType.OBJECT, result));
     return result;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index f9a7f1f..aad7961 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -23,10 +23,10 @@
 import com.android.tools.r8.ir.code.InvokeCustom;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
@@ -278,7 +278,7 @@
     Value lambdaInstanceValue = invoke.outValue();
     if (lambdaInstanceValue == null) {
       // The out value might be empty in case it was optimized out.
-      lambdaInstanceValue = code.createValue(MoveType.OBJECT);
+      lambdaInstanceValue = code.createValue(ValueType.OBJECT);
     }
 
     // For stateless lambdas we replace InvokeCustom instruction with StaticGet
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
index 525310a..399ae92 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
@@ -20,9 +20,9 @@
 import com.android.tools.r8.ir.code.InvokeCustom;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.google.common.collect.Lists;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -328,7 +328,7 @@
       instructions.previous();
 
       // new-instance v0, StringBuilder
-      Value sbInstance = code.createValue(MoveType.OBJECT);
+      Value sbInstance = code.createValue(ValueType.OBJECT);
       appendInstruction(new NewInstance(factory.stringBuilderType, sbInstance));
 
       // invoke-direct {v0}, void StringBuilder.<init>()
@@ -349,7 +349,7 @@
       Value concatValue = invokeCustom.outValue();
       if (concatValue == null) {
         // The out value might be empty in case it was optimized out.
-        concatValue = code.createValue(MoveType.OBJECT);
+        concatValue = code.createValue(ValueType.OBJECT);
       }
 
       // Replace the instruction.
@@ -427,7 +427,7 @@
 
       @Override
       Value getOrCreateValue() {
-        Value value = code.createValue(MoveType.OBJECT);
+        Value value = code.createValue(ValueType.OBJECT);
         appendInstruction(new ConstString(value, factory.createString(str)));
         return value;
       }
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 e948ace..96ccab1 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
@@ -37,7 +37,6 @@
 import com.android.tools.r8.ir.code.ConstInstruction;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.DebugLocalWrite;
 import com.android.tools.r8.ir.code.DominatorTree;
 import com.android.tools.r8.ir.code.Goto;
@@ -52,7 +51,6 @@
 import com.android.tools.r8.ir.code.InvokeNewArray;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NewArrayEmpty;
 import com.android.tools.r8.ir.code.NewArrayFilledData;
 import com.android.tools.r8.ir.code.NumericType;
@@ -63,6 +61,7 @@
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Switch;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.Xor;
 import com.android.tools.r8.ir.conversion.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.SwitchUtils.EnumSwitchInfo;
@@ -503,7 +502,7 @@
               for (Integer outlier : outliers) {
                 if (outlier != 0) {
                   rewrittenSize += ConstNumber.estimatedDexSize(
-                      ConstType.fromMoveType(theSwitch.value().outType()), outlier);
+                      theSwitch.value().outType(), outlier);
                 }
                 rewrittenSize += If.estimatedDexSize();
               }
@@ -737,10 +736,11 @@
                 if (argumentIndex != -1 && checkArgumentType(invoke, target.method,
                     argumentIndex)) {
                   Value argument = invoke.arguments().get(argumentIndex);
-                  assert (invoke.outType() == argument.outType()) ||
-                      (invoke.outType() == MoveType.OBJECT
-                          && argument.outType() == MoveType.SINGLE
-                          && argument.isZero());
+                  assert invoke.outType().compatible(argument.outType())
+                      || (!options.outputClassFiles
+                            && invoke.outType() == ValueType.OBJECT
+                            && argument.outType().isSingle()
+                            && argument.isZero());
                   invoke.outValue().replaceUsers(argument);
                   invoke.setOutValue(null);
                 }
@@ -1851,7 +1851,7 @@
   }
 
   private Value addConstString(IRCode code, InstructionListIterator iterator, String s) {
-    Value value = code.createValue(MoveType.OBJECT);
+    Value value = code.createValue(ValueType.OBJECT);
     iterator.add(new ConstString(value, dexItemFactory.createString(s)));
     return value;
   }
@@ -1878,7 +1878,7 @@
 
     // Now that the block is split there should not be any catch handlers in the block.
     assert !block.hasCatchHandlers();
-    Value out = code.createValue(MoveType.OBJECT);
+    Value out = code.createValue(ValueType.OBJECT);
     DexType javaLangSystemType = dexItemFactory.createType("Ljava/lang/System;");
     DexType javaIoPrintStreamType = dexItemFactory.createType("Ljava/io/PrintStream;");
 
@@ -1890,11 +1890,11 @@
         new StaticGet(MemberType.OBJECT, out,
             dexItemFactory.createField(javaLangSystemType, javaIoPrintStreamType, "out")));
 
-    Value value = code.createValue(MoveType.OBJECT);
+    Value value = code.createValue(ValueType.OBJECT);
     iterator.add(new ConstString(value, dexItemFactory.createString("INVOKE ")));
     iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
 
-    value = code.createValue(MoveType.OBJECT);
+    value = code.createValue(ValueType.OBJECT);
     iterator.add(
         new ConstString(value, dexItemFactory.createString(method.method.qualifiedName())));
     iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
@@ -1920,7 +1920,7 @@
       eol.link(successor);
 
       Value argument = arguments.get(i);
-      if (argument.outType() != MoveType.OBJECT) {
+      if (argument.outType() != ValueType.OBJECT) {
         iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, primitive)));
       } else {
         // Insert "if (argument != null) ...".
@@ -1948,7 +1948,7 @@
         iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, nul)));
         iterator = isNotNullBlock.listIterator();
         iterator.setInsertionPosition(position);
-        value = code.createValue(MoveType.OBJECT);
+        value = code.createValue(ValueType.OBJECT);
         iterator.add(new InvokeVirtual(dexItemFactory.objectMethods.getClass, value,
             ImmutableList.of(arguments.get(i))));
         iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index d71febe..bad56c1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -13,16 +13,15 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardMemberRule;
 
@@ -72,19 +71,18 @@
       ProguardMemberRule rule, IRCode code, Instruction instruction) {
     // Check if this value can be assumed constant.
     Instruction replacement = null;
-    MoveType moveType = instruction.outValue().outType();
+    ValueType valueType = instruction.outValue().outType();
     if (rule != null && rule.hasReturnValue() && rule.getReturnValue().isSingleValue()) {
-      assert moveType != MoveType.OBJECT;
-      Value value = code.createValue(moveType, instruction.getLocalInfo());
-      replacement = new ConstNumber(
-          ConstType.fromMoveType(moveType), value, rule.getReturnValue().getSingleValue());
+      assert valueType != ValueType.OBJECT;
+      Value value = code.createValue(valueType, instruction.getLocalInfo());
+      replacement = new ConstNumber(valueType, value, rule.getReturnValue().getSingleValue());
     }
     if (replacement == null &&
         rule != null && rule.hasReturnValue() && rule.getReturnValue().isField()) {
       DexField field = rule.getReturnValue().getField();
       DexEncodedField staticField = appInfo.lookupStaticTarget(field.clazz, field);
       if (staticField != null) {
-        Value value = code.createValue(moveType, instruction.getLocalInfo());
+        Value value = code.createValue(valueType, instruction.getLocalInfo());
         replacement = staticField.staticValue.asConstInstruction(false, value);
       } else {
         throw new CompilationError(field.clazz.toSourceString() + "." + field.name.toString() +
@@ -165,15 +163,10 @@
             }
             if (target.getOptimizationInfo().returnsConstant()) {
               long constant = target.getOptimizationInfo().getReturnedConstant();
-              MoveType moveType = invoke.outType();
-              if (moveType == MoveType.OBJECT) {
-                assert constant == 0;
-                moveType = MoveType.SINGLE;
-              }
-              Value value = code.createValue(moveType);
+              ValueType valueType = invoke.outType();
+              Value value = code.createValue(valueType);
               // TODO(ager): Attempt to get a more precise const type from the method analysis?
-              Instruction knownConstReturn =
-                  new ConstNumber(ConstType.fromMoveType(moveType), value, constant);
+              Instruction knownConstReturn = new ConstNumber(valueType, value, constant);
               invoke.outValue().replaceUsers(value);
               knownConstReturn.setPosition(invoke.getPosition());
               iterator.add(knownConstReturn);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MoveEliminator.java b/src/main/java/com/android/tools/r8/ir/optimize/MoveEliminator.java
index a228b20..dd7767a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MoveEliminator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MoveEliminator.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.Move;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import java.util.HashSet;
@@ -35,7 +34,7 @@
           return true;
         }
         if (activeMoveDstRegister == moveSrcRegister && activeMoveSrcRegister == moveDstRegister) {
-          if (move.outType() != MoveType.WIDE) {
+          if (!move.outType().isWide()) {
             return true;
           }
           // If the move is wide make sure the register pair is non-overlapping.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index d799e7d..67e58cb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -37,13 +37,13 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Mul;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Rem;
 import com.android.tools.r8.ir.code.Sub;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -863,8 +863,8 @@
     public void buildPrelude(IRBuilder builder) {
       // Fill in the Argument instructions in the argument block.
       for (int i = 0; i < outline.arguments.size(); i++) {
-        MoveType moveType = outline.arguments.get(i).outType();
-        builder.addNonThisArgument(i, moveType);
+        ValueType valueType = outline.arguments.get(i).outType();
+        builder.addNonThisArgument(i, valueType);
       }
     }
 
@@ -879,7 +879,7 @@
         if (outline.returnType == dexItemFactory.voidType) {
           builder.addReturn();
         } else {
-          builder.addReturn(MoveType.fromDexType(outline.returnType), outline.argumentCount());
+          builder.addReturn(ValueType.fromDexType(outline.returnType), outline.argumentCount());
         }
         return;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index 39f622c..8f6ae85 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
 import com.android.tools.r8.ir.regalloc.LiveIntervals;
@@ -294,7 +293,7 @@
               // Insert the current constant in the mapping. Make sure to clobber the second
               // register if wide.
               registerToNumber.put(outRegister, current.asConstNumber());
-              if (current.outType() == MoveType.WIDE) {
+              if (current.outType().isWide()) {
                 registerToNumber.remove(outRegister + 1);
               }
             }
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 45edc8a..523d6db 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
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.regalloc;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.ir.code.Add;
@@ -16,12 +17,12 @@
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.Move;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Or;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Sub;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.code.Xor;
 import com.android.tools.r8.ir.regalloc.RegisterPositions.Type;
 import com.android.tools.r8.logging.Log;
@@ -1970,7 +1971,7 @@
     code.blocks.forEach(BasicBlock::clearUserInfo);
   }
 
-  private Value createValue(MoveType type) {
+  private Value createValue(ValueType type) {
     Value value = code.createValue(type, null);
     value.setNeedsRegister(true);
     return value;
@@ -2035,7 +2036,7 @@
   }
 
   private Value createSentinelRegisterValue() {
-    return createValue(MoveType.OBJECT);
+    return createValue(ValueType.OBJECT);
   }
 
   private LiveIntervals createSentinelLiveInterval(Value sentinelValue) {
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 3c2210d..4745a81 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -6,8 +6,8 @@
 import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
 import static com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator.NO_REGISTER;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.utils.CfgPrinter;
 import java.util.ArrayList;
@@ -18,6 +18,7 @@
 public class LiveIntervals implements Comparable<LiveIntervals> {
 
   private final Value value;
+  private final MoveType type;
   private LiveIntervals nextConsecutive;
   private LiveIntervals previousConsecutive;
   private LiveIntervals splitParent;
@@ -40,6 +41,7 @@
 
   LiveIntervals(Value value) {
     this.value = value;
+    this.type = MoveType.fromValueType(value.outType());
     usedInMonitorOperations = value.usedInMonitorOperation();
     splitParent = this;
     value.setLiveIntervals(this);
@@ -48,6 +50,7 @@
   LiveIntervals(LiveIntervals splitParent) {
     this.splitParent = splitParent;
     value = splitParent.value;
+    type = splitParent.type;
     usedInMonitorOperations = splitParent.usedInMonitorOperations;
   }
 
@@ -60,7 +63,7 @@
   }
 
   public MoveType getType() {
-    return value.outType();
+    return type;
   }
 
   public Value getValue() {
@@ -68,7 +71,7 @@
   }
 
   public int requiredRegisters() {
-    return getType() == MoveType.WIDE ? 2 : 1;
+    return type == MoveType.WIDE ? 2 : 1;
   }
 
   public void setHint(LiveIntervals intervals) {
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
index 313497c..dd857fc 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.regalloc;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.MoveType;
 import java.util.Map;
 import java.util.Set;
 
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
index 5d7606d..49b46dd 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
@@ -3,12 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.regalloc;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.FixedRegisterValue;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Move;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
index c13d23e..70354fe 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.ir.regalloc;
 
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.code.MoveType;
 
 /**
  * A SpillMove represents either a phi move that transfers an SSA value to the SSA phi value or
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index 9154eff..e466904 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -4,11 +4,11 @@
 
 package com.android.tools.r8.ir.regalloc;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Position;
 import java.util.Collection;
 import java.util.HashMap;
@@ -172,10 +172,10 @@
 
   private SpillMove getMoveWritingSourceRegister(SpillMove inMove, Collection<SpillMove> moves) {
     int srcRegister = inMove.from.getRegister();
-    int srcRegisters = inMove.type == MoveType.WIDE ? 2 : 1;
+    int srcRegisters = inMove.type.requiredRegisters();
     for (SpillMove move : moves) {
       int dstRegister = move.to.getRegister();
-      int dstRegisters = move.type == MoveType.WIDE ? 2 : 1;
+      int dstRegisters = move.type.requiredRegisters();
       for (int s = 0; s < srcRegisters; s++) {
         for (int d = 0; d < dstRegisters; d++) {
           if ((dstRegister + d) == (srcRegister + s)) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index bcc9462..43e55ac 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.google.common.collect.Lists;
 import java.util.ArrayList;
@@ -74,32 +74,32 @@
   @Override
   protected void prepareInstructions() {
     // Prepare call arguments.
-    List<MoveType> argMoveTypes = new ArrayList<>();
+    List<ValueType> argValueTypes = new ArrayList<>();
     List<Integer> argRegisters = new ArrayList<>();
 
     if (receiver != null) {
-      argMoveTypes.add(MoveType.OBJECT);
+      argValueTypes.add(ValueType.OBJECT);
       argRegisters.add(getReceiverRegister());
     }
 
     DexType[] accessorParams = proto.parameters.values;
     for (int i = 0; i < accessorParams.length; i++) {
-      argMoveTypes.add(MoveType.fromDexType(accessorParams[i]));
+      argValueTypes.add(ValueType.fromDexType(accessorParams[i]));
       argRegisters.add(getParamRegister(i));
     }
 
     // Method call to the target method.
     add(builder -> builder.addInvoke(this.invokeType,
-        this.target, this.target.proto, argMoveTypes, argRegisters));
+        this.target, this.target.proto, argValueTypes, argRegisters));
 
     // Does the method return value?
     if (proto.returnType.isVoidType()) {
       add(IRBuilder::addReturn);
     } else {
-      MoveType moveType = MoveType.fromDexType(proto.returnType);
-      int tempValue = nextRegister(moveType);
-      add(builder -> builder.addMoveResult(moveType, tempValue));
-      add(builder -> builder.addReturn(moveType, tempValue));
+      ValueType valueType = ValueType.fromDexType(proto.returnType);
+      int tempValue = nextRegister(valueType);
+      add(builder -> builder.addMoveResult(valueType, tempValue));
+      add(builder -> builder.addReturn(valueType, tempValue));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
index 637cbac..ed4a207 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -13,9 +13,9 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.CatchHandlers;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.utils.ThrowingConsumer;
@@ -48,14 +48,14 @@
     this.proto = proto;
 
     // Initialize register values for receiver and arguments
-    this.receiverRegister = receiver != null ? nextRegister(MoveType.OBJECT) : -1;
+    this.receiverRegister = receiver != null ? nextRegister(ValueType.OBJECT) : -1;
 
     DexType[] params = proto.parameters.values;
     int paramCount = params.length;
     this.paramRegisters = new int[paramCount];
     this.paramValues = new Value[paramCount];
     for (int i = 0; i < paramCount; i++) {
-      this.paramRegisters[i] = nextRegister(MoveType.fromDexType(params[i]));
+      this.paramRegisters[i] = nextRegister(ValueType.fromDexType(params[i]));
     }
   }
 
@@ -63,9 +63,9 @@
     constructors.add(constructor);
   }
 
-  protected final int nextRegister(MoveType type) {
+  protected final int nextRegister(ValueType type) {
     int value = nextRegister;
-    nextRegister += type == MoveType.WIDE ? 2 : 1;
+    nextRegister += type.requiredRegisters();
     return value;
   }
 
@@ -147,7 +147,7 @@
   @Override
   public final void buildPrelude(IRBuilder builder) {
     if (receiver != null) {
-      receiverValue = builder.writeRegister(receiverRegister, MoveType.OBJECT, NO_THROW);
+      receiverValue = builder.writeRegister(receiverRegister, ValueType.OBJECT, NO_THROW);
       builder.add(new Argument(receiverValue));
       receiverValue.markAsThis();
     }
@@ -155,8 +155,8 @@
     // Fill in the Argument instructions in the argument block.
     DexType[] parameters = proto.parameters.values;
     for (int i = 0; i < parameters.length; i++) {
-      MoveType moveType = MoveType.fromDexType(parameters[i]);
-      Value paramValue = builder.writeRegister(paramRegisters[i], moveType, NO_THROW);
+      ValueType valueType = ValueType.fromDexType(parameters[i]);
+      Value paramValue = builder.writeRegister(paramRegisters[i], valueType, NO_THROW);
       paramValues[i] = paramValue;
       builder.add(new Argument(paramValue));
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
index ced15f5..df3801b 100644
--- a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
@@ -24,9 +24,9 @@
 import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Switch;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.optimize.SwitchUtils;
 import com.android.tools.r8.ir.optimize.SwitchUtils.EnumSwitchInfo;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
@@ -471,9 +471,9 @@
               if (appInfo.withLiveness().liveFields.contains(field)) {
                 // Effectively inline the code that is normally inside these methods.
                 Value thisReference = invokeMethod.getReceiver();
-                Value newResult = code.createValue(MoveType.SINGLE);
+                Value newResult = code.createValue(ValueType.INT);
                 invokeMethod.outValue().replaceUsers(newResult);
-                Value theList = code.createValue(MoveType.OBJECT);
+                Value theList = code.createValue(ValueType.OBJECT);
                 it.replaceCurrentInstruction(
                     new InstanceGet(MemberType.OBJECT, theList, thisReference, field));
                 it.add(new InvokeInterface(sizeMethod, newResult, Collections.emptyList()));
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
index 9192b2f..0b7dafb 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -13,15 +13,14 @@
 import com.android.tools.r8.ir.code.Add;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.ConstType;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.smali.SmaliTestBase;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableList;
@@ -364,11 +363,11 @@
       BasicBlock newReturnBlock = iterator.split(code);
       // Modify the code to make the inserted block add the constant 10 to the original return
       // value.
-      Value newConstValue = new Value(test.valueNumberGenerator.next(), MoveType.SINGLE, null);
-      Value newReturnValue = new Value(test.valueNumberGenerator.next(), MoveType.SINGLE, null);
+      Value newConstValue = new Value(test.valueNumberGenerator.next(), ValueType.INT, null);
+      Value newReturnValue = new Value(test.valueNumberGenerator.next(), ValueType.INT, null);
       Value oldReturnValue = newReturnBlock.listIterator().next().asReturn().returnValue();
       newReturnBlock.listIterator().next().asReturn().returnValue().replaceUsers(newReturnValue);
-      Instruction constInstruction = new ConstNumber(ConstType.INT, newConstValue, 10);
+      Instruction constInstruction = new ConstNumber(ValueType.INT, newConstValue, 10);
       Instruction addInstruction =
           new Add(NumericType.INT, newReturnValue, oldReturnValue, newConstValue);
       iterator.previous();
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
index 6969c2d..726d6b1 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
@@ -8,11 +8,10 @@
 
 import com.android.tools.r8.ir.code.Add;
 import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.ConstType;
-import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
 import org.junit.Test;
 
 public class IdenticalAfterRegisterAllocationTest {
@@ -47,13 +46,13 @@
   @Test
   public void equalityOfConstantOperands() {
     RegisterAllocator allocator = new MockRegisterAllocator();
-    Value value0 = new Value(0, MoveType.SINGLE, null);
-    ConstNumber const0 = new ConstNumber(ConstType.INT, value0, 0);
-    Value value1 = new Value(1, MoveType.SINGLE, null);
-    ConstNumber const1 = new ConstNumber(ConstType.INT, value1, 1);
-    Value value2 = new Value(2, MoveType.SINGLE, null);
-    ConstNumber const2 = new ConstNumber(ConstType.INT, value2, 2);
-    Value value3 = new Value(2, MoveType.SINGLE, null);
+    Value value0 = new Value(0, ValueType.INT, null);
+    ConstNumber const0 = new ConstNumber(ValueType.INT, value0, 0);
+    Value value1 = new Value(1, ValueType.INT, null);
+    ConstNumber const1 = new ConstNumber(ValueType.INT, value1, 1);
+    Value value2 = new Value(2, ValueType.INT, null);
+    ConstNumber const2 = new ConstNumber(ValueType.INT, value2, 2);
+    Value value3 = new Value(2, ValueType.INT, null);
     Add add0 = new Add(NumericType.INT, value3, value0, value1);
     add0.setPosition(Position.none());
     Add add1 = new Add(NumericType.INT, value3, value0, value2);
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index a1046db..140aef5 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -5,6 +5,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.code.MoveType;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -12,7 +13,7 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Move;
-import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.ValueType;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -124,9 +125,9 @@
     Move tempMove = moves.get(0);
     Move firstMove = moves.get(1);
     Move secondMove = moves.get(2);
-    assertEquals(MoveType.SINGLE, tempMove.outType());
-    assertEquals(MoveType.SINGLE, firstMove.outType());
-    assertEquals(MoveType.SINGLE, secondMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, tempMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, firstMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, secondMove.outType());
     assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(
         tempMove.src().asFixedRegisterValue().getRegister(),
@@ -149,9 +150,9 @@
     Move tempMove = moves.get(0);
     Move firstMove = moves.get(1);
     Move secondMove = moves.get(2);
-    assertEquals(MoveType.WIDE, tempMove.outType());
-    assertEquals(MoveType.WIDE, firstMove.outType());
-    assertEquals(MoveType.WIDE, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, tempMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, firstMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, secondMove.outType());
     assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(
         tempMove.src().asFixedRegisterValue().getRegister(),
@@ -174,9 +175,9 @@
     Move tempMove = moves.get(0).asMove();
     Move firstMove = moves.get(1).asMove();
     Move secondMove = moves.get(2).asMove();
-    assertEquals(MoveType.WIDE, tempMove.outType());
-    assertEquals(MoveType.SINGLE, firstMove.outType());
-    assertEquals(MoveType.WIDE, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, tempMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, firstMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, secondMove.outType());
     assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(
         tempMove.src().asFixedRegisterValue().getRegister(),
@@ -199,9 +200,9 @@
     Move tempMove = moves.get(0).asMove();
     Move firstMove = moves.get(1).asMove();
     Move secondMove = moves.get(2).asMove();
-    assertEquals(MoveType.WIDE, tempMove.outType());
-    assertEquals(MoveType.SINGLE, firstMove.outType());
-    assertEquals(MoveType.WIDE, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, tempMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, firstMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, secondMove.outType());
     assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(
         tempMove.src().asFixedRegisterValue().getRegister(),
@@ -223,8 +224,8 @@
     assertEquals(2, moves.size());
     Move firstMove = moves.get(0).asMove();
     Move secondMove = moves.get(1).asMove();
-    assertEquals(MoveType.WIDE, firstMove.outType());
-    assertEquals(MoveType.WIDE, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, firstMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, secondMove.outType());
     assertEquals(0, firstMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(1, firstMove.src().asFixedRegisterValue().getRegister());
     assertEquals(2, secondMove.dest().asFixedRegisterValue().getRegister());
@@ -243,9 +244,9 @@
     Move firstMove = moves.get(0).asMove();
     Move secondMove = moves.get(1).asMove();
     Move thirdMove = moves.get(2).asMove();
-    assertEquals(MoveType.WIDE, firstMove.outType());
-    assertEquals(MoveType.WIDE, secondMove.outType());
-    assertEquals(MoveType.WIDE, thirdMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, firstMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, thirdMove.outType());
     assertEquals(42, firstMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(1, firstMove.src().asFixedRegisterValue().getRegister());
     assertEquals(0, secondMove.dest().asFixedRegisterValue().getRegister());
@@ -268,10 +269,10 @@
     Move secondMove = moves.get(1).asMove();
     Move thirdMove = moves.get(2).asMove();
     Move fourthMove = moves.get(3).asMove();
-    assertEquals(MoveType.WIDE, firstMove.outType());
-    assertEquals(MoveType.SINGLE, secondMove.outType());
-    assertEquals(MoveType.SINGLE, thirdMove.outType());
-    assertEquals(MoveType.WIDE, fourthMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, firstMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, secondMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, thirdMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, fourthMove.outType());
     assertEquals(temp, firstMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(0, secondMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(1, thirdMove.dest().asFixedRegisterValue().getRegister());
@@ -290,9 +291,9 @@
     Move firstMove = moves.get(0).asMove();
     Move secondMove = moves.get(1).asMove();
     Move thirdMove = moves.get(2).asMove();
-    assertEquals(MoveType.WIDE, firstMove.outType());
-    assertEquals(MoveType.SINGLE, secondMove.outType());
-    assertEquals(MoveType.WIDE, thirdMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, firstMove.outType());
+    assertEquals(ValueType.INT_OR_FLOAT, secondMove.outType());
+    assertEquals(ValueType.LONG_OR_DOUBLE, thirdMove.outType());
     assertEquals(temp, firstMove.dest().asFixedRegisterValue().getRegister());
     assertEquals(2, firstMove.src().asFixedRegisterValue().getRegister());
     assertEquals(3, secondMove.dest().asFixedRegisterValue().getRegister());