Merge "Enables GVN for MIPS32 and MIPS64."
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 1475679..b1bef79 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -54,6 +54,7 @@
         "optimizing/code_sinking.cc",
         "optimizing/constant_folding.cc",
         "optimizing/constructor_fence_redundancy_elimination.cc",
+        "optimizing/data_type.cc",
         "optimizing/dead_code_elimination.cc",
         "optimizing/escape.cc",
         "optimizing/graph_checker.cc",
@@ -204,10 +205,10 @@
     cmd: "$(location generate-operator-out.py) art/compiler $(in) > $(out)",
     tool_files: ["generate-operator-out.py"],
     srcs: [
-        "compiled_method.h",
         "dex/dex_to_dex_compiler.h",
         "driver/compiler_driver.h",
         "driver/compiler_options.h",
+        "linker/linker_patch.h",
         "optimizing/locations.h",
 
         "utils/arm/constants_arm.h",
@@ -310,16 +311,18 @@
         "art_gtest_defaults",
     ],
     srcs: [
-        "compiled_method_test.cc",
         "debug/dwarf/dwarf_test.cc",
+        "debug/src_map_elem_test.cc",
         "dex/dex_to_dex_decompiler_test.cc",
         "driver/compiled_method_storage_test.cc",
         "driver/compiler_driver_test.cc",
         "exception_test.cc",
         "jni/jni_compiler_test.cc",
+        "linker/linker_patch_test.cc",
         "linker/method_bss_mapping_encoder_test.cc",
         "linker/output_stream_test.cc",
         "optimizing/bounds_check_elimination_test.cc",
+        "optimizing/data_type_test.cc",
         "optimizing/dominator_test.cc",
         "optimizing/find_loops_test.cc",
         "optimizing/graph_checker_test.cc",
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 0d38620..500fc4a 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -22,7 +22,7 @@
 #include "base/callee_save_type.h"
 #include "base/enums.h"
 #include "class_linker.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
diff --git a/compiler/compiled_method-inl.h b/compiler/compiled_method-inl.h
new file mode 100644
index 0000000..c432747
--- /dev/null
+++ b/compiler/compiled_method-inl.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_COMPILED_METHOD_INL_H_
+#define ART_COMPILER_COMPILED_METHOD_INL_H_
+
+#include "compiled_method.h"
+
+#include "base/array_ref.h"
+#include "base/length_prefixed_array.h"
+#include "linker/linker_patch.h"
+
+namespace art {
+
+inline ArrayRef<const uint8_t> CompiledCode::GetQuickCode() const {
+  return GetArray(quick_code_);
+}
+
+template <typename T>
+inline ArrayRef<const T> CompiledCode::GetArray(const LengthPrefixedArray<T>* array) {
+  if (array == nullptr) {
+    return ArrayRef<const T>();
+  }
+  DCHECK_NE(array->size(), 0u);
+  return ArrayRef<const T>(&array->At(0), array->size());
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetMethodInfo() const {
+  return GetArray(method_info_);
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetVmapTable() const {
+  return GetArray(vmap_table_);
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetCFIInfo() const {
+  return GetArray(cfi_info_);
+}
+
+inline ArrayRef<const linker::LinkerPatch> CompiledMethod::GetPatches() const {
+  return GetArray(patches_);
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILED_METHOD_INL_H_
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 0d9021f..111469f 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -22,7 +22,8 @@
 
 namespace art {
 
-CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
+CompiledCode::CompiledCode(CompilerDriver* compiler_driver,
+                           InstructionSet instruction_set,
                            const ArrayRef<const uint8_t>& quick_code)
     : compiler_driver_(compiler_driver),
       instruction_set_(instruction_set),
@@ -77,8 +78,7 @@
   }
 }
 
-const void* CompiledCode::CodePointer(const void* code_pointer,
-                                      InstructionSet instruction_set) {
+const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet instruction_set) {
   switch (instruction_set) {
     case kArm:
     case kArm64:
@@ -108,7 +108,7 @@
                                const ArrayRef<const uint8_t>& method_info,
                                const ArrayRef<const uint8_t>& vmap_table,
                                const ArrayRef<const uint8_t>& cfi_info,
-                               const ArrayRef<const LinkerPatch>& patches)
+                               const ArrayRef<const linker::LinkerPatch>& patches)
     : CompiledCode(driver, instruction_set, quick_code),
       frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask),
@@ -129,7 +129,7 @@
     const ArrayRef<const uint8_t>& method_info,
     const ArrayRef<const uint8_t>& vmap_table,
     const ArrayRef<const uint8_t>& cfi_info,
-    const ArrayRef<const LinkerPatch>& patches) {
+    const ArrayRef<const linker::LinkerPatch>& patches) {
   SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
   CompiledMethod* ret = alloc.allocate(1);
   alloc.construct(ret,
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 5ef6cbf..892bc59 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -17,27 +17,28 @@
 #ifndef ART_COMPILER_COMPILED_METHOD_H_
 #define ART_COMPILER_COMPILED_METHOD_H_
 
-#include <iosfwd>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include "arch/instruction_set.h"
-#include "base/array_ref.h"
-#include "base/bit_utils.h"
-#include "base/length_prefixed_array.h"
-#include "dex_file_types.h"
-#include "method_reference.h"
 
 namespace art {
 
+template <typename T> class ArrayRef;
 class CompilerDriver;
 class CompiledMethodStorage;
+template<typename T> class LengthPrefixedArray;
+
+namespace linker {
+class LinkerPatch;
+}  // namespace linker
 
 class CompiledCode {
  public:
   // For Quick to supply an code blob
-  CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
+  CompiledCode(CompilerDriver* compiler_driver,
+               InstructionSet instruction_set,
                const ArrayRef<const uint8_t>& quick_code);
 
   virtual ~CompiledCode();
@@ -46,9 +47,7 @@
     return instruction_set_;
   }
 
-  ArrayRef<const uint8_t> GetQuickCode() const {
-    return GetArray(quick_code_);
-  }
+  ArrayRef<const uint8_t> GetQuickCode() const;
 
   bool operator==(const CompiledCode& rhs) const;
 
@@ -66,18 +65,11 @@
   // Returns a pointer suitable for invoking the code at the argument
   // code_pointer address.  Mainly to cope with kThumb2 where the
   // lower bit must be set to indicate Thumb mode.
-  static const void* CodePointer(const void* code_pointer,
-                                 InstructionSet instruction_set);
+  static const void* CodePointer(const void* code_pointer, InstructionSet instruction_set);
 
  protected:
   template <typename T>
-  static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array) {
-    if (array == nullptr) {
-      return ArrayRef<const T>();
-    }
-    DCHECK_NE(array->size(), 0u);
-    return ArrayRef<const T>(&array->At(0), array->size());
-  }
+  static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array);
 
   CompilerDriver* GetCompilerDriver() {
     return compiler_driver_;
@@ -92,298 +84,6 @@
   const LengthPrefixedArray<uint8_t>* const quick_code_;
 };
 
-class SrcMapElem {
- public:
-  uint32_t from_;
-  int32_t to_;
-};
-
-inline bool operator<(const SrcMapElem& lhs, const SrcMapElem& rhs) {
-  if (lhs.from_ != rhs.from_) {
-    return lhs.from_ < rhs.from_;
-  }
-  return lhs.to_ < rhs.to_;
-}
-
-inline bool operator==(const SrcMapElem& lhs, const SrcMapElem& rhs) {
-  return lhs.from_ == rhs.from_ && lhs.to_ == rhs.to_;
-}
-
-class LinkerPatch {
- public:
-  // Note: We explicitly specify the underlying type of the enum because GCC
-  // would otherwise select a bigger underlying type and then complain that
-  //     'art::LinkerPatch::patch_type_' is too small to hold all
-  //     values of 'enum class art::LinkerPatch::Type'
-  // which is ridiculous given we have only a handful of values here. If we
-  // choose to squeeze the Type into fewer than 8 bits, we'll have to declare
-  // patch_type_ as an uintN_t and do explicit static_cast<>s.
-  enum class Type : uint8_t {
-    kMethodRelative,          // NOTE: Actual patching is instruction_set-dependent.
-    kMethodBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
-    kCall,
-    kCallRelative,            // NOTE: Actual patching is instruction_set-dependent.
-    kTypeRelative,            // NOTE: Actual patching is instruction_set-dependent.
-    kTypeClassTable,          // NOTE: Actual patching is instruction_set-dependent.
-    kTypeBssEntry,            // NOTE: Actual patching is instruction_set-dependent.
-    kStringRelative,          // NOTE: Actual patching is instruction_set-dependent.
-    kStringInternTable,       // NOTE: Actual patching is instruction_set-dependent.
-    kStringBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
-    kBakerReadBarrierBranch,  // NOTE: Actual patching is instruction_set-dependent.
-  };
-
-  static LinkerPatch RelativeMethodPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kMethodRelative, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch MethodBssEntryPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch CodePatch(size_t literal_offset,
-                               const DexFile* target_dex_file,
-                               uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kCall, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    return patch;
-  }
-
-  static LinkerPatch RelativeCodePatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kCallRelative, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    return patch;
-  }
-
-  static LinkerPatch RelativeTypePatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t pc_insn_offset,
-                                       uint32_t target_type_idx) {
-    LinkerPatch patch(literal_offset, Type::kTypeRelative, target_dex_file);
-    patch.type_idx_ = target_type_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch TypeClassTablePatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_type_idx) {
-    LinkerPatch patch(literal_offset, Type::kTypeClassTable, target_dex_file);
-    patch.type_idx_ = target_type_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch TypeBssEntryPatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t pc_insn_offset,
-                                       uint32_t target_type_idx) {
-    LinkerPatch patch(literal_offset, Type::kTypeBssEntry, target_dex_file);
-    patch.type_idx_ = target_type_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch RelativeStringPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_string_idx) {
-    LinkerPatch patch(literal_offset, Type::kStringRelative, target_dex_file);
-    patch.string_idx_ = target_string_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch StringInternTablePatch(size_t literal_offset,
-                                            const DexFile* target_dex_file,
-                                            uint32_t pc_insn_offset,
-                                            uint32_t target_string_idx) {
-    LinkerPatch patch(literal_offset, Type::kStringInternTable, target_dex_file);
-    patch.string_idx_ = target_string_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch StringBssEntryPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_string_idx) {
-    LinkerPatch patch(literal_offset, Type::kStringBssEntry, target_dex_file);
-    patch.string_idx_ = target_string_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
-                                                 uint32_t custom_value1 = 0u,
-                                                 uint32_t custom_value2 = 0u) {
-    LinkerPatch patch(literal_offset, Type::kBakerReadBarrierBranch, nullptr);
-    patch.baker_custom_value1_ = custom_value1;
-    patch.baker_custom_value2_ = custom_value2;
-    return patch;
-  }
-
-  LinkerPatch(const LinkerPatch& other) = default;
-  LinkerPatch& operator=(const LinkerPatch& other) = default;
-
-  size_t LiteralOffset() const {
-    return literal_offset_;
-  }
-
-  Type GetType() const {
-    return patch_type_;
-  }
-
-  bool IsPcRelative() const {
-    switch (GetType()) {
-      case Type::kMethodRelative:
-      case Type::kMethodBssEntry:
-      case Type::kCallRelative:
-      case Type::kTypeRelative:
-      case Type::kTypeClassTable:
-      case Type::kTypeBssEntry:
-      case Type::kStringRelative:
-      case Type::kStringInternTable:
-      case Type::kStringBssEntry:
-      case Type::kBakerReadBarrierBranch:
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  MethodReference TargetMethod() const {
-    DCHECK(patch_type_ == Type::kMethodRelative ||
-           patch_type_ == Type::kMethodBssEntry ||
-           patch_type_ == Type::kCall ||
-           patch_type_ == Type::kCallRelative);
-    return MethodReference(target_dex_file_, method_idx_);
-  }
-
-  const DexFile* TargetTypeDexFile() const {
-    DCHECK(patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeClassTable ||
-           patch_type_ == Type::kTypeBssEntry);
-    return target_dex_file_;
-  }
-
-  dex::TypeIndex TargetTypeIndex() const {
-    DCHECK(patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeClassTable ||
-           patch_type_ == Type::kTypeBssEntry);
-    return dex::TypeIndex(type_idx_);
-  }
-
-  const DexFile* TargetStringDexFile() const {
-    DCHECK(patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringInternTable ||
-           patch_type_ == Type::kStringBssEntry);
-    return target_dex_file_;
-  }
-
-  dex::StringIndex TargetStringIndex() const {
-    DCHECK(patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringInternTable ||
-           patch_type_ == Type::kStringBssEntry);
-    return dex::StringIndex(string_idx_);
-  }
-
-  uint32_t PcInsnOffset() const {
-    DCHECK(patch_type_ == Type::kMethodRelative ||
-           patch_type_ == Type::kMethodBssEntry ||
-           patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeClassTable ||
-           patch_type_ == Type::kTypeBssEntry ||
-           patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringInternTable ||
-           patch_type_ == Type::kStringBssEntry);
-    return pc_insn_offset_;
-  }
-
-  uint32_t GetBakerCustomValue1() const {
-    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
-    return baker_custom_value1_;
-  }
-
-  uint32_t GetBakerCustomValue2() const {
-    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
-    return baker_custom_value2_;
-  }
-
- private:
-  LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file)
-      : target_dex_file_(target_dex_file),
-        literal_offset_(literal_offset),
-        patch_type_(patch_type) {
-    cmp1_ = 0u;
-    cmp2_ = 0u;
-    // The compiler rejects methods that are too big, so the compiled code
-    // of a single method really shouln't be anywhere close to 16MiB.
-    DCHECK(IsUint<24>(literal_offset));
-  }
-
-  const DexFile* target_dex_file_;
-  // TODO: Clean up naming. Some patched locations are literals but others are not.
-  uint32_t literal_offset_ : 24;  // Method code size up to 16MiB.
-  Type patch_type_ : 8;
-  union {
-    uint32_t cmp1_;             // Used for relational operators.
-    uint32_t method_idx_;       // Method index for Call/Method patches.
-    uint32_t type_idx_;         // Type index for Type patches.
-    uint32_t string_idx_;       // String index for String patches.
-    uint32_t baker_custom_value1_;
-    static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
-  };
-  union {
-    // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
-    // This allows a hashing function to treat an array of linker patches as raw memory.
-    size_t cmp2_;             // Used for relational operators.
-    // Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
-    // may be different if the PC-relative addressing needs multiple insns).
-    uint32_t pc_insn_offset_;
-    uint32_t baker_custom_value2_;
-    static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
-    static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators");
-  };
-
-  friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
-  friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs);
-};
-std::ostream& operator<<(std::ostream& os, const LinkerPatch::Type& type);
-
-inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) {
-  return lhs.literal_offset_ == rhs.literal_offset_ &&
-      lhs.patch_type_ == rhs.patch_type_ &&
-      lhs.target_dex_file_ == rhs.target_dex_file_ &&
-      lhs.cmp1_ == rhs.cmp1_ &&
-      lhs.cmp2_ == rhs.cmp2_;
-}
-
-inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) {
-  return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_
-      : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_
-      : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_
-      : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_
-      : lhs.cmp2_ < rhs.cmp2_;
-}
-
 class CompiledMethod FINAL : public CompiledCode {
  public:
   // Constructs a CompiledMethod.
@@ -398,7 +98,7 @@
                  const ArrayRef<const uint8_t>& method_info,
                  const ArrayRef<const uint8_t>& vmap_table,
                  const ArrayRef<const uint8_t>& cfi_info,
-                 const ArrayRef<const LinkerPatch>& patches);
+                 const ArrayRef<const linker::LinkerPatch>& patches);
 
   virtual ~CompiledMethod();
 
@@ -412,7 +112,7 @@
       const ArrayRef<const uint8_t>& method_info,
       const ArrayRef<const uint8_t>& vmap_table,
       const ArrayRef<const uint8_t>& cfi_info,
-      const ArrayRef<const LinkerPatch>& patches);
+      const ArrayRef<const linker::LinkerPatch>& patches);
 
   static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m);
 
@@ -428,21 +128,13 @@
     return fp_spill_mask_;
   }
 
-  ArrayRef<const uint8_t> GetMethodInfo() const {
-    return GetArray(method_info_);
-  }
+  ArrayRef<const uint8_t> GetMethodInfo() const;
 
-  ArrayRef<const uint8_t> GetVmapTable() const {
-    return GetArray(vmap_table_);
-  }
+  ArrayRef<const uint8_t> GetVmapTable() const;
 
-  ArrayRef<const uint8_t> GetCFIInfo() const {
-    return GetArray(cfi_info_);
-  }
+  ArrayRef<const uint8_t> GetCFIInfo() const;
 
-  ArrayRef<const LinkerPatch> GetPatches() const {
-    return GetArray(patches_);
-  }
+  ArrayRef<const linker::LinkerPatch> GetPatches() const;
 
  private:
   // For quick code, the size of the activation used by the code.
@@ -458,7 +150,7 @@
   // For quick code, a FDE entry for the debug_frame section.
   const LengthPrefixedArray<uint8_t>* const cfi_info_;
   // For quick code, linker patches needed by the method.
-  const LengthPrefixedArray<LinkerPatch>* const patches_;
+  const LengthPrefixedArray<linker::LinkerPatch>* const patches_;
 };
 
 }  // namespace art
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index cf5d65e..49d52c4 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -20,10 +20,10 @@
 #include <unordered_set>
 #include <vector>
 
-#include "compiled_method.h"
 #include "debug/dwarf/debug_line_opcode_writer.h"
 #include "debug/dwarf/headers.h"
 #include "debug/elf_compilation_unit.h"
+#include "debug/src_map_elem.h"
 #include "dex_file-inl.h"
 #include "linker/elf_builder.h"
 #include "stack_map.h"
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
index 5678910..a8225fa 100644
--- a/compiler/debug/method_debug_info.h
+++ b/compiler/debug/method_debug_info.h
@@ -19,7 +19,8 @@
 
 #include <string>
 
-#include "compiled_method.h"
+#include "arch/instruction_set.h"
+#include "base/array_ref.h"
 #include "dex_file.h"
 
 namespace art {
diff --git a/compiler/debug/src_map_elem.h b/compiler/debug/src_map_elem.h
new file mode 100644
index 0000000..5286b8c
--- /dev/null
+++ b/compiler/debug/src_map_elem.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
+#define ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
+
+#include <stdint.h>
+
+namespace art {
+
+class SrcMapElem {
+ public:
+  uint32_t from_;
+  int32_t to_;
+};
+
+inline bool operator<(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  if (lhs.from_ != rhs.from_) {
+    return lhs.from_ < rhs.from_;
+  }
+  return lhs.to_ < rhs.to_;
+}
+
+inline bool operator==(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  return lhs.from_ == rhs.from_ && lhs.to_ == rhs.to_;
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
diff --git a/compiler/debug/src_map_elem_test.cc b/compiler/debug/src_map_elem_test.cc
new file mode 100644
index 0000000..ceaa53f
--- /dev/null
+++ b/compiler/debug/src_map_elem_test.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "src_map_elem.h"
+
+#include "base/macros.h"
+
+namespace art {
+namespace debug {
+
+TEST(SrcMapElem, Operators) {
+  SrcMapElem elems[] = {
+      { 1u, -1 },
+      { 1u, 0 },
+      { 1u, 1 },
+      { 2u, -1 },
+      { 2u, 0 },    // Index 4.
+      { 2u, 1 },
+      { 2u, 0u },   // Index 6: Arbitrarily add identical SrcMapElem with index 4.
+  };
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) == (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] == elems[j]) << i << " " << j;
+    }
+  }
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) < (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] < elems[j]) << i << " " << j;
+    }
+  }
+}
+
+}  // namespace debug
+}  // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 9d57b96..e49f83f 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -395,7 +395,7 @@
         ArrayRef<const uint8_t>(),                   // method_info
         ArrayRef<const uint8_t>(quicken_data),       // vmap_table
         ArrayRef<const uint8_t>(),                   // cfi data
-        ArrayRef<const LinkerPatch>());
+        ArrayRef<const linker::LinkerPatch>());
   }
   return nullptr;
 }
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index e36d416..6637be2 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -18,7 +18,7 @@
 
 #include "class_linker.h"
 #include "common_compiler_test.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler_callbacks.h"
 #include "dex_file.h"
 #include "driver/compiler_driver.h"
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index 528b0a2..c739333 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -21,6 +21,7 @@
 
 #include "base/logging.h"
 #include "compiled_method.h"
+#include "linker/linker_patch.h"
 #include "thread-current-inl.h"
 #include "utils.h"
 #include "utils/dedupe_set-inl.h"
@@ -178,7 +179,7 @@
                          LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
       dedupe_cfi_info_("dedupe cfi info", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
       dedupe_linker_patches_("dedupe cfi info",
-                             LengthPrefixedArrayAlloc<LinkerPatch>(swap_space_.get())) {
+                             LengthPrefixedArrayAlloc<linker::LinkerPatch>(swap_space_.get())) {
 }
 
 CompiledMethodStorage::~CompiledMethodStorage() {
@@ -234,13 +235,13 @@
   ReleaseArrayIfNotDeduplicated(cfi_info);
 }
 
-const LengthPrefixedArray<LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
-    const ArrayRef<const LinkerPatch>& linker_patches) {
+const LengthPrefixedArray<linker::LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
+    const ArrayRef<const linker::LinkerPatch>& linker_patches) {
   return AllocateOrDeduplicateArray(linker_patches, &dedupe_linker_patches_);
 }
 
 void CompiledMethodStorage::ReleaseLinkerPatches(
-    const LengthPrefixedArray<LinkerPatch>* linker_patches) {
+    const LengthPrefixedArray<linker::LinkerPatch>* linker_patches) {
   ReleaseArrayIfNotDeduplicated(linker_patches);
 }
 
diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h
index 27011e8..249f06c 100644
--- a/compiler/driver/compiled_method_storage.h
+++ b/compiler/driver/compiled_method_storage.h
@@ -28,7 +28,9 @@
 
 namespace art {
 
+namespace linker {
 class LinkerPatch;
+}  // namespace linker
 
 class CompiledMethodStorage {
  public:
@@ -61,9 +63,9 @@
   const LengthPrefixedArray<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
   void ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info);
 
-  const LengthPrefixedArray<LinkerPatch>* DeduplicateLinkerPatches(
-      const ArrayRef<const LinkerPatch>& linker_patches);
-  void ReleaseLinkerPatches(const LengthPrefixedArray<LinkerPatch>* linker_patches);
+  const LengthPrefixedArray<linker::LinkerPatch>* DeduplicateLinkerPatches(
+      const ArrayRef<const linker::LinkerPatch>& linker_patches);
+  void ReleaseLinkerPatches(const LengthPrefixedArray<linker::LinkerPatch>* linker_patches);
 
  private:
   template <typename T, typename DedupeSetType>
@@ -98,7 +100,7 @@
   ArrayDedupeSet<uint8_t> dedupe_method_info_;
   ArrayDedupeSet<uint8_t> dedupe_vmap_table_;
   ArrayDedupeSet<uint8_t> dedupe_cfi_info_;
-  ArrayDedupeSet<LinkerPatch> dedupe_linker_patches_;
+  ArrayDedupeSet<linker::LinkerPatch> dedupe_linker_patches_;
 
   DISALLOW_COPY_AND_ASSIGN(CompiledMethodStorage);
 };
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 2ec2af5..e1ea630 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -18,7 +18,7 @@
 
 #include <gtest/gtest.h>
 
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler_driver.h"
 #include "compiler_options.h"
 #include "dex/verification_results.h"
@@ -70,17 +70,17 @@
       ArrayRef<const uint8_t>(raw_cfi_info1),
       ArrayRef<const uint8_t>(raw_cfi_info2),
   };
-  const LinkerPatch raw_patches1[] = {
-      LinkerPatch::CodePatch(0u, nullptr, 1u),
-      LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 1u),
+  const linker::LinkerPatch raw_patches1[] = {
+      linker::LinkerPatch::CodePatch(0u, nullptr, 1u),
+      linker::LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 1u),
   };
-  const LinkerPatch raw_patches2[] = {
-      LinkerPatch::CodePatch(0u, nullptr, 1u),
-      LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 2u),
+  const linker::LinkerPatch raw_patches2[] = {
+      linker::LinkerPatch::CodePatch(0u, nullptr, 1u),
+      linker::LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 2u),
   };
-  ArrayRef<const LinkerPatch> patches[] = {
-      ArrayRef<const LinkerPatch>(raw_patches1),
-      ArrayRef<const LinkerPatch>(raw_patches2),
+  ArrayRef<const linker::LinkerPatch> patches[] = {
+      ArrayRef<const linker::LinkerPatch>(raw_patches1),
+      ArrayRef<const linker::LinkerPatch>(raw_patches2),
   };
 
   std::vector<CompiledMethod*> compiled_methods;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 678f090..03d8ef5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -37,7 +37,7 @@
 #include "base/time_utils.h"
 #include "base/timing_logger.h"
 #include "class_linker-inl.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler.h"
 #include "compiler_callbacks.h"
 #include "compiler_driver-inl.h"
@@ -55,6 +55,7 @@
 #include "handle_scope-inl.h"
 #include "intrinsics_enum.h"
 #include "jni_internal.h"
+#include "linker/linker_patch.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
@@ -618,7 +619,7 @@
   if (compiled_method != nullptr) {
     // Count non-relative linker patches.
     size_t non_relative_linker_patch_count = 0u;
-    for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+    for (const linker::LinkerPatch& patch : compiled_method->GetPatches()) {
       if (!patch.IsPcRelative()) {
         ++non_relative_linker_patch_count;
       }
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 5fdf9ff..511a44a 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -175,7 +175,8 @@
   DCHECK(!method->IsProxyMethod());
   DCHECK(method->GetDeclaringClass()->IsResolved());
 
-  TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
+  TimingLogger logger(
+      "JIT compiler timing logger", true, VLOG_IS_ON(jit), TimingLogger::TimingKind::kThreadCpu);
   self->AssertNoPendingException();
   Runtime* runtime = Runtime::Current();
 
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index e7e4647..c66a2a6 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -665,7 +665,7 @@
                                                  /* method_info */ ArrayRef<const uint8_t>(),
                                                  /* vmap_table */ ArrayRef<const uint8_t>(),
                                                  ArrayRef<const uint8_t>(*jni_asm->cfi().data()),
-                                                 ArrayRef<const LinkerPatch>());
+                                                 ArrayRef<const linker::LinkerPatch>());
 }
 
 // Copy a single parameter from the managed to the JNI calling convention.
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index cb6522c..2cb23d1 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -17,9 +17,10 @@
 #include "linker/arm/relative_patcher_arm_base.h"
 
 #include "base/stl_util.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "debug/method_debug_info.h"
 #include "dex_file_types.h"
+#include "linker/linker_patch.h"
 #include "linker/output_stream.h"
 #include "oat.h"
 #include "oat_quick_method_header.h"
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index 704feeb..f84fea3 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -21,6 +21,7 @@
 #include "base/bit_utils.h"
 #include "compiled_method.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "linker/linker_patch.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
 #include "mirror/object.h"
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 82f502a..828c99b 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -20,10 +20,11 @@
 #include "arch/arm64/instruction_set_features_arm64.h"
 #include "art_method.h"
 #include "base/bit_utils.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "driver/compiler_driver.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "heap_poisoning.h"
+#include "linker/linker_patch.h"
 #include "linker/output_stream.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
diff --git a/compiler/linker/linker_patch.h b/compiler/linker/linker_patch.h
new file mode 100644
index 0000000..0ac1490
--- /dev/null
+++ b/compiler/linker/linker_patch.h
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_LINKER_LINKER_PATCH_H_
+#define ART_COMPILER_LINKER_LINKER_PATCH_H_
+
+#include <iosfwd>
+#include <stdint.h>
+
+#include "base/bit_utils.h"
+#include "base/logging.h"
+#include "method_reference.h"
+
+namespace art {
+
+class DexFile;
+
+namespace linker {
+
+class LinkerPatch {
+ public:
+  // Note: We explicitly specify the underlying type of the enum because GCC
+  // would otherwise select a bigger underlying type and then complain that
+  //     'art::LinkerPatch::patch_type_' is too small to hold all
+  //     values of 'enum class art::LinkerPatch::Type'
+  // which is ridiculous given we have only a handful of values here. If we
+  // choose to squeeze the Type into fewer than 8 bits, we'll have to declare
+  // patch_type_ as an uintN_t and do explicit static_cast<>s.
+  enum class Type : uint8_t {
+    kMethodRelative,          // NOTE: Actual patching is instruction_set-dependent.
+    kMethodBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
+    kCall,
+    kCallRelative,            // NOTE: Actual patching is instruction_set-dependent.
+    kTypeRelative,            // NOTE: Actual patching is instruction_set-dependent.
+    kTypeClassTable,          // NOTE: Actual patching is instruction_set-dependent.
+    kTypeBssEntry,            // NOTE: Actual patching is instruction_set-dependent.
+    kStringRelative,          // NOTE: Actual patching is instruction_set-dependent.
+    kStringInternTable,       // NOTE: Actual patching is instruction_set-dependent.
+    kStringBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
+    kBakerReadBarrierBranch,  // NOTE: Actual patching is instruction_set-dependent.
+  };
+
+  static LinkerPatch RelativeMethodPatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_method_idx) {
+    LinkerPatch patch(literal_offset, Type::kMethodRelative, target_dex_file);
+    patch.method_idx_ = target_method_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch MethodBssEntryPatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_method_idx) {
+    LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file);
+    patch.method_idx_ = target_method_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch CodePatch(size_t literal_offset,
+                               const DexFile* target_dex_file,
+                               uint32_t target_method_idx) {
+    LinkerPatch patch(literal_offset, Type::kCall, target_dex_file);
+    patch.method_idx_ = target_method_idx;
+    return patch;
+  }
+
+  static LinkerPatch RelativeCodePatch(size_t literal_offset,
+                                       const DexFile* target_dex_file,
+                                       uint32_t target_method_idx) {
+    LinkerPatch patch(literal_offset, Type::kCallRelative, target_dex_file);
+    patch.method_idx_ = target_method_idx;
+    return patch;
+  }
+
+  static LinkerPatch RelativeTypePatch(size_t literal_offset,
+                                       const DexFile* target_dex_file,
+                                       uint32_t pc_insn_offset,
+                                       uint32_t target_type_idx) {
+    LinkerPatch patch(literal_offset, Type::kTypeRelative, target_dex_file);
+    patch.type_idx_ = target_type_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch TypeClassTablePatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_type_idx) {
+    LinkerPatch patch(literal_offset, Type::kTypeClassTable, target_dex_file);
+    patch.type_idx_ = target_type_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch TypeBssEntryPatch(size_t literal_offset,
+                                       const DexFile* target_dex_file,
+                                       uint32_t pc_insn_offset,
+                                       uint32_t target_type_idx) {
+    LinkerPatch patch(literal_offset, Type::kTypeBssEntry, target_dex_file);
+    patch.type_idx_ = target_type_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch RelativeStringPatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_string_idx) {
+    LinkerPatch patch(literal_offset, Type::kStringRelative, target_dex_file);
+    patch.string_idx_ = target_string_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch StringInternTablePatch(size_t literal_offset,
+                                            const DexFile* target_dex_file,
+                                            uint32_t pc_insn_offset,
+                                            uint32_t target_string_idx) {
+    LinkerPatch patch(literal_offset, Type::kStringInternTable, target_dex_file);
+    patch.string_idx_ = target_string_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch StringBssEntryPatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_string_idx) {
+    LinkerPatch patch(literal_offset, Type::kStringBssEntry, target_dex_file);
+    patch.string_idx_ = target_string_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
+  static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
+                                                 uint32_t custom_value1 = 0u,
+                                                 uint32_t custom_value2 = 0u) {
+    LinkerPatch patch(literal_offset, Type::kBakerReadBarrierBranch, nullptr);
+    patch.baker_custom_value1_ = custom_value1;
+    patch.baker_custom_value2_ = custom_value2;
+    return patch;
+  }
+
+  LinkerPatch(const LinkerPatch& other) = default;
+  LinkerPatch& operator=(const LinkerPatch& other) = default;
+
+  size_t LiteralOffset() const {
+    return literal_offset_;
+  }
+
+  Type GetType() const {
+    return patch_type_;
+  }
+
+  bool IsPcRelative() const {
+    switch (GetType()) {
+      case Type::kMethodRelative:
+      case Type::kMethodBssEntry:
+      case Type::kCallRelative:
+      case Type::kTypeRelative:
+      case Type::kTypeClassTable:
+      case Type::kTypeBssEntry:
+      case Type::kStringRelative:
+      case Type::kStringInternTable:
+      case Type::kStringBssEntry:
+      case Type::kBakerReadBarrierBranch:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  MethodReference TargetMethod() const {
+    DCHECK(patch_type_ == Type::kMethodRelative ||
+           patch_type_ == Type::kMethodBssEntry ||
+           patch_type_ == Type::kCall ||
+           patch_type_ == Type::kCallRelative);
+    return MethodReference(target_dex_file_, method_idx_);
+  }
+
+  const DexFile* TargetTypeDexFile() const {
+    DCHECK(patch_type_ == Type::kTypeRelative ||
+           patch_type_ == Type::kTypeClassTable ||
+           patch_type_ == Type::kTypeBssEntry);
+    return target_dex_file_;
+  }
+
+  dex::TypeIndex TargetTypeIndex() const {
+    DCHECK(patch_type_ == Type::kTypeRelative ||
+           patch_type_ == Type::kTypeClassTable ||
+           patch_type_ == Type::kTypeBssEntry);
+    return dex::TypeIndex(type_idx_);
+  }
+
+  const DexFile* TargetStringDexFile() const {
+    DCHECK(patch_type_ == Type::kStringRelative ||
+           patch_type_ == Type::kStringInternTable ||
+           patch_type_ == Type::kStringBssEntry);
+    return target_dex_file_;
+  }
+
+  dex::StringIndex TargetStringIndex() const {
+    DCHECK(patch_type_ == Type::kStringRelative ||
+           patch_type_ == Type::kStringInternTable ||
+           patch_type_ == Type::kStringBssEntry);
+    return dex::StringIndex(string_idx_);
+  }
+
+  uint32_t PcInsnOffset() const {
+    DCHECK(patch_type_ == Type::kMethodRelative ||
+           patch_type_ == Type::kMethodBssEntry ||
+           patch_type_ == Type::kTypeRelative ||
+           patch_type_ == Type::kTypeClassTable ||
+           patch_type_ == Type::kTypeBssEntry ||
+           patch_type_ == Type::kStringRelative ||
+           patch_type_ == Type::kStringInternTable ||
+           patch_type_ == Type::kStringBssEntry);
+    return pc_insn_offset_;
+  }
+
+  uint32_t GetBakerCustomValue1() const {
+    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
+    return baker_custom_value1_;
+  }
+
+  uint32_t GetBakerCustomValue2() const {
+    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
+    return baker_custom_value2_;
+  }
+
+ private:
+  LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file)
+      : target_dex_file_(target_dex_file),
+        literal_offset_(literal_offset),
+        patch_type_(patch_type) {
+    cmp1_ = 0u;
+    cmp2_ = 0u;
+    // The compiler rejects methods that are too big, so the compiled code
+    // of a single method really shouln't be anywhere close to 16MiB.
+    DCHECK(IsUint<24>(literal_offset));
+  }
+
+  const DexFile* target_dex_file_;
+  // TODO: Clean up naming. Some patched locations are literals but others are not.
+  uint32_t literal_offset_ : 24;  // Method code size up to 16MiB.
+  Type patch_type_ : 8;
+  union {
+    uint32_t cmp1_;             // Used for relational operators.
+    uint32_t method_idx_;       // Method index for Call/Method patches.
+    uint32_t type_idx_;         // Type index for Type patches.
+    uint32_t string_idx_;       // String index for String patches.
+    uint32_t baker_custom_value1_;
+    static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
+    static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
+    static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
+    static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
+  };
+  union {
+    // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
+    // This allows a hashing function to treat an array of linker patches as raw memory.
+    size_t cmp2_;             // Used for relational operators.
+    // Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
+    // may be different if the PC-relative addressing needs multiple insns).
+    uint32_t pc_insn_offset_;
+    uint32_t baker_custom_value2_;
+    static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
+    static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators");
+  };
+
+  friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
+  friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs);
+};
+std::ostream& operator<<(std::ostream& os, const LinkerPatch::Type& type);
+
+inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) {
+  return lhs.literal_offset_ == rhs.literal_offset_ &&
+      lhs.patch_type_ == rhs.patch_type_ &&
+      lhs.target_dex_file_ == rhs.target_dex_file_ &&
+      lhs.cmp1_ == rhs.cmp1_ &&
+      lhs.cmp2_ == rhs.cmp2_;
+}
+
+inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) {
+  return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_
+      : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_
+      : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_
+      : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_
+      : lhs.cmp2_ < rhs.cmp2_;
+}
+
+}  // namespace linker
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_LINKER_PATCH_H_
diff --git a/compiler/compiled_method_test.cc b/compiler/linker/linker_patch_test.cc
similarity index 90%
rename from compiler/compiled_method_test.cc
rename to compiler/linker/linker_patch_test.cc
index f4a72cf..e87dc8d 100644
--- a/compiler/compiled_method_test.cc
+++ b/compiler/linker/linker_patch_test.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,37 +16,12 @@
 
 #include <gtest/gtest.h>
 
-#include "compiled_method.h"
+#include "linker_patch.h"
 
 namespace art {
+namespace linker {
 
-TEST(CompiledMethod, SrcMapElemOperators) {
-  SrcMapElem elems[] = {
-      { 1u, -1 },
-      { 1u, 0 },
-      { 1u, 1 },
-      { 2u, -1 },
-      { 2u, 0 },    // Index 4.
-      { 2u, 1 },
-      { 2u, 0u },   // Index 6: Arbitrarily add identical SrcMapElem with index 4.
-  };
-
-  for (size_t i = 0; i != arraysize(elems); ++i) {
-    for (size_t j = 0; j != arraysize(elems); ++j) {
-      bool expected = (i != 6u ? i : 4u) == (j != 6u ? j : 4u);
-      EXPECT_EQ(expected, elems[i] == elems[j]) << i << " " << j;
-    }
-  }
-
-  for (size_t i = 0; i != arraysize(elems); ++i) {
-    for (size_t j = 0; j != arraysize(elems); ++j) {
-      bool expected = (i != 6u ? i : 4u) < (j != 6u ? j : 4u);
-      EXPECT_EQ(expected, elems[i] < elems[j]) << i << " " << j;
-    }
-  }
-}
-
-TEST(CompiledMethod, LinkerPatchOperators) {
+TEST(LinkerPatch, LinkerPatchOperators) {
   const DexFile* dex_file1 = reinterpret_cast<const DexFile*>(1);
   const DexFile* dex_file2 = reinterpret_cast<const DexFile*>(2);
   LinkerPatch patches[] = {
@@ -191,4 +166,5 @@
   }
 }
 
+}  // namespace linker
 }  // namespace art
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index 408ac22..69e0846 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -18,6 +18,7 @@
 
 #include "compiled_method.h"
 #include "debug/method_debug_info.h"
+#include "linker/linker_patch.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc
index 2bcd98a..aae5746 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64.cc
@@ -18,6 +18,7 @@
 
 #include "compiled_method.h"
 #include "debug/method_debug_info.h"
+#include "linker/linker_patch.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
index e079946..548e128 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -28,7 +28,6 @@
 namespace art {
 
 class CompiledMethod;
-class LinkerPatch;
 
 namespace debug {
 struct MethodDebugInfo;
@@ -36,6 +35,7 @@
 
 namespace linker {
 
+class LinkerPatch;
 class OutputStream;
 
 /**
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index f7dbc1e..6297dd0 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -21,7 +21,7 @@
 #include "arch/instruction_set_features.h"
 #include "base/array_ref.h"
 #include "base/macros.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
diff --git a/compiler/linker/x86/relative_patcher_x86.cc b/compiler/linker/x86/relative_patcher_x86.cc
index 6967b0b..cdd2cef 100644
--- a/compiler/linker/x86/relative_patcher_x86.cc
+++ b/compiler/linker/x86/relative_patcher_x86.cc
@@ -17,6 +17,7 @@
 #include "linker/x86/relative_patcher_x86.h"
 
 #include "compiled_method.h"
+#include "linker/linker_patch.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/x86_64/relative_patcher_x86_64.cc b/compiler/linker/x86_64/relative_patcher_x86_64.cc
index 156ece9..9633564 100644
--- a/compiler/linker/x86_64/relative_patcher_x86_64.cc
+++ b/compiler/linker/x86_64/relative_patcher_x86_64.cc
@@ -17,6 +17,7 @@
 #include "linker/x86_64/relative_patcher_x86_64.h"
 
 #include "compiled_method.h"
+#include "linker/linker_patch.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index a170734..a7f7bce 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -927,7 +927,7 @@
 
   void VisitPhi(HPhi* phi) OVERRIDE {
     if (phi->IsLoopHeaderPhi()
-        && (phi->GetType() == Primitive::kPrimInt)
+        && (phi->GetType() == DataType::Type::kInt32)
         && HasSameInputAtBackEdges(phi)) {
       HInstruction* instruction = phi->InputAt(1);
       HInstruction *left;
@@ -1261,8 +1261,8 @@
       DCHECK_GE(min_c, 0);
     } else {
       HInstruction* lower = new (GetGraph()->GetArena())
-          HAdd(Primitive::kPrimInt, base, GetGraph()->GetIntConstant(min_c));
-      upper = new (GetGraph()->GetArena()) HAdd(Primitive::kPrimInt, base, upper);
+          HAdd(DataType::Type::kInt32, base, GetGraph()->GetIntConstant(min_c));
+      upper = new (GetGraph()->GetArena()) HAdd(DataType::Type::kInt32, base, upper);
       block->InsertInstructionBefore(lower, bounds_check);
       block->InsertInstructionBefore(upper, bounds_check);
       InsertDeoptInBlock(bounds_check, new (GetGraph()->GetArena()) HAbove(lower, upper));
@@ -1801,7 +1801,7 @@
       // Scan all instructions in a new deoptimization block.
       for (HInstructionIterator it(true_block->GetInstructions()); !it.Done(); it.Advance()) {
         HInstruction* instruction = it.Current();
-        Primitive::Type type = instruction->GetType();
+        DataType::Type type = instruction->GetType();
         HPhi* phi = nullptr;
         // Scan all uses of an instruction and replace each later use with a phi node.
         const HUseList<HInstruction*>& uses = instruction->GetUses();
@@ -1844,20 +1844,20 @@
    */
   HPhi* NewPhi(HBasicBlock* new_preheader,
                HInstruction* instruction,
-               Primitive::Type type) {
+               DataType::Type type) {
     HGraph* graph = GetGraph();
     HInstruction* zero;
     switch (type) {
-      case Primitive::kPrimNot: zero = graph->GetNullConstant(); break;
-      case Primitive::kPrimFloat: zero = graph->GetFloatConstant(0); break;
-      case Primitive::kPrimDouble: zero = graph->GetDoubleConstant(0); break;
+      case DataType::Type::kReference: zero = graph->GetNullConstant(); break;
+      case DataType::Type::kFloat32: zero = graph->GetFloatConstant(0); break;
+      case DataType::Type::kFloat64: zero = graph->GetDoubleConstant(0); break;
       default: zero = graph->GetConstant(type, 0); break;
     }
     HPhi* phi = new (graph->GetArena())
         HPhi(graph->GetArena(), kNoRegNumber, /*number_of_inputs*/ 2, HPhi::ToPhiType(type));
     phi->SetRawInputAt(0, instruction);
     phi->SetRawInputAt(1, zero);
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       phi->SetReferenceTypeInfo(instruction->GetReferenceTypeInfo());
     }
     new_preheader->AddPhi(phi);
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 2aaf058..851838c 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -70,10 +70,10 @@
   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
-  HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
-  HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
+  HInstruction* parameter1 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);  // array
+  HInstruction* parameter2 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -95,7 +95,7 @@
   HBoundsCheck* bounds_check2 = new (&allocator_)
       HBoundsCheck(parameter2, array_length, 0);
   HArraySet* array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check2, constant_1, DataType::Type::kInt32, 0);
   block2->AddInstruction(null_check);
   block2->AddInstruction(array_length);
   block2->AddInstruction(bounds_check2);
@@ -119,7 +119,7 @@
   HBoundsCheck* bounds_check4 = new (&allocator_)
       HBoundsCheck(parameter2, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
   block4->AddInstruction(null_check);
   block4->AddInstruction(array_length);
   block4->AddInstruction(bounds_check4);
@@ -132,7 +132,7 @@
   HBoundsCheck* bounds_check5 = new (&allocator_)
       HBoundsCheck(parameter2, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
   block5->AddInstruction(null_check);
   block5->AddInstruction(array_length);
   block5->AddInstruction(bounds_check5);
@@ -167,10 +167,10 @@
   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
-  HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
-  HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
+  HInstruction* parameter1 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);  // array
+  HInstruction* parameter2 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -188,7 +188,7 @@
 
   HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(block2);
-  HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
+  HInstruction* add = new (&allocator_) HAdd(DataType::Type::kInt32, parameter2, constant_max_int);
   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
   HInstruction* cmp2 = new (&allocator_) HGreaterThanOrEqual(add, array_length);
@@ -204,7 +204,7 @@
   HBoundsCheck* bounds_check = new (&allocator_)
       HBoundsCheck(add, array_length, 0);
   HArraySet* array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
   block3->AddInstruction(bounds_check);
   block3->AddInstruction(array_set);
 
@@ -231,10 +231,10 @@
   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
-  HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
-  HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
+  HInstruction* parameter1 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);  // array
+  HInstruction* parameter2 = new (&allocator_) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -256,8 +256,8 @@
 
   HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(block2);
-  HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
-  HInstruction* sub2 = new (&allocator_) HSub(Primitive::kPrimInt, sub1, constant_max_int);
+  HInstruction* sub1 = new (&allocator_) HSub(DataType::Type::kInt32, parameter2, constant_max_int);
+  HInstruction* sub2 = new (&allocator_) HSub(DataType::Type::kInt32, sub1, constant_max_int);
   HInstruction* cmp2 = new (&allocator_) HLessThanOrEqual(sub2, constant_0);
   if_inst = new (&allocator_) HIf(cmp2);
   block2->AddInstruction(sub1);
@@ -270,7 +270,7 @@
   HBoundsCheck* bounds_check = new (&allocator_)
       HBoundsCheck(sub2, array_length, 0);
   HArraySet* array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
   block3->AddInstruction(bounds_check);
   block3->AddInstruction(array_set);
 
@@ -296,7 +296,7 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_5 = graph_->GetIntConstant(5);
@@ -313,7 +313,7 @@
   HBoundsCheck* bounds_check6 = new (&allocator_)
       HBoundsCheck(constant_6, array_length, 0);
   HInstruction* array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check6, constant_1, DataType::Type::kInt32, 0);
   block->AddInstruction(null_check);
   block->AddInstruction(array_length);
   block->AddInstruction(bounds_check6);
@@ -324,7 +324,7 @@
   HBoundsCheck* bounds_check5 = new (&allocator_)
       HBoundsCheck(constant_5, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
   block->AddInstruction(null_check);
   block->AddInstruction(array_length);
   block->AddInstruction(bounds_check5);
@@ -335,7 +335,7 @@
   HBoundsCheck* bounds_check4 = new (&allocator_)
       HBoundsCheck(constant_4, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-    null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
+    null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
   block->AddInstruction(null_check);
   block->AddInstruction(array_length);
   block->AddInstruction(bounds_check4);
@@ -365,7 +365,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -389,7 +389,7 @@
   loop_header->AddSuccessor(loop_body);  // false successor
   loop_body->AddSuccessor(loop_header);
 
-  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
   HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
   HInstruction* cmp = nullptr;
@@ -411,9 +411,9 @@
   array_length = new (allocator) HArrayLength(null_check, 0);
   HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
   HInstruction* array_set = new (allocator) HArraySet(
-      null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
+      null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
 
-  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+  HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
   loop_body->AddInstruction(bounds_check);
@@ -480,7 +480,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -509,7 +509,7 @@
   loop_header->AddSuccessor(loop_body);  // false successor
   loop_body->AddSuccessor(loop_header);
 
-  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
   HInstruction* cmp = nullptr;
   if (cond == kCondLE) {
     cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
@@ -523,13 +523,13 @@
   loop_header->AddInstruction(if_inst);
   phi->AddInput(array_length);
 
-  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
+  HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_minus_1);
   null_check = new (allocator) HNullCheck(parameter, 0);
   array_length = new (allocator) HArrayLength(null_check, 0);
   HInstruction* bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
   HInstruction* array_set = new (allocator) HArraySet(
-      null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
-  HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+      null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
+  HInstruction* add_phi = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
   loop_body->AddInstruction(add);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
@@ -617,7 +617,7 @@
   loop_header->AddSuccessor(loop_body);  // false successor
   loop_body->AddSuccessor(loop_header);
 
-  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
   HInstruction* cmp = nullptr;
   if (cond == kCondGE) {
     cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
@@ -635,8 +635,8 @@
   HArrayLength* array_length = new (allocator) HArrayLength(null_check, 0);
   HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
   HInstruction* array_set = new (allocator) HArraySet(
-      null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
-  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+      null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
+  HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
   loop_body->AddInstruction(bounds_check);
@@ -691,7 +691,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -716,7 +716,7 @@
   loop_header->AddSuccessor(loop_body);  // false successor
   loop_body->AddSuccessor(loop_header);
 
-  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
   HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
   HInstruction* cmp = nullptr;
@@ -735,13 +735,13 @@
 
   null_check = new (allocator) HNullCheck(parameter, 0);
   array_length = new (allocator) HArrayLength(null_check, 0);
-  HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
+  HInstruction* sub = new (allocator) HSub(DataType::Type::kInt32, array_length, phi);
   HInstruction* add_minus_1 = new (allocator)
-      HAdd(Primitive::kPrimInt, sub, constant_minus_1);
+      HAdd(DataType::Type::kInt32, sub, constant_minus_1);
   HInstruction* bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
   HInstruction* array_set = new (allocator) HArraySet(
-      null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
-  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
+      null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
+  HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_1);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
   loop_body->AddInstruction(sub);
@@ -794,7 +794,7 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_0 = graph_->GetIntConstant(0);
@@ -812,10 +812,10 @@
 
   HBasicBlock* outer_header = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(outer_header);
-  HPhi* phi_i = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+  HPhi* phi_i = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter, 0);
   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
-  HAdd* add = new (&allocator_) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
+  HAdd* add = new (&allocator_) HAdd(DataType::Type::kInt32, array_length, constant_minus_1);
   HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi_i, add);
   HIf* if_inst = new (&allocator_) HIf(cmp);
   outer_header->AddPhi(phi_i);
@@ -828,11 +828,11 @@
 
   HBasicBlock* inner_header = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(inner_header);
-  HPhi* phi_j = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+  HPhi* phi_j = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
   null_check = new (&allocator_) HNullCheck(parameter, 0);
   array_length = new (&allocator_) HArrayLength(null_check, 0);
-  HSub* sub = new (&allocator_) HSub(Primitive::kPrimInt, array_length, phi_i);
-  add = new (&allocator_) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
+  HSub* sub = new (&allocator_) HSub(DataType::Type::kInt32, array_length, phi_i);
+  add = new (&allocator_) HAdd(DataType::Type::kInt32, sub, constant_minus_1);
   cmp = new (&allocator_) HGreaterThanOrEqual(phi_j, add);
   if_inst = new (&allocator_) HIf(cmp);
   inner_header->AddPhi(phi_j);
@@ -850,17 +850,17 @@
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HBoundsCheck* bounds_check1 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
   HArrayGet* array_get_j = new (&allocator_)
-      HArrayGet(null_check, bounds_check1, Primitive::kPrimInt, 0);
+      HArrayGet(null_check, bounds_check1, DataType::Type::kInt32, 0);
   inner_body_compare->AddInstruction(null_check);
   inner_body_compare->AddInstruction(array_length);
   inner_body_compare->AddInstruction(bounds_check1);
   inner_body_compare->AddInstruction(array_get_j);
-  HInstruction* j_plus_1 = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  HInstruction* j_plus_1 = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
   null_check = new (&allocator_) HNullCheck(parameter, 0);
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HBoundsCheck* bounds_check2 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
   HArrayGet* array_get_j_plus_1 = new (&allocator_)
-      HArrayGet(null_check, bounds_check2, Primitive::kPrimInt, 0);
+      HArrayGet(null_check, bounds_check2, DataType::Type::kInt32, 0);
   cmp = new (&allocator_) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
   if_inst = new (&allocator_) HIf(cmp);
   inner_body_compare->AddInstruction(j_plus_1);
@@ -873,13 +873,13 @@
 
   HBasicBlock* inner_body_swap = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(inner_body_swap);
-  j_plus_1 = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  j_plus_1 = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
   // temp = array[j+1]
   null_check = new (&allocator_) HNullCheck(parameter, 0);
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HInstruction* bounds_check3 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
   array_get_j_plus_1 = new (&allocator_)
-      HArrayGet(null_check, bounds_check3, Primitive::kPrimInt, 0);
+      HArrayGet(null_check, bounds_check3, DataType::Type::kInt32, 0);
   inner_body_swap->AddInstruction(j_plus_1);
   inner_body_swap->AddInstruction(null_check);
   inner_body_swap->AddInstruction(array_length);
@@ -890,7 +890,7 @@
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HInstruction* bounds_check4 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
   array_get_j = new (&allocator_)
-      HArrayGet(null_check, bounds_check4, Primitive::kPrimInt, 0);
+      HArrayGet(null_check, bounds_check4, DataType::Type::kInt32, 0);
   inner_body_swap->AddInstruction(null_check);
   inner_body_swap->AddInstruction(array_length);
   inner_body_swap->AddInstruction(bounds_check4);
@@ -899,7 +899,7 @@
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HInstruction* bounds_check5 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
   HArraySet* array_set_j_plus_1 = new (&allocator_)
-      HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
+      HArraySet(null_check, bounds_check5, array_get_j, DataType::Type::kInt32, 0);
   inner_body_swap->AddInstruction(null_check);
   inner_body_swap->AddInstruction(array_length);
   inner_body_swap->AddInstruction(bounds_check5);
@@ -909,7 +909,7 @@
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HInstruction* bounds_check6 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
   HArraySet* array_set_j = new (&allocator_)
-      HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
+      HArraySet(null_check, bounds_check6, array_get_j_plus_1, DataType::Type::kInt32, 0);
   inner_body_swap->AddInstruction(null_check);
   inner_body_swap->AddInstruction(array_length);
   inner_body_swap->AddInstruction(bounds_check6);
@@ -918,14 +918,14 @@
 
   HBasicBlock* inner_body_add = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(inner_body_add);
-  add = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  add = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
   inner_body_add->AddInstruction(add);
   inner_body_add->AddInstruction(new (&allocator_) HGoto());
   phi_j->AddInput(add);
 
   HBasicBlock* outer_body_add = new (&allocator_) HBasicBlock(graph_);
   graph_->AddBlock(outer_body_add);
-  add = new (&allocator_) HAdd(Primitive::kPrimInt, phi_i, constant_1);
+  add = new (&allocator_) HAdd(DataType::Type::kInt32, phi_i, constant_1);
   outer_body_add->AddInstruction(add);
   outer_body_add->AddInstruction(new (&allocator_) HGoto());
   phi_i->AddInput(add);
@@ -965,7 +965,7 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* param_i = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   entry->AddInstruction(param_i);
 
   HInstruction* constant_0 = graph_->GetIntConstant(0);
@@ -994,7 +994,7 @@
   loop_header->AddSuccessor(loop_body);  // false successor
   loop_body->AddSuccessor(loop_header);
 
-  HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+  HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
   HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi, constant_200);
   HInstruction* if_inst = new (&allocator_) HIf(cmp);
   loop_header->AddPhi(phi);
@@ -1005,38 +1005,38 @@
   //////////////////////////////////////////////////////////////////////////////////
   // LOOP BODY:
   // array[i % 10] = 10;
-  HRem* i_mod_10 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_10, 0);
+  HRem* i_mod_10 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_10, 0);
   HBoundsCheck* bounds_check_i_mod_10 = new (&allocator_) HBoundsCheck(i_mod_10, constant_10, 0);
   HInstruction* array_set = new (&allocator_) HArraySet(
-      new_array, bounds_check_i_mod_10, constant_10, Primitive::kPrimInt, 0);
+      new_array, bounds_check_i_mod_10, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(i_mod_10);
   loop_body->AddInstruction(bounds_check_i_mod_10);
   loop_body->AddInstruction(array_set);
 
   // array[i % 1] = 10;
-  HRem* i_mod_1 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_1, 0);
+  HRem* i_mod_1 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_1, 0);
   HBoundsCheck* bounds_check_i_mod_1 = new (&allocator_) HBoundsCheck(i_mod_1, constant_10, 0);
   array_set = new (&allocator_) HArraySet(
-      new_array, bounds_check_i_mod_1, constant_10, Primitive::kPrimInt, 0);
+      new_array, bounds_check_i_mod_1, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(i_mod_1);
   loop_body->AddInstruction(bounds_check_i_mod_1);
   loop_body->AddInstruction(array_set);
 
   // array[i % 200] = 10;
-  HRem* i_mod_200 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_1, 0);
+  HRem* i_mod_200 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_1, 0);
   HBoundsCheck* bounds_check_i_mod_200 = new (&allocator_) HBoundsCheck(i_mod_200, constant_10, 0);
   array_set = new (&allocator_) HArraySet(
-      new_array, bounds_check_i_mod_200, constant_10, Primitive::kPrimInt, 0);
+      new_array, bounds_check_i_mod_200, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(i_mod_200);
   loop_body->AddInstruction(bounds_check_i_mod_200);
   loop_body->AddInstruction(array_set);
 
   // array[i % -10] = 10;
-  HRem* i_mod_minus_10 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_minus_10, 0);
+  HRem* i_mod_minus_10 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_minus_10, 0);
   HBoundsCheck* bounds_check_i_mod_minus_10 = new (&allocator_) HBoundsCheck(
       i_mod_minus_10, constant_10, 0);
   array_set = new (&allocator_) HArraySet(
-      new_array, bounds_check_i_mod_minus_10, constant_10, Primitive::kPrimInt, 0);
+      new_array, bounds_check_i_mod_minus_10, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(i_mod_minus_10);
   loop_body->AddInstruction(bounds_check_i_mod_minus_10);
   loop_body->AddInstruction(array_set);
@@ -1044,11 +1044,11 @@
   // array[i%array.length] = 10;
   HNullCheck* null_check = new (&allocator_) HNullCheck(new_array, 0);
   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
-  HRem* i_mod_array_length = new (&allocator_) HRem(Primitive::kPrimInt, phi, array_length, 0);
+  HRem* i_mod_array_length = new (&allocator_) HRem(DataType::Type::kInt32, phi, array_length, 0);
   HBoundsCheck* bounds_check_i_mod_array_len = new (&allocator_) HBoundsCheck(
       i_mod_array_length, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-      null_check, bounds_check_i_mod_array_len, constant_10, Primitive::kPrimInt, 0);
+      null_check, bounds_check_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
   loop_body->AddInstruction(i_mod_array_length);
@@ -1056,11 +1056,11 @@
   loop_body->AddInstruction(array_set);
 
   // array[param_i % 10] = 10;
-  HRem* param_i_mod_10 = new (&allocator_) HRem(Primitive::kPrimInt, param_i, constant_10, 0);
+  HRem* param_i_mod_10 = new (&allocator_) HRem(DataType::Type::kInt32, param_i, constant_10, 0);
   HBoundsCheck* bounds_check_param_i_mod_10 = new (&allocator_) HBoundsCheck(
       param_i_mod_10, constant_10, 0);
   array_set = new (&allocator_) HArraySet(
-      new_array, bounds_check_param_i_mod_10, constant_10, Primitive::kPrimInt, 0);
+      new_array, bounds_check_param_i_mod_10, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(param_i_mod_10);
   loop_body->AddInstruction(bounds_check_param_i_mod_10);
   loop_body->AddInstruction(array_set);
@@ -1069,11 +1069,11 @@
   null_check = new (&allocator_) HNullCheck(new_array, 0);
   array_length = new (&allocator_) HArrayLength(null_check, 0);
   HRem* param_i_mod_array_length = new (&allocator_) HRem(
-      Primitive::kPrimInt, param_i, array_length, 0);
+      DataType::Type::kInt32, param_i, array_length, 0);
   HBoundsCheck* bounds_check_param_i_mod_array_len = new (&allocator_) HBoundsCheck(
       param_i_mod_array_length, array_length, 0);
   array_set = new (&allocator_) HArraySet(
-      null_check, bounds_check_param_i_mod_array_len, constant_10, Primitive::kPrimInt, 0);
+      null_check, bounds_check_param_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
   loop_body->AddInstruction(null_check);
   loop_body->AddInstruction(array_length);
   loop_body->AddInstruction(param_i_mod_array_length);
@@ -1081,7 +1081,7 @@
   loop_body->AddInstruction(array_set);
 
   // i++;
-  HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, phi, constant_1);
+  HInstruction* add = new (&allocator_) HAdd(DataType::Type::kInt32, phi, constant_1);
   loop_body->AddInstruction(add);
   loop_body->AddInstruction(new (&allocator_) HGoto());
   phi->AddInput(add);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 0d9d3d4..0e708ed 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -20,17 +20,52 @@
 #include "base/arena_bit_vector.h"
 #include "base/bit_vector-inl.h"
 #include "base/logging.h"
+#include "data_type-inl.h"
 #include "dex/verified_method.h"
 #include "driver/compiler_options.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache.h"
 #include "nodes.h"
-#include "primitive.h"
 #include "thread.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 
 namespace art {
 
+HGraphBuilder::HGraphBuilder(HGraph* graph,
+                             DexCompilationUnit* dex_compilation_unit,
+                             const DexCompilationUnit* const outer_compilation_unit,
+                             CompilerDriver* driver,
+                             CodeGenerator* code_generator,
+                             OptimizingCompilerStats* compiler_stats,
+                             const uint8_t* interpreter_metadata,
+                             Handle<mirror::DexCache> dex_cache,
+                             VariableSizedHandleScope* handles)
+    : graph_(graph),
+      dex_file_(&graph->GetDexFile()),
+      code_item_(*dex_compilation_unit->GetCodeItem()),
+      dex_compilation_unit_(dex_compilation_unit),
+      compiler_driver_(driver),
+      compilation_stats_(compiler_stats),
+      block_builder_(graph, dex_file_, code_item_),
+      ssa_builder_(graph,
+                   dex_compilation_unit->GetClassLoader(),
+                   dex_compilation_unit->GetDexCache(),
+                   handles),
+      instruction_builder_(graph,
+                           &block_builder_,
+                           &ssa_builder_,
+                           dex_file_,
+                           code_item_,
+                           DataType::FromShorty(dex_compilation_unit_->GetShorty()[0]),
+                           dex_compilation_unit,
+                           outer_compilation_unit,
+                           driver,
+                           code_generator,
+                           interpreter_metadata,
+                           compiler_stats,
+                           dex_cache,
+                           handles) {}
+
 bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {
   if (compiler_driver_ == nullptr) {
     // Note that the compiler driver is null when unit testing.
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 2c9a9ef..9524fe2 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -27,7 +27,6 @@
 #include "instruction_builder.h"
 #include "nodes.h"
 #include "optimizing_compiler_stats.h"
-#include "primitive.h"
 #include "ssa_builder.h"
 
 namespace art {
@@ -39,45 +38,18 @@
   HGraphBuilder(HGraph* graph,
                 DexCompilationUnit* dex_compilation_unit,
                 const DexCompilationUnit* const outer_compilation_unit,
-                const DexFile* dex_file,
-                const DexFile::CodeItem& code_item,
                 CompilerDriver* driver,
                 CodeGenerator* code_generator,
                 OptimizingCompilerStats* compiler_stats,
                 const uint8_t* interpreter_metadata,
                 Handle<mirror::DexCache> dex_cache,
-                VariableSizedHandleScope* handles)
-      : graph_(graph),
-        dex_file_(dex_file),
-        code_item_(code_item),
-        dex_compilation_unit_(dex_compilation_unit),
-        compiler_driver_(driver),
-        compilation_stats_(compiler_stats),
-        block_builder_(graph, dex_file, code_item),
-        ssa_builder_(graph,
-                     dex_compilation_unit->GetClassLoader(),
-                     dex_compilation_unit->GetDexCache(),
-                     handles),
-        instruction_builder_(graph,
-                             &block_builder_,
-                             &ssa_builder_,
-                             dex_file,
-                             code_item_,
-                             Primitive::GetType(dex_compilation_unit_->GetShorty()[0]),
-                             dex_compilation_unit,
-                             outer_compilation_unit,
-                             driver,
-                             code_generator,
-                             interpreter_metadata,
-                             compiler_stats,
-                             dex_cache,
-                             handles) {}
+                VariableSizedHandleScope* handles);
 
   // Only for unit testing.
   HGraphBuilder(HGraph* graph,
                 const DexFile::CodeItem& code_item,
                 VariableSizedHandleScope* handles,
-                Primitive::Type return_type = Primitive::kPrimInt)
+                DataType::Type return_type = DataType::Type::kInt32)
       : graph_(graph),
         dex_file_(nullptr),
         code_item_(code_item),
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 1e5f1ec..b8e4f32 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -68,35 +68,35 @@
 static constexpr bool kEnableDexLayoutOptimizations = false;
 
 // Return whether a location is consistent with a type.
-static bool CheckType(Primitive::Type type, Location location) {
+static bool CheckType(DataType::Type type, Location location) {
   if (location.IsFpuRegister()
       || (location.IsUnallocated() && (location.GetPolicy() == Location::kRequiresFpuRegister))) {
-    return (type == Primitive::kPrimFloat) || (type == Primitive::kPrimDouble);
+    return (type == DataType::Type::kFloat32) || (type == DataType::Type::kFloat64);
   } else if (location.IsRegister() ||
              (location.IsUnallocated() && (location.GetPolicy() == Location::kRequiresRegister))) {
-    return Primitive::IsIntegralType(type) || (type == Primitive::kPrimNot);
+    return DataType::IsIntegralType(type) || (type == DataType::Type::kReference);
   } else if (location.IsRegisterPair()) {
-    return type == Primitive::kPrimLong;
+    return type == DataType::Type::kInt64;
   } else if (location.IsFpuRegisterPair()) {
-    return type == Primitive::kPrimDouble;
+    return type == DataType::Type::kFloat64;
   } else if (location.IsStackSlot()) {
-    return (Primitive::IsIntegralType(type) && type != Primitive::kPrimLong)
-           || (type == Primitive::kPrimFloat)
-           || (type == Primitive::kPrimNot);
+    return (DataType::IsIntegralType(type) && type != DataType::Type::kInt64)
+           || (type == DataType::Type::kFloat32)
+           || (type == DataType::Type::kReference);
   } else if (location.IsDoubleStackSlot()) {
-    return (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble);
+    return (type == DataType::Type::kInt64) || (type == DataType::Type::kFloat64);
   } else if (location.IsConstant()) {
     if (location.GetConstant()->IsIntConstant()) {
-      return Primitive::IsIntegralType(type) && (type != Primitive::kPrimLong);
+      return DataType::IsIntegralType(type) && (type != DataType::Type::kInt64);
     } else if (location.GetConstant()->IsNullConstant()) {
-      return type == Primitive::kPrimNot;
+      return type == DataType::Type::kReference;
     } else if (location.GetConstant()->IsLongConstant()) {
-      return type == Primitive::kPrimLong;
+      return type == DataType::Type::kInt64;
     } else if (location.GetConstant()->IsFloatConstant()) {
-      return type == Primitive::kPrimFloat;
+      return type == DataType::Type::kFloat32;
     } else {
       return location.GetConstant()->IsDoubleConstant()
-          && (type == Primitive::kPrimDouble);
+          && (type == DataType::Type::kFloat64);
     }
   } else {
     return location.IsInvalid() || (location.GetPolicy() == Location::kAny);
@@ -130,7 +130,7 @@
   HEnvironment* environment = instruction->GetEnvironment();
   for (size_t i = 0; i < instruction->EnvironmentSize(); ++i) {
     if (environment->GetInstructionAt(i) != nullptr) {
-      Primitive::Type type = environment->GetInstructionAt(i)->GetType();
+      DataType::Type type = environment->GetInstructionAt(i)->GetType();
       DCHECK(CheckType(type, environment->GetLocationAt(i)))
         << type << " " << environment->GetLocationAt(i);
     } else {
@@ -157,10 +157,10 @@
 }
 
 uint32_t CodeGenerator::GetArrayDataOffset(HArrayGet* array_get) {
-  DCHECK(array_get->GetType() == Primitive::kPrimChar || !array_get->IsStringCharAt());
+  DCHECK(array_get->GetType() == DataType::Type::kUint16 || !array_get->IsStringCharAt());
   return array_get->IsStringCharAt()
       ? mirror::String::ValueOffset().Uint32Value()
-      : mirror::Array::DataOffset(Primitive::ComponentSize(array_get->GetType())).Uint32Value();
+      : mirror::Array::DataOffset(DataType::Size(array_get->GetType())).Uint32Value();
 }
 
 bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {
@@ -288,7 +288,8 @@
   GetAssembler()->FinalizeInstructions(code);
 }
 
-void CodeGenerator::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches ATTRIBUTE_UNUSED) {
+void CodeGenerator::EmitLinkerPatches(
+    ArenaVector<linker::LinkerPatch>* linker_patches ATTRIBUTE_UNUSED) {
   // No linker patches by default.
 }
 
@@ -412,7 +413,7 @@
 
 void CodeGenerator::CreateUnresolvedFieldLocationSummary(
     HInstruction* field_access,
-    Primitive::Type field_type,
+    DataType::Type field_type,
     const FieldAccessCallingConvention& calling_convention) {
   bool is_instance = field_access->IsUnresolvedInstanceFieldGet()
       || field_access->IsUnresolvedInstanceFieldSet();
@@ -434,7 +435,7 @@
   // regardless of the the type. Because of that we forced to special case
   // the access to floating point values.
   if (is_get) {
-    if (Primitive::IsFloatingPointType(field_type)) {
+    if (DataType::IsFloatingPointType(field_type)) {
       // The return value will be stored in regular registers while register
       // allocator expects it in a floating point register.
       // Note We don't need to request additional temps because the return
@@ -447,7 +448,7 @@
     }
   } else {
      size_t set_index = is_instance ? 1 : 0;
-     if (Primitive::IsFloatingPointType(field_type)) {
+     if (DataType::IsFloatingPointType(field_type)) {
       // The set value comes from a float location while the calling convention
       // expects it in a regular register location. Allocate a temp for it and
       // make the transfer at codegen.
@@ -462,7 +463,7 @@
 
 void CodeGenerator::GenerateUnresolvedFieldAccess(
     HInstruction* field_access,
-    Primitive::Type field_type,
+    DataType::Type field_type,
     uint32_t field_index,
     uint32_t dex_pc,
     const FieldAccessCallingConvention& calling_convention) {
@@ -475,51 +476,52 @@
   bool is_get = field_access->IsUnresolvedInstanceFieldGet()
       || field_access->IsUnresolvedStaticFieldGet();
 
-  if (!is_get && Primitive::IsFloatingPointType(field_type)) {
+  if (!is_get && DataType::IsFloatingPointType(field_type)) {
     // Copy the float value to be set into the calling convention register.
     // Note that using directly the temp location is problematic as we don't
     // support temp register pairs. To avoid boilerplate conversion code, use
     // the location from the calling convention.
     MoveLocation(calling_convention.GetSetValueLocation(field_type, is_instance),
                  locations->InAt(is_instance ? 1 : 0),
-                 (Primitive::Is64BitType(field_type) ? Primitive::kPrimLong : Primitive::kPrimInt));
+                 (DataType::Is64BitType(field_type) ? DataType::Type::kInt64
+                                                    : DataType::Type::kInt32));
   }
 
   QuickEntrypointEnum entrypoint = kQuickSet8Static;  // Initialize to anything to avoid warnings.
   switch (field_type) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       entrypoint = is_instance
           ? (is_get ? kQuickGetBooleanInstance : kQuickSet8Instance)
           : (is_get ? kQuickGetBooleanStatic : kQuickSet8Static);
       break;
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       entrypoint = is_instance
           ? (is_get ? kQuickGetByteInstance : kQuickSet8Instance)
           : (is_get ? kQuickGetByteStatic : kQuickSet8Static);
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       entrypoint = is_instance
           ? (is_get ? kQuickGetShortInstance : kQuickSet16Instance)
           : (is_get ? kQuickGetShortStatic : kQuickSet16Static);
       break;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       entrypoint = is_instance
           ? (is_get ? kQuickGetCharInstance : kQuickSet16Instance)
           : (is_get ? kQuickGetCharStatic : kQuickSet16Static);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       entrypoint = is_instance
           ? (is_get ? kQuickGet32Instance : kQuickSet32Instance)
           : (is_get ? kQuickGet32Static : kQuickSet32Static);
       break;
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       entrypoint = is_instance
           ? (is_get ? kQuickGetObjInstance : kQuickSetObjInstance)
           : (is_get ? kQuickGetObjStatic : kQuickSetObjStatic);
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       entrypoint = is_instance
           ? (is_get ? kQuickGet64Instance : kQuickSet64Instance)
           : (is_get ? kQuickGet64Static : kQuickSet64Static);
@@ -529,7 +531,7 @@
   }
   InvokeRuntime(entrypoint, field_access, dex_pc, nullptr);
 
-  if (is_get && Primitive::IsFloatingPointType(field_type)) {
+  if (is_get && DataType::IsFloatingPointType(field_type)) {
     MoveLocation(locations->Out(), calling_convention.GetReturnLocation(field_type), field_type);
   }
 }
@@ -779,8 +781,8 @@
       return;
     }
     if (instruction->IsRem()) {
-      Primitive::Type type = instruction->AsRem()->GetResultType();
-      if ((type == Primitive::kPrimFloat) || (type == Primitive::kPrimDouble)) {
+      DataType::Type type = instruction->AsRem()->GetResultType();
+      if ((type == DataType::Type::kFloat32) || (type == DataType::Type::kFloat64)) {
         return;
       }
     }
@@ -1051,7 +1053,7 @@
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(id);
           stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
-          if (current->GetType() == Primitive::kPrimLong) {
+          if (current->GetType() == DataType::Type::kInt64) {
             stack_map_stream_.AddDexRegisterEntry(
                 DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
             ++i;
@@ -1059,7 +1061,7 @@
           }
         } else {
           stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
-          if (current->GetType() == Primitive::kPrimLong) {
+          if (current->GetType() == DataType::Type::kInt64) {
             stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegisterHigh, id);
             ++i;
             DCHECK_LT(i, environment_size);
@@ -1073,7 +1075,7 @@
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(id);
           stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
-          if (current->GetType() == Primitive::kPrimDouble) {
+          if (current->GetType() == DataType::Type::kFloat64) {
             stack_map_stream_.AddDexRegisterEntry(
                 DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
             ++i;
@@ -1081,7 +1083,7 @@
           }
         } else {
           stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
-          if (current->GetType() == Primitive::kPrimDouble) {
+          if (current->GetType() == DataType::Type::kFloat64) {
             stack_map_stream_.AddDexRegisterEntry(
                 DexRegisterLocation::Kind::kInFpuRegisterHigh, id);
             ++i;
@@ -1225,7 +1227,7 @@
     LiveInterval* interval = current->GetLiveInterval();
     // We only need to clear bits of loop phis containing objects and allocated in register.
     // Loop phis allocated on stack already have the object in the stack.
-    if (current->GetType() == Primitive::kPrimNot
+    if (current->GetType() == DataType::Type::kReference
         && interval->HasRegister()
         && interval->HasSpillSlot()) {
       locations->ClearStackBit(interval->GetSpillSlot() / kVRegSize);
@@ -1235,10 +1237,10 @@
 
 void CodeGenerator::EmitParallelMoves(Location from1,
                                       Location to1,
-                                      Primitive::Type type1,
+                                      DataType::Type type1,
                                       Location from2,
                                       Location to2,
-                                      Primitive::Type type2) {
+                                      DataType::Type type2) {
   HParallelMove parallel_move(GetGraph()->GetArena());
   parallel_move.AddMove(from1, to1, type1, nullptr);
   parallel_move.AddMove(from2, to2, type2, nullptr);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 30c2b52..ac3c839 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -61,9 +61,12 @@
 class CodeGenerator;
 class CompilerDriver;
 class CompilerOptions;
-class LinkerPatch;
 class ParallelMoveResolver;
 
+namespace linker {
+class LinkerPatch;
+}  // namespace linker
+
 class CodeAllocator {
  public:
   CodeAllocator() {}
@@ -143,8 +146,8 @@
 
 class InvokeDexCallingConventionVisitor {
  public:
-  virtual Location GetNextLocation(Primitive::Type type) = 0;
-  virtual Location GetReturnLocation(Primitive::Type type) const = 0;
+  virtual Location GetNextLocation(DataType::Type type) = 0;
+  virtual Location GetReturnLocation(DataType::Type type) const = 0;
   virtual Location GetMethodLocation() const = 0;
 
  protected:
@@ -166,9 +169,9 @@
  public:
   virtual Location GetObjectLocation() const = 0;
   virtual Location GetFieldIndexLocation() const = 0;
-  virtual Location GetReturnLocation(Primitive::Type type) const = 0;
-  virtual Location GetSetValueLocation(Primitive::Type type, bool is_instance) const = 0;
-  virtual Location GetFpuLocation(Primitive::Type type) const = 0;
+  virtual Location GetReturnLocation(DataType::Type type) const = 0;
+  virtual Location GetSetValueLocation(DataType::Type type, bool is_instance) const = 0;
+  virtual Location GetFpuLocation(DataType::Type type) const = 0;
   virtual ~FieldAccessCallingConvention() {}
 
  protected:
@@ -205,12 +208,12 @@
 
   virtual void Initialize() = 0;
   virtual void Finalize(CodeAllocator* allocator);
-  virtual void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches);
+  virtual void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches);
   virtual void GenerateFrameEntry() = 0;
   virtual void GenerateFrameExit() = 0;
   virtual void Bind(HBasicBlock* block) = 0;
   virtual void MoveConstant(Location destination, int32_t value) = 0;
-  virtual void MoveLocation(Location dst, Location src, Primitive::Type dst_type) = 0;
+  virtual void MoveLocation(Location dst, Location src, DataType::Type dst_type) = 0;
   virtual void AddLocationAsTemp(Location location, LocationSummary* locations) = 0;
 
   virtual Assembler* GetAssembler() = 0;
@@ -262,7 +265,7 @@
   virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0;
   virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0;
 
-  virtual bool NeedsTwoRegisters(Primitive::Type type) const = 0;
+  virtual bool NeedsTwoRegisters(DataType::Type type) const = 0;
   // Returns whether we should split long moves in parallel moves.
   virtual bool ShouldSplitLongMoves() const { return false; }
 
@@ -404,15 +407,15 @@
 
   void EmitParallelMoves(Location from1,
                          Location to1,
-                         Primitive::Type type1,
+                         DataType::Type type1,
                          Location from2,
                          Location to2,
-                         Primitive::Type type2);
+                         DataType::Type type2);
 
-  static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
+  static bool StoreNeedsWriteBarrier(DataType::Type type, HInstruction* value) {
     // Check that null value is not represented as an integer constant.
-    DCHECK(type != Primitive::kPrimNot || !value->IsIntConstant());
-    return type == Primitive::kPrimNot && !value->IsNullConstant();
+    DCHECK(type != DataType::Type::kReference || !value->IsIntConstant());
+    return type == DataType::Type::kReference && !value->IsNullConstant();
   }
 
 
@@ -501,12 +504,12 @@
 
   void CreateUnresolvedFieldLocationSummary(
       HInstruction* field_access,
-      Primitive::Type field_type,
+      DataType::Type field_type,
       const FieldAccessCallingConvention& calling_convention);
 
   void GenerateUnresolvedFieldAccess(
       HInstruction* field_access,
-      Primitive::Type field_type,
+      DataType::Type field_type,
       uint32_t field_index,
       uint32_t dex_pc,
       const FieldAccessCallingConvention& calling_convention);
@@ -570,7 +573,7 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) = 0;
 
   // Copy the result of a call into the given target.
-  virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0;
+  virtual void MoveFromReturnRegister(Location trg, DataType::Type type) = 0;
 
   virtual void GenerateNop() = 0;
 
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 8814cfc..42e9f68 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -31,6 +31,7 @@
 #include "intrinsics.h"
 #include "intrinsics_arm64.h"
 #include "linker/arm64/relative_patcher_arm64.h"
+#include "linker/linker_patch.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
@@ -143,24 +144,24 @@
   }
 }
 
-Location ARM64ReturnLocation(Primitive::Type return_type) {
+Location ARM64ReturnLocation(DataType::Type return_type) {
   // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
   // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
   // but we use the exact registers for clarity.
-  if (return_type == Primitive::kPrimFloat) {
+  if (return_type == DataType::Type::kFloat32) {
     return LocationFrom(s0);
-  } else if (return_type == Primitive::kPrimDouble) {
+  } else if (return_type == DataType::Type::kFloat64) {
     return LocationFrom(d0);
-  } else if (return_type == Primitive::kPrimLong) {
+  } else if (return_type == DataType::Type::kInt64) {
     return LocationFrom(x0);
-  } else if (return_type == Primitive::kPrimVoid) {
+  } else if (return_type == DataType::Type::kVoid) {
     return Location::NoLocation();
   } else {
     return LocationFrom(w0);
   }
 }
 
-Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
+Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type return_type) {
   return ARM64ReturnLocation(return_type);
 }
 
@@ -264,9 +265,12 @@
     // We're moving two locations to locations that could overlap, so we need a parallel
     // move resolver.
     InvokeRuntimeCallingConvention calling_convention;
-    codegen->EmitParallelMoves(
-        locations->InAt(0), LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimInt,
-        locations->InAt(1), LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimInt);
+    codegen->EmitParallelMoves(locations->InAt(0),
+                               LocationFrom(calling_convention.GetRegisterAt(0)),
+                               DataType::Type::kInt32,
+                               locations->InAt(1),
+                               LocationFrom(calling_convention.GetRegisterAt(1)),
+                               DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -355,7 +359,7 @@
     // Move the class to the desired location.
     if (out.IsValid()) {
       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
-      Primitive::Type type = instruction_->GetType();
+      DataType::Type type = instruction_->GetType();
       arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
     }
     RestoreLiveRegisters(codegen, locations);
@@ -375,7 +379,7 @@
       {
         SingleEmissionCheckScope guard(arm64_codegen->GetVIXLAssembler());
         __ Bind(strp_label);
-        __ str(RegisterFrom(locations->Out(), Primitive::kPrimNot),
+        __ str(RegisterFrom(locations->Out(), DataType::Type::kReference),
                MemOperand(bss_entry_temp_, /* offset placeholder */ 0));
       }
     }
@@ -426,7 +430,7 @@
     __ Mov(calling_convention.GetRegisterAt(0).W(), string_index.index_);
     arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
-    Primitive::Type type = instruction_->GetType();
+    DataType::Type type = instruction_->GetType();
     arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
 
     RestoreLiveRegisters(codegen, locations);
@@ -445,7 +449,7 @@
     {
       SingleEmissionCheckScope guard(arm64_codegen->GetVIXLAssembler());
       __ Bind(strp_label);
-      __ str(RegisterFrom(locations->Out(), Primitive::kPrimNot),
+      __ str(RegisterFrom(locations->Out(), DataType::Type::kReference),
              MemOperand(temp_, /* offset placeholder */ 0));
     }
 
@@ -552,14 +556,14 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                LocationFrom(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimNot,
+                               DataType::Type::kReference,
                                locations->InAt(1),
                                LocationFrom(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       arm64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
-      Primitive::Type ret_type = instruction_->GetType();
+      DataType::Type ret_type = instruction_->GetType();
       Location ret_loc = calling_convention.GetReturnLocation(ret_type);
       arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
     } else {
@@ -620,17 +624,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         LocationFrom(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         LocationFrom(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         LocationFrom(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -1199,7 +1203,7 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
     LocationSummary* locations = instruction_->GetLocations();
-    Primitive::Type type = Primitive::kPrimNot;
+    DataType::Type type = DataType::Type::kReference;
     DCHECK(locations->CanCall());
     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
     DCHECK(instruction_->IsInstanceFieldGet() ||
@@ -1228,7 +1232,7 @@
       // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
       if (instruction_->IsArrayGet()) {
         // Compute the actual memory offset and store it in `index`.
-        Register index_reg = RegisterFrom(index_, Primitive::kPrimInt);
+        Register index_reg = RegisterFrom(index_, DataType::Type::kInt32);
         DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_.reg()));
         if (codegen->IsCoreCalleeSaveRegister(index_.reg())) {
           // We are about to change the value of `index_reg` (see the
@@ -1267,7 +1271,7 @@
         // factor (2) cannot overflow in practice, as the runtime is
         // unable to allocate object arrays with a size larger than
         // 2^26 - 1 (that is, 2^28 - 4 bytes).
-        __ Lsl(index_reg, index_reg, Primitive::ComponentSizeShift(type));
+        __ Lsl(index_reg, index_reg, DataType::SizeShift(type));
         static_assert(
             sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
             "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -1302,7 +1306,7 @@
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             LocationFrom(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -1364,7 +1368,7 @@
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     LocationSummary* locations = instruction_->GetLocations();
-    Primitive::Type type = Primitive::kPrimNot;
+    DataType::Type type = DataType::Type::kReference;
     DCHECK(locations->CanCall());
     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
     DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
@@ -1386,7 +1390,7 @@
     //       type);
     //
     // which would emit a 32-bit move, as `type` is a (32-bit wide)
-    // reference type (`Primitive::kPrimNot`).
+    // reference type (`DataType::Type::kReference`).
     __ Mov(calling_convention.GetRegisterAt(0), XRegisterFrom(out_));
     arm64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
                                  instruction_,
@@ -1410,26 +1414,26 @@
 
 #undef __
 
-Location InvokeDexCallingConventionVisitorARM64::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorARM64::GetNextLocation(DataType::Type type) {
   Location next_location;
-  if (type == Primitive::kPrimVoid) {
+  if (type == DataType::Type::kVoid) {
     LOG(FATAL) << "Unreachable type " << type;
   }
 
-  if (Primitive::IsFloatingPointType(type) &&
+  if (DataType::IsFloatingPointType(type) &&
       (float_index_ < calling_convention.GetNumberOfFpuRegisters())) {
     next_location = LocationFrom(calling_convention.GetFpuRegisterAt(float_index_++));
-  } else if (!Primitive::IsFloatingPointType(type) &&
+  } else if (!DataType::IsFloatingPointType(type) &&
              (gp_index_ < calling_convention.GetNumberOfRegisters())) {
     next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
   } else {
     size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
-    next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
-                                                 : Location::StackSlot(stack_offset);
+    next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
+                                                : Location::StackSlot(stack_offset);
   }
 
   // Space on the stack is reserved for all arguments.
-  stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
+  stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
   return next_location;
 }
 
@@ -1546,7 +1550,7 @@
 
 void ParallelMoveResolverARM64::EmitMove(size_t index) {
   MoveOperands* move = moves_[index];
-  codegen_->MoveLocation(move->GetDestination(), move->GetSource(), Primitive::kPrimVoid);
+  codegen_->MoveLocation(move->GetDestination(), move->GetSource(), DataType::Type::kVoid);
 }
 
 void CodeGeneratorARM64::GenerateFrameEntry() {
@@ -1637,7 +1641,7 @@
 
 void CodeGeneratorARM64::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
-  __ Mov(RegisterFrom(location, Primitive::kPrimInt), value);
+  __ Mov(RegisterFrom(location, DataType::Type::kInt32), value);
 }
 
 void CodeGeneratorARM64::AddLocationAsTemp(Location location, LocationSummary* locations) {
@@ -1744,15 +1748,15 @@
 }
 
 
-static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
+static bool CoherentConstantAndType(Location constant, DataType::Type type) {
   DCHECK(constant.IsConstant());
   HConstant* cst = constant.GetConstant();
-  return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
+  return (cst->IsIntConstant() && type == DataType::Type::kInt32) ||
          // Null is mapped to a core W register, which we associate with kPrimInt.
-         (cst->IsNullConstant() && type == Primitive::kPrimInt) ||
-         (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
-         (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
-         (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
+         (cst->IsNullConstant() && type == DataType::Type::kInt32) ||
+         (cst->IsLongConstant() && type == DataType::Type::kInt64) ||
+         (cst->IsFloatConstant() && type == DataType::Type::kFloat32) ||
+         (cst->IsDoubleConstant() && type == DataType::Type::kFloat64);
 }
 
 // Allocate a scratch register from the VIXL pool, querying first
@@ -1770,7 +1774,7 @@
 
 void CodeGeneratorARM64::MoveLocation(Location destination,
                                       Location source,
-                                      Primitive::Type dst_type) {
+                                      DataType::Type dst_type) {
   if (source.Equals(destination)) {
     return;
   }
@@ -1779,7 +1783,7 @@
   // locations. When moving from and to a register, the argument type can be
   // used to generate 32bit instead of 64bit moves. In debug mode we also
   // checks the coherency of the locations and the type.
-  bool unspecified_type = (dst_type == Primitive::kPrimVoid);
+  bool unspecified_type = (dst_type == DataType::Type::kVoid);
 
   if (destination.IsRegister() || destination.IsFpuRegister()) {
     if (unspecified_type) {
@@ -1789,17 +1793,17 @@
                                   || src_cst->IsFloatConstant()
                                   || src_cst->IsNullConstant()))) {
         // For stack slots and 32bit constants, a 64bit type is appropriate.
-        dst_type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
+        dst_type = destination.IsRegister() ? DataType::Type::kInt32 : DataType::Type::kFloat32;
       } else {
         // If the source is a double stack slot or a 64bit constant, a 64bit
         // type is appropriate. Else the source is a register, and since the
         // type has not been specified, we chose a 64bit type to force a 64bit
         // move.
-        dst_type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
+        dst_type = destination.IsRegister() ? DataType::Type::kInt64 : DataType::Type::kFloat64;
       }
     }
-    DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(dst_type)) ||
-           (destination.IsRegister() && !Primitive::IsFloatingPointType(dst_type)));
+    DCHECK((destination.IsFpuRegister() && DataType::IsFloatingPointType(dst_type)) ||
+           (destination.IsRegister() && !DataType::IsFloatingPointType(dst_type)));
     CPURegister dst = CPURegisterFrom(destination, dst_type);
     if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
       DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
@@ -1814,17 +1818,17 @@
         __ Mov(Register(dst), RegisterFrom(source, dst_type));
       } else {
         DCHECK(destination.IsFpuRegister());
-        Primitive::Type source_type = Primitive::Is64BitType(dst_type)
-            ? Primitive::kPrimLong
-            : Primitive::kPrimInt;
+        DataType::Type source_type = DataType::Is64BitType(dst_type)
+            ? DataType::Type::kInt64
+            : DataType::Type::kInt32;
         __ Fmov(FPRegisterFrom(destination, dst_type), RegisterFrom(source, source_type));
       }
     } else {
       DCHECK(source.IsFpuRegister());
       if (destination.IsRegister()) {
-        Primitive::Type source_type = Primitive::Is64BitType(dst_type)
-            ? Primitive::kPrimDouble
-            : Primitive::kPrimFloat;
+        DataType::Type source_type = DataType::Is64BitType(dst_type)
+            ? DataType::Type::kFloat64
+            : DataType::Type::kFloat32;
         __ Fmov(RegisterFrom(destination, dst_type), FPRegisterFrom(source, source_type));
       } else {
         DCHECK(destination.IsFpuRegister());
@@ -1858,13 +1862,14 @@
     if (source.IsRegister() || source.IsFpuRegister()) {
       if (unspecified_type) {
         if (source.IsRegister()) {
-          dst_type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
+          dst_type = destination.IsStackSlot() ? DataType::Type::kInt32 : DataType::Type::kInt64;
         } else {
-          dst_type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
+          dst_type =
+              destination.IsStackSlot() ? DataType::Type::kFloat32 : DataType::Type::kFloat64;
         }
       }
-      DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(dst_type)) &&
-             (source.IsFpuRegister() == Primitive::IsFloatingPointType(dst_type)));
+      DCHECK((destination.IsDoubleStackSlot() == DataType::Is64BitType(dst_type)) &&
+             (source.IsFpuRegister() == DataType::IsFloatingPointType(dst_type)));
       __ Str(CPURegisterFrom(source, dst_type), StackOperandFrom(destination));
     } else if (source.IsConstant()) {
       DCHECK(unspecified_type || CoherentConstantAndType(source, dst_type))
@@ -1919,31 +1924,31 @@
   }
 }
 
-void CodeGeneratorARM64::Load(Primitive::Type type,
+void CodeGeneratorARM64::Load(DataType::Type type,
                               CPURegister dst,
                               const MemOperand& src) {
   switch (type) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       __ Ldrb(Register(dst), src);
       break;
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       __ Ldrsb(Register(dst), src);
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ Ldrsh(Register(dst), src);
       break;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       __ Ldrh(Register(dst), src);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
+      DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
       __ Ldr(dst, src);
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 }
@@ -1955,7 +1960,7 @@
   MacroAssembler* masm = GetVIXLAssembler();
   UseScratchRegisterScope temps(masm);
   Register temp_base = temps.AcquireX();
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   DCHECK(!src.IsPreIndex());
   DCHECK(!src.IsPostIndex());
@@ -1966,7 +1971,7 @@
     // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
     MemOperand base = MemOperand(temp_base);
     switch (type) {
-      case Primitive::kPrimBoolean:
+      case DataType::Type::kBool:
         {
           ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
           __ ldarb(Register(dst), base);
@@ -1975,7 +1980,7 @@
           }
         }
         break;
-      case Primitive::kPrimByte:
+      case DataType::Type::kInt8:
         {
           ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
           __ ldarb(Register(dst), base);
@@ -1983,9 +1988,9 @@
             MaybeRecordImplicitNullCheck(instruction);
           }
         }
-        __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
+        __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
         break;
-      case Primitive::kPrimChar:
+      case DataType::Type::kUint16:
         {
           ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
           __ ldarh(Register(dst), base);
@@ -1994,7 +1999,7 @@
           }
         }
         break;
-      case Primitive::kPrimShort:
+      case DataType::Type::kInt16:
         {
           ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
           __ ldarh(Register(dst), base);
@@ -2002,12 +2007,12 @@
             MaybeRecordImplicitNullCheck(instruction);
           }
         }
-        __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
+        __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
         break;
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimLong:
-        DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
+      case DataType::Type::kInt32:
+      case DataType::Type::kReference:
+      case DataType::Type::kInt64:
+        DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
         {
           ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
           __ ldar(Register(dst), base);
@@ -2016,10 +2021,10 @@
           }
         }
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble: {
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64: {
         DCHECK(dst.IsFPRegister());
-        DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
+        DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
 
         Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
         {
@@ -2032,39 +2037,39 @@
         __ Fmov(FPRegister(dst), temp);
         break;
       }
-      case Primitive::kPrimVoid:
+      case DataType::Type::kVoid:
         LOG(FATAL) << "Unreachable type " << type;
     }
   }
 }
 
-void CodeGeneratorARM64::Store(Primitive::Type type,
+void CodeGeneratorARM64::Store(DataType::Type type,
                                CPURegister src,
                                const MemOperand& dst) {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       __ Strb(Register(src), dst);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       __ Strh(Register(src), dst);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
+      DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
       __ Str(src, dst);
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 }
 
 void CodeGeneratorARM64::StoreRelease(HInstruction* instruction,
-                                      Primitive::Type type,
+                                      DataType::Type type,
                                       CPURegister src,
                                       const MemOperand& dst,
                                       bool needs_null_check) {
@@ -2081,8 +2086,8 @@
   MemOperand base = MemOperand(temp_base);
   // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       {
         ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
         __ stlrb(Register(src), base);
@@ -2091,8 +2096,8 @@
         }
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       {
         ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
         __ stlrh(Register(src), base);
@@ -2101,10 +2106,10 @@
         }
       }
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
-      DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
+      DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
       {
         ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
         __ stlr(Register(src), base);
@@ -2113,9 +2118,9 @@
         }
       }
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
-      DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
+      DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
       Register temp_src;
       if (src.IsZero()) {
         // The zero register is used to avoid synthesizing zero constants.
@@ -2134,7 +2139,7 @@
       }
       break;
     }
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 }
@@ -2268,17 +2273,17 @@
 void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
   DCHECK_EQ(instr->InputCount(), 2U);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, ARM64EncodableConstantOrRegister(instr->InputAt(1), instr));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -2294,7 +2299,7 @@
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_field_get_with_read_barrier ?
@@ -2317,7 +2322,7 @@
     }
   }
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister());
   } else {
     // The output overlaps for an object field get when read barriers
@@ -2336,13 +2341,14 @@
   Location base_loc = locations->InAt(0);
   Location out = locations->Out();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), field_info.GetFieldOffset());
 
-  if (field_type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (kEmitCompilerReadBarrier && kUseBakerReadBarrier &&
+      field_type == DataType::Type::kReference) {
     // Object FieldGet with Baker's read barrier case.
     // /* HeapReference<Object> */ out = *(base + offset)
-    Register base = RegisterFrom(base_loc, Primitive::kPrimNot);
+    Register base = RegisterFrom(base_loc, DataType::Type::kReference);
     Location maybe_temp =
         (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
     // Note that potential implicit null checks are handled in this
@@ -2369,7 +2375,7 @@
       codegen_->Load(field_type, OutputCPURegister(instruction), field);
       codegen_->MaybeRecordImplicitNullCheck(instruction);
     }
-    if (field_type == Primitive::kPrimNot) {
+    if (field_type == DataType::Type::kReference) {
       // If read barriers are enabled, emit read barriers other than
       // Baker's using a slow path (and also unpoison the loaded
       // reference, if heap poisoning is enabled).
@@ -2384,7 +2390,7 @@
   locations->SetInAt(0, Location::RequiresRegister());
   if (IsConstantZeroBitPattern(instruction->InputAt(1))) {
     locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
-  } else if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
+  } else if (DataType::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
     locations->SetInAt(1, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(1, Location::RequiresRegister());
@@ -2400,14 +2406,14 @@
   CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 1);
   CPURegister source = value;
   Offset offset = field_info.GetFieldOffset();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
 
   {
     // We use a block to end the scratch scope before the write barrier, thus
     // freeing the temporary registers so they can be used in `MarkGCCard`.
     UseScratchRegisterScope temps(GetVIXLAssembler());
 
-    if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+    if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
       DCHECK(value.IsW());
       Register temp = temps.AcquireW();
       __ Mov(temp, value.W());
@@ -2432,11 +2438,11 @@
 }
 
 void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
-  Primitive::Type type = instr->GetType();
+  DataType::Type type = instr->GetType();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       Register dst = OutputRegister(instr);
       Register lhs = InputRegisterAt(instr, 0);
       Operand rhs = InputOperandAt(instr, 1);
@@ -2465,8 +2471,8 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FPRegister dst = OutputFPRegister(instr);
       FPRegister lhs = InputFPRegisterAt(instr, 0);
       FPRegister rhs = InputFPRegisterAt(instr, 1);
@@ -2488,10 +2494,10 @@
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2505,16 +2511,16 @@
 void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
 
-  Primitive::Type type = instr->GetType();
+  DataType::Type type = instr->GetType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       Register dst = OutputRegister(instr);
       Register lhs = InputRegisterAt(instr, 0);
       Operand rhs = InputOperandAt(instr, 1);
       if (rhs.IsImmediate()) {
         uint32_t shift_value = rhs.GetImmediate() &
-            (type == Primitive::kPrimInt ? kMaxIntShiftDistance : kMaxLongShiftDistance);
+            (type == DataType::Type::kInt32 ? kMaxIntShiftDistance : kMaxLongShiftDistance);
         if (instr->IsShl()) {
           __ Lsl(dst, lhs, shift_value);
         } else if (instr->IsShr()) {
@@ -2557,7 +2563,7 @@
 }
 
 void LocationsBuilderARM64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instr) {
-  DCHECK(Primitive::IsIntegralType(instr->GetType())) << instr->GetType();
+  DCHECK(DataType::IsIntegralType(instr->GetType())) << instr->GetType();
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
   locations->SetInAt(0, Location::RequiresRegister());
   // There is no immediate variant of negated bitwise instructions in AArch64.
@@ -2587,8 +2593,8 @@
 
 void LocationsBuilderARM64::VisitDataProcWithShifterOp(
     HDataProcWithShifterOp* instruction) {
-  DCHECK(instruction->GetType() == Primitive::kPrimInt ||
-         instruction->GetType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
+         instruction->GetType() == DataType::Type::kInt64);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   if (instruction->GetInstrKind() == HInstruction::kNeg) {
@@ -2602,9 +2608,9 @@
 
 void InstructionCodeGeneratorARM64::VisitDataProcWithShifterOp(
     HDataProcWithShifterOp* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   HInstruction::InstructionKind kind = instruction->GetInstrKind();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
   Register out = OutputRegister(instruction);
   Register left;
   if (kind != HInstruction::kNeg) {
@@ -2730,7 +2736,7 @@
   // Avoid emitting code that could trigger Cortex A53's erratum 835769.
   // This fixup should be carried out for all multiply-accumulate instructions:
   // madd, msub, smaddl, smsubl, umaddl and umsubl.
-  if (instr->GetType() == Primitive::kPrimLong &&
+  if (instr->GetType() == DataType::Type::kInt64 &&
       codegen_->GetInstructionSetFeatures().NeedFixCortexA53_835769()) {
     MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen_)->GetVIXLAssembler();
     vixl::aarch64::Instruction* prev =
@@ -2759,7 +2765,7 @@
 
 void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier ?
@@ -2777,7 +2783,7 @@
       // constant index loads we need a temporary only if the offset is too big.
       uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
       uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
-      offset += index << Primitive::ComponentSizeShift(Primitive::kPrimNot);
+      offset += index << DataType::SizeShift(DataType::Type::kReference);
       if (offset >= kReferenceLoadMinFarOffset) {
         locations->AddTemp(FixedTempLocation());
       }
@@ -2787,7 +2793,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps in the case of an object array get with
@@ -2800,7 +2806,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   Register obj = InputRegisterAt(instruction, 0);
   LocationSummary* locations = instruction->GetLocations();
   Location index = locations->InAt(1);
@@ -2813,18 +2819,18 @@
 
   // The read barrier instrumentation of object ArrayGet instructions
   // does not support the HIntermediateAddress instruction.
-  DCHECK(!((type == Primitive::kPrimNot) &&
+  DCHECK(!((type == DataType::Type::kReference) &&
            instruction->GetArray()->IsIntermediateAddress() &&
            kEmitCompilerReadBarrier));
 
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // Object ArrayGet with Baker's read barrier case.
     // Note that a potential implicit null check is handled in the
     // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
     DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
     if (index.IsConstant()) {
       // Array load with a constant index can be treated as a field load.
-      offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+      offset += Int64ConstantFrom(index) << DataType::SizeShift(type);
       Location maybe_temp =
           (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
       codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
@@ -2876,7 +2882,7 @@
                 HeapOperand(obj, offset + (Int64ConstantFrom(index) << 1)));
         __ Bind(&done);
       } else {
-        offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+        offset += Int64ConstantFrom(index) << DataType::SizeShift(type);
         source = HeapOperand(obj, offset);
       }
     } else {
@@ -2906,7 +2912,7 @@
                 HeapOperand(temp, XRegisterFrom(index), LSL, 1));
         __ Bind(&done);
       } else {
-        source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+        source = HeapOperand(temp, XRegisterFrom(index), LSL, DataType::SizeShift(type));
       }
     }
     if (!maybe_compressed_char_at) {
@@ -2916,7 +2922,7 @@
       codegen_->MaybeRecordImplicitNullCheck(instruction);
     }
 
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       static_assert(
           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -2952,7 +2958,7 @@
 }
 
 void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
@@ -2964,7 +2970,7 @@
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   if (IsConstantZeroBitPattern(instruction->InputAt(2))) {
     locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
-  } else if (Primitive::IsFloatingPointType(value_type)) {
+  } else if (DataType::IsFloatingPointType(value_type)) {
     locations->SetInAt(2, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(2, Location::RequiresRegister());
@@ -2972,7 +2978,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   LocationSummary* locations = instruction->GetLocations();
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   bool needs_write_barrier =
@@ -2982,14 +2988,14 @@
   CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 2);
   CPURegister source = value;
   Location index = locations->InAt(1);
-  size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
+  size_t offset = mirror::Array::DataOffset(DataType::Size(value_type)).Uint32Value();
   MemOperand destination = HeapOperand(array);
   MacroAssembler* masm = GetVIXLAssembler();
 
   if (!needs_write_barrier) {
     DCHECK(!may_need_runtime_call_for_type_check);
     if (index.IsConstant()) {
-      offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
+      offset += Int64ConstantFrom(index) << DataType::SizeShift(value_type);
       destination = HeapOperand(array, offset);
     } else {
       UseScratchRegisterScope temps(masm);
@@ -3009,7 +3015,7 @@
       destination = HeapOperand(temp,
                                 XRegisterFrom(index),
                                 LSL,
-                                Primitive::ComponentSizeShift(value_type));
+                                DataType::SizeShift(value_type));
     }
     {
       // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
@@ -3027,13 +3033,13 @@
       UseScratchRegisterScope temps(masm);
       Register temp = temps.AcquireSameSizeAs(array);
       if (index.IsConstant()) {
-        offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
+        offset += Int64ConstantFrom(index) << DataType::SizeShift(value_type);
         destination = HeapOperand(array, offset);
       } else {
         destination = HeapOperand(temp,
                                   XRegisterFrom(index),
                                   LSL,
-                                  Primitive::ComponentSizeShift(value_type));
+                                  DataType::SizeShift(value_type));
       }
 
       uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
@@ -3213,21 +3219,21 @@
 void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  Primitive::Type in_type = compare->InputAt(0)->GetType();
+  DataType::Type in_type = compare->InputAt(0)->GetType();
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, ARM64EncodableConstantOrRegister(compare->InputAt(1), compare));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1,
                          IsFloatingPointZeroConstant(compare->InputAt(1))
@@ -3242,18 +3248,18 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
-  Primitive::Type in_type = compare->InputAt(0)->GetType();
+  DataType::Type in_type = compare->InputAt(0)->GetType();
 
   //  0 if: left == right
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       Register result = OutputRegister(compare);
       Register left = InputRegisterAt(compare, 0);
       Operand right = InputOperandAt(compare, 1);
@@ -3262,8 +3268,8 @@
       __ Cneg(result, result, lt);  // result == -1 if LT or unchanged otherwise
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       Register result = OutputRegister(compare);
       GenerateFcmp(compare);
       __ Cset(result, ne);
@@ -3278,7 +3284,7 @@
 void LocationsBuilderARM64::HandleCondition(HCondition* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
 
-  if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
     locations->SetInAt(1,
                        IsFloatingPointZeroConstant(instruction->InputAt(1))
@@ -3304,7 +3310,7 @@
   Register res = RegisterFrom(locations->Out(), instruction->GetType());
   IfCondition if_cond = instruction->GetCondition();
 
-  if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
     GenerateFcmp(instruction);
     __ Cset(res, ARM64FPCondition(if_cond, instruction->IsGtBias()));
   } else {
@@ -3383,7 +3389,7 @@
       __ Neg(out, Operand(out, ASR, ctz_imm));
     }
   } else {
-    int bits = instruction->GetResultType() == Primitive::kPrimInt ? 32 : 64;
+    int bits = instruction->GetResultType() == DataType::Type::kInt32 ? 32 : 64;
     __ Asr(temp, dividend, bits - 1);
     __ Lsr(temp, temp, bits - ctz_imm);
     __ Add(out, dividend, temp);
@@ -3403,19 +3409,20 @@
   Register dividend = InputRegisterAt(instruction, 0);
   int64_t imm = Int64FromConstant(second.GetConstant());
 
-  Primitive::Type type = instruction->GetResultType();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DataType::Type type = instruction->GetResultType();
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   int64_t magic;
   int shift;
-  CalculateMagicAndShiftForDivRem(imm, type == Primitive::kPrimLong /* is_long */, &magic, &shift);
+  CalculateMagicAndShiftForDivRem(
+      imm, type == DataType::Type::kInt64 /* is_long */, &magic, &shift);
 
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register temp = temps.AcquireSameSizeAs(out);
 
   // temp = get_high(dividend * magic)
   __ Mov(temp, magic);
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ Smulh(temp, dividend, temp);
   } else {
     __ Smull(temp.X(), dividend, temp);
@@ -3433,9 +3440,9 @@
   }
 
   if (instruction->IsDiv()) {
-    __ Sub(out, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+    __ Sub(out, temp, Operand(temp, ASR, type == DataType::Type::kInt64 ? 63 : 31));
   } else {
-    __ Sub(temp, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+    __ Sub(temp, temp, Operand(temp, ASR, type == DataType::Type::kInt64 ? 63 : 31));
     // TODO: Strength reduction for msub.
     Register temp_imm = temps.AcquireSameSizeAs(out);
     __ Mov(temp_imm, imm);
@@ -3445,8 +3452,8 @@
 
 void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  Primitive::Type type = instruction->GetResultType();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DataType::Type type = instruction->GetResultType();
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   LocationSummary* locations = instruction->GetLocations();
   Register out = OutputRegister(instruction);
@@ -3483,15 +3490,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3503,15 +3510,15 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
-  Primitive::Type type = div->GetResultType();
+  DataType::Type type = div->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       GenerateDivRemIntegral(div);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
       break;
 
@@ -3531,9 +3538,9 @@
   codegen_->AddSlowPath(slow_path);
   Location value = instruction->GetLocations()->InAt(0);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
-  if (!Primitive::IsIntegralType(type)) {
+  if (!DataType::IsIntegralType(type)) {
     LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
     return;
   }
@@ -3664,8 +3671,8 @@
     // the comparison and its condition as the branch condition.
     HCondition* condition = cond->AsCondition();
 
-    Primitive::Type type = condition->InputAt(0)->GetType();
-    if (Primitive::IsFloatingPointType(type)) {
+    DataType::Type type = condition->InputAt(0)->GetType();
+    if (DataType::IsFloatingPointType(type)) {
       GenerateFcmp(condition);
       if (true_target == nullptr) {
         IfCondition opposite_condition = condition->GetOppositeCondition();
@@ -3779,7 +3786,7 @@
 
 static inline bool IsConditionOnFloatingPointValues(HInstruction* condition) {
   return condition->IsCondition() &&
-         Primitive::IsFloatingPointType(condition->InputAt(0)->GetType());
+         DataType::IsFloatingPointType(condition->InputAt(0)->GetType());
 }
 
 static inline Condition GetConditionForSelect(HCondition* condition) {
@@ -3790,7 +3797,7 @@
 
 void LocationsBuilderARM64::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
     locations->SetInAt(1, Location::RequiresFpuRegister());
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3844,7 +3851,7 @@
     csel_cond = GetConditionForSelect(cond->AsCondition());
   }
 
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     __ Fcsel(OutputFPRegister(select),
              InputFPRegisterAt(select, 1),
              InputFPRegisterAt(select, 0),
@@ -4754,10 +4761,10 @@
   __ ldr(out, MemOperand(base, /* offset placeholder */ 0));
 }
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorARM64::EmitPcRelativeLinkerPatches(
     const ArenaDeque<PcRelativePatchInfo>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
     linker_patches->push_back(Factory(info.label.GetLocation(),
                                       &info.target_dex_file,
@@ -4766,7 +4773,7 @@
   }
 }
 
-void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       pc_relative_method_patches_.size() +
@@ -4778,28 +4785,28 @@
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
-                                                                  linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        pc_relative_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        pc_relative_string_patches_, linker_patches);
   } else {
     DCHECK(pc_relative_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        pc_relative_string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
-    linker_patches->push_back(LinkerPatch::BakerReadBarrierBranchPatch(info.label.GetLocation(),
-                                                                       info.custom_data));
+    linker_patches->push_back(linker::LinkerPatch::BakerReadBarrierBranchPatch(
+        info.label.GetLocation(), info.custom_data));
   }
   DCHECK_EQ(size, linker_patches->size());
 }
@@ -4912,8 +4919,8 @@
       InvokeRuntimeCallingConvention calling_convention;
       caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
       DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(),
-                RegisterFrom(calling_convention.GetReturnLocation(Primitive::kPrimNot),
-                             Primitive::kPrimNot).GetCode());
+                RegisterFrom(calling_convention.GetReturnLocation(DataType::Type::kReference),
+                             DataType::Type::kReference).GetCode());
       locations->SetCustomSlowPathCallerSaves(caller_saves);
     } else {
       // For non-Baker read barrier we have a temp-clobbering call.
@@ -5107,8 +5114,8 @@
         InvokeRuntimeCallingConvention calling_convention;
         caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
         DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(),
-                  RegisterFrom(calling_convention.GetReturnLocation(Primitive::kPrimNot),
-                               Primitive::kPrimNot).GetCode());
+                  RegisterFrom(calling_convention.GetReturnLocation(DataType::Type::kReference),
+                               DataType::Type::kReference).GetCode());
         locations->SetCustomSlowPathCallerSaves(caller_saves);
       } else {
         // For non-Baker read barrier we have a temp-clobbering call.
@@ -5240,15 +5247,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -5261,13 +5268,13 @@
 
 void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
       break;
 
@@ -5280,14 +5287,14 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, ARM64EncodableConstantOrRegister(neg->InputAt(0), neg));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -5299,13 +5306,13 @@
 
 void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
       break;
 
@@ -5342,7 +5349,7 @@
   } else {
     locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
   }
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
@@ -5378,8 +5385,8 @@
 
 void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
   switch (instruction->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
       break;
 
@@ -5486,22 +5493,22 @@
 }
 
 void LocationsBuilderARM64::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   LocationSummary::CallKind call_kind =
-      Primitive::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
+      DataType::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
                                            : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
       locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
@@ -5516,20 +5523,21 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GenerateDivRemIntegral(rem);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
-      QuickEntrypointEnum entrypoint = (type == Primitive::kPrimFloat) ? kQuickFmodf : kQuickFmod;
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
+      QuickEntrypointEnum entrypoint =
+          (type == DataType::Type::kFloat32) ? kQuickFmodf : kQuickFmod;
       codegen_->InvokeRuntime(entrypoint, rem, rem->GetDexPc());
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         CheckEntrypointTypes<kQuickFmodf, float, float, float>();
       } else {
         CheckEntrypointTypes<kQuickFmod, double, double, double>();
@@ -5562,7 +5570,7 @@
 
 void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  Primitive::Type return_type = instruction->InputAt(0)->GetType();
+  DataType::Type return_type = instruction->InputAt(0)->GetType();
   locations->SetInAt(0, ARM64ReturnLocation(return_type));
 }
 
@@ -5734,21 +5742,21 @@
 void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
-  Primitive::Type input_type = conversion->GetInputType();
-  Primitive::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
   DCHECK_NE(input_type, result_type);
-  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
-      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+  if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
+      (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
     LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
   }
 
-  if (Primitive::IsFloatingPointType(input_type)) {
+  if (DataType::IsFloatingPointType(input_type)) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(0, Location::RequiresRegister());
   }
 
-  if (Primitive::IsFloatingPointType(result_type)) {
+  if (DataType::IsFloatingPointType(result_type)) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -5756,18 +5764,18 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
 
   DCHECK_NE(input_type, result_type);
 
-  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
-    int result_size = Primitive::ComponentSize(result_type);
-    int input_size = Primitive::ComponentSize(input_type);
+  if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
+    int result_size = DataType::Size(result_type);
+    int input_size = DataType::Size(input_type);
     int min_size = std::min(result_size, input_size);
     Register output = OutputRegister(conversion);
     Register source = InputRegisterAt(conversion, 0);
-    if (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimLong) {
+    if (result_type == DataType::Type::kInt32 && input_type == DataType::Type::kInt64) {
       // 'int' values are used directly as W registers, discarding the top
       // bits, so we don't need to sign-extend and can just perform a move.
       // We do not pass the `kDiscardForSameWReg` argument to force clearing the
@@ -5776,21 +5784,21 @@
       // 32bit input value as a 64bit value assuming that the top 32 bits are
       // zero.
       __ Mov(output.W(), source.W());
-    } else if (result_type == Primitive::kPrimChar ||
-               (input_type == Primitive::kPrimChar && input_size < result_size)) {
+    } else if (result_type == DataType::Type::kUint16 ||
+               (input_type == DataType::Type::kUint16 && input_size < result_size)) {
       __ Ubfx(output,
               output.IsX() ? source.X() : source.W(),
-              0, Primitive::ComponentSize(Primitive::kPrimChar) * kBitsPerByte);
+              0, DataType::Size(DataType::Type::kUint16) * kBitsPerByte);
     } else {
       __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
     }
-  } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
+  } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
     __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
-  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
-    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
+  } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
+    CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
     __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
-  } else if (Primitive::IsFloatingPointType(result_type) &&
-             Primitive::IsFloatingPointType(input_type)) {
+  } else if (DataType::IsFloatingPointType(result_type) &&
+             DataType::IsFloatingPointType(input_type)) {
     __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
   } else {
     LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
@@ -5917,7 +5925,7 @@
     uint32_t offset,
     Location maybe_temp,
     ReadBarrierOption read_barrier_option) {
-  Primitive::Type type = Primitive::kPrimNot;
+  DataType::Type type = DataType::Type::kReference;
   Register out_reg = RegisterFrom(out, type);
   if (read_barrier_option == kWithReadBarrier) {
     CHECK(kEmitCompilerReadBarrier);
@@ -5957,7 +5965,7 @@
     uint32_t offset,
     Location maybe_temp,
     ReadBarrierOption read_barrier_option) {
-  Primitive::Type type = Primitive::kPrimNot;
+  DataType::Type type = DataType::Type::kReference;
   Register out_reg = RegisterFrom(out, type);
   Register obj_reg = RegisterFrom(obj, type);
   if (read_barrier_option == kWithReadBarrier) {
@@ -5994,7 +6002,7 @@
     vixl::aarch64::Label* fixup_label,
     ReadBarrierOption read_barrier_option) {
   DCHECK(fixup_label == nullptr || offset == 0u);
-  Register root_reg = RegisterFrom(root, Primitive::kPrimNot);
+  Register root_reg = RegisterFrom(root, DataType::Type::kReference);
   if (read_barrier_option == kWithReadBarrier) {
     DCHECK(kEmitCompilerReadBarrier);
     if (kUseBakerReadBarrier) {
@@ -6158,7 +6166,7 @@
       static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
                     "Field LDR must be 1 instruction (4B) before the return address label; "
                     " 2 instructions (8B) for heap poisoning.");
-      Register ref_reg = RegisterFrom(ref, Primitive::kPrimNot);
+      Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
       __ ldr(ref_reg, MemOperand(base.X(), offset));
       if (needs_null_check) {
         MaybeRecordImplicitNullCheck(instruction);
@@ -6198,7 +6206,7 @@
   static_assert(
       sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
       "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
-  size_t scale_factor = Primitive::ComponentSizeShift(Primitive::kPrimNot);
+  size_t scale_factor = DataType::SizeShift(DataType::Type::kReference);
 
   if (kBakerReadBarrierLinkTimeThunksEnableForArrays &&
       !Runtime::Current()->UseJitCompilation()) {
@@ -6223,8 +6231,8 @@
     //   gray_return_address:
 
     DCHECK(index.IsValid());
-    Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
-    Register ref_reg = RegisterFrom(ref, Primitive::kPrimNot);
+    Register index_reg = RegisterFrom(index, DataType::Type::kInt32);
+    Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
 
     UseScratchRegisterScope temps(GetVIXLAssembler());
     DCHECK(temps.IsAvailable(ip0));
@@ -6396,7 +6404,7 @@
                                                   bool needs_null_check,
                                                   bool use_load_acquire) {
   DCHECK(obj.IsW());
-  Primitive::Type type = Primitive::kPrimNot;
+  DataType::Type type = DataType::Type::kReference;
   Register ref_reg = RegisterFrom(ref, type);
 
   // If needed, vixl::EmissionCheckScope guards are used to ensure
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 69c5119..21da955 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -100,7 +100,7 @@
                                                           vixl::aarch64::kDRegSize,
                                                           vixl::aarch64::d8.GetCode(),
                                                           vixl::aarch64::d15.GetCode());
-Location ARM64ReturnLocation(Primitive::Type return_type);
+Location ARM64ReturnLocation(DataType::Type return_type);
 
 class SlowPathCodeARM64 : public SlowPathCode {
  public:
@@ -171,7 +171,7 @@
                           kRuntimeParameterFpuRegistersLength,
                           kArm64PointerSize) {}
 
-  Location GetReturnLocation(Primitive::Type return_type);
+  Location GetReturnLocation(DataType::Type return_type);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
@@ -187,7 +187,7 @@
                           kParameterFPRegistersLength,
                           kArm64PointerSize) {}
 
-  Location GetReturnLocation(Primitive::Type return_type) const {
+  Location GetReturnLocation(DataType::Type return_type) const {
     return ARM64ReturnLocation(return_type);
   }
 
@@ -201,8 +201,8 @@
   InvokeDexCallingConventionVisitorARM64() {}
   virtual ~InvokeDexCallingConventionVisitorARM64() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type return_type) const OVERRIDE {
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type return_type) const OVERRIDE {
     return calling_convention.GetReturnLocation(return_type);
   }
   Location GetMethodLocation() const OVERRIDE;
@@ -223,16 +223,16 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return helpers::LocationFrom(vixl::aarch64::x0);
   }
-  Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return helpers::LocationFrom(vixl::aarch64::x0);
   }
-  Location GetSetValueLocation(Primitive::Type type ATTRIBUTE_UNUSED,
+  Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,
                                bool is_instance) const OVERRIDE {
     return is_instance
         ? helpers::LocationFrom(vixl::aarch64::x2)
         : helpers::LocationFrom(vixl::aarch64::x1);
   }
-  Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return helpers::LocationFrom(vixl::aarch64::d0);
   }
 
@@ -498,13 +498,13 @@
   // Code generation helpers.
   void MoveConstant(vixl::aarch64::CPURegister destination, HConstant* constant);
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
-  void Load(Primitive::Type type,
+  void Load(DataType::Type type,
             vixl::aarch64::CPURegister dst,
             const vixl::aarch64::MemOperand& src);
-  void Store(Primitive::Type type,
+  void Store(DataType::Type type,
              vixl::aarch64::CPURegister src,
              const vixl::aarch64::MemOperand& dst);
   void LoadAcquire(HInstruction* instruction,
@@ -512,7 +512,7 @@
                    const vixl::aarch64::MemOperand& src,
                    bool needs_null_check);
   void StoreRelease(HInstruction* instruction,
-                    Primitive::Type type,
+                    DataType::Type type,
                     vixl::aarch64::CPURegister src,
                     const vixl::aarch64::MemOperand& dst,
                     bool needs_null_check);
@@ -531,7 +531,7 @@
 
   ParallelMoveResolverARM64* GetMoveResolver() OVERRIDE { return &move_resolver_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return false;
   }
 
@@ -557,7 +557,7 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
-                              Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
+                              DataType::Type type ATTRIBUTE_UNUSED) OVERRIDE {
     UNIMPLEMENTED(FATAL);
   }
 
@@ -627,7 +627,7 @@
                                 vixl::aarch64::Register out,
                                 vixl::aarch64::Register base);
 
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
 
   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
 
@@ -805,9 +805,9 @@
 
   void EmitJumpTables();
 
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
-                                          ArenaVector<LinkerPatch>* linker_patches);
+                                          ArenaVector<linker::LinkerPatch>* linker_patches);
 
   // Labels for each block that will be compiled.
   // We use a deque so that the `vixl::aarch64::Label` objects do not move in memory.
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index baf68c4..2b9e0fe 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -30,6 +30,7 @@
 #include "heap_poisoning.h"
 #include "intrinsics_arm_vixl.h"
 #include "linker/arm/relative_patcher_thumb2.h"
+#include "linker/linker_patch.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "thread.h"
@@ -449,10 +450,10 @@
     codegen->EmitParallelMoves(
         locations->InAt(0),
         LocationFrom(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         locations->InAt(1),
         LocationFrom(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt);
+        DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -640,10 +641,10 @@
 
     codegen->EmitParallelMoves(locations->InAt(0),
                                LocationFrom(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimNot,
+                               DataType::Type::kReference,
                                locations->InAt(1),
                                LocationFrom(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
                                  instruction_,
@@ -714,17 +715,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         LocationFrom(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         LocationFrom(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         LocationFrom(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -1364,16 +1365,16 @@
     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
     parallel_move.AddMove(ref_,
                           LocationFrom(calling_convention.GetRegisterAt(0)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     parallel_move.AddMove(obj_,
                           LocationFrom(calling_convention.GetRegisterAt(1)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             LocationFrom(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -1640,7 +1641,7 @@
 
 static void GenerateLongDataProc(HDataProcWithShifterOp* instruction,
                                  CodeGeneratorARMVIXL* codegen) {
-  DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64);
   DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
 
   const LocationSummary* const locations = instruction->GetLocations();
@@ -1775,12 +1776,12 @@
     // care here.
     DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
 
-    const Primitive::Type type = instruction->InputAt(0)->GetType();
+    const DataType::Type type = instruction->InputAt(0)->GetType();
 
-    if (type == Primitive::kPrimFloat) {
+    if (type == DataType::Type::kFloat32) {
       __ Vcmp(F32, InputSRegisterAt(instruction, 0), 0.0);
     } else {
-      DCHECK_EQ(type, Primitive::kPrimDouble);
+      DCHECK_EQ(type, DataType::Type::kFloat64);
       __ Vcmp(F64, InputDRegisterAt(instruction, 0), 0.0);
     }
   } else {
@@ -1820,7 +1821,7 @@
     HCondition* condition,
     bool invert,
     CodeGeneratorARMVIXL* codegen) {
-  DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(condition->GetLeft()->GetType(), DataType::Type::kInt64);
 
   const LocationSummary* const locations = condition->GetLocations();
   IfCondition cond = condition->GetCondition();
@@ -1941,7 +1942,7 @@
     HCondition* condition,
     bool invert,
     CodeGeneratorARMVIXL* codegen) {
-  DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(condition->GetLeft()->GetType(), DataType::Type::kInt64);
 
   const LocationSummary* const locations = condition->GetLocations();
   IfCondition cond = condition->GetCondition();
@@ -2011,7 +2012,7 @@
 static std::pair<vixl32::Condition, vixl32::Condition> GenerateTest(HCondition* condition,
                                                                     bool invert,
                                                                     CodeGeneratorARMVIXL* codegen) {
-  const Primitive::Type type = condition->GetLeft()->GetType();
+  const DataType::Type type = condition->GetLeft()->GetType();
   IfCondition cond = condition->GetCondition();
   IfCondition opposite = condition->GetOppositeCondition();
   std::pair<vixl32::Condition, vixl32::Condition> ret(eq, ne);
@@ -2020,17 +2021,17 @@
     std::swap(cond, opposite);
   }
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     ret = condition->GetLocations()->InAt(1).IsConstant()
         ? GenerateLongTestConstant(condition, invert, codegen)
         : GenerateLongTest(condition, invert, codegen);
-  } else if (Primitive::IsFloatingPointType(type)) {
+  } else if (DataType::IsFloatingPointType(type)) {
     GenerateVcmp(condition, codegen);
     __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR);
     ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
                          ARMFPCondition(opposite, condition->IsGtBias()));
   } else {
-    DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+    DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
     __ Cmp(InputRegisterAt(condition, 0), InputOperandAt(condition, 1));
     ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
   }
@@ -2066,7 +2067,7 @@
 }
 
 static void GenerateEqualLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) {
-  DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(cond->GetLeft()->GetType(), DataType::Type::kInt64);
 
   const LocationSummary* const locations = cond->GetLocations();
   IfCondition condition = cond->GetCondition();
@@ -2122,7 +2123,7 @@
 }
 
 static void GenerateConditionLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) {
-  DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(cond->GetLeft()->GetType(), DataType::Type::kInt64);
 
   const LocationSummary* const locations = cond->GetLocations();
   IfCondition condition = cond->GetCondition();
@@ -2187,11 +2188,11 @@
 
 static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond,
                                                     CodeGeneratorARMVIXL* codegen) {
-  const Primitive::Type type = cond->GetLeft()->GetType();
+  const DataType::Type type = cond->GetLeft()->GetType();
 
-  DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+  DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     GenerateConditionLong(cond, codegen);
     return;
   }
@@ -2277,12 +2278,12 @@
 }
 
 static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
-  const Primitive::Type type = constant->GetType();
+  const DataType::Type type = constant->GetType();
   bool ret = false;
 
-  DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+  DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     const uint64_t value = Uint64ConstantFrom(constant);
 
     ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
@@ -2294,7 +2295,7 @@
 }
 
 static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
-  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
+  DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
 
   if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
     return Location::ConstantLocation(constant->AsConstant());
@@ -2595,14 +2596,14 @@
   __ Bind(GetLabelOf(block));
 }
 
-Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       uint32_t index = gp_index_++;
       uint32_t stack_index = stack_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2612,7 +2613,7 @@
       }
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t index = gp_index_;
       uint32_t stack_index = stack_index_;
       gp_index_ += 2;
@@ -2635,7 +2636,7 @@
       }
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t stack_index = stack_index_++;
       if (float_index_ % 2 == 0) {
         float_index_ = std::max(double_index_, float_index_);
@@ -2647,7 +2648,7 @@
       }
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
       uint32_t stack_index = stack_index_;
       stack_index_ += 2;
@@ -2664,37 +2665,37 @@
       }
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
       break;
   }
   return Location::NoLocation();
 }
 
-Location InvokeDexCallingConventionVisitorARMVIXL::GetReturnLocation(Primitive::Type type) const {
+Location InvokeDexCallingConventionVisitorARMVIXL::GetReturnLocation(DataType::Type type) const {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       return LocationFrom(r0);
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       return LocationFrom(s0);
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       return LocationFrom(r0, r1);
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       return LocationFrom(s0, s1);
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       return Location::NoLocation();
   }
 
@@ -2752,7 +2753,7 @@
   __ Mov(RegisterFrom(location), value);
 }
 
-void CodeGeneratorARMVIXL::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
+void CodeGeneratorARMVIXL::MoveLocation(Location dst, Location src, DataType::Type dst_type) {
   // TODO(VIXL): Maybe refactor to have the 'move' implementation here and use it in
   // `ParallelMoveResolverARMVIXL::EmitMove`, as is done in the `arm64` backend.
   HParallelMove move(GetGraph()->GetArena());
@@ -2935,8 +2936,8 @@
 
     // If this is a long or FP comparison that has been folded into
     // the HCondition, generate the comparison directly.
-    Primitive::Type type = condition->InputAt(0)->GetType();
-    if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+    DataType::Type type = condition->InputAt(0)->GetType();
+    if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
       GenerateCompareTestAndBranch(condition, true_target, false_target, far_target);
       return;
     }
@@ -3027,7 +3028,7 @@
 
 void LocationsBuilderARMVIXL::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
-  const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
+  const bool is_floating_point = DataType::IsFloatingPointType(select->GetType());
 
   if (is_floating_point) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
@@ -3055,7 +3056,7 @@
 void InstructionCodeGeneratorARMVIXL::VisitSelect(HSelect* select) {
   HInstruction* const condition = select->GetCondition();
   const LocationSummary* const locations = select->GetLocations();
-  const Primitive::Type type = select->GetType();
+  const DataType::Type type = select->GetType();
   const Location first = locations->InAt(0);
   const Location out = locations->Out();
   const Location second = locations->InAt(1);
@@ -3072,7 +3073,7 @@
     return;
   }
 
-  if (!Primitive::IsFloatingPointType(type)) {
+  if (!DataType::IsFloatingPointType(type)) {
     bool invert = false;
 
     if (out.Equals(second)) {
@@ -3260,7 +3261,7 @@
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   // Handle the long/FP comparisons made in instruction simplification.
   switch (cond->InputAt(0)->GetType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
       if (!cond->IsEmittedAtUseSite()) {
@@ -3268,8 +3269,8 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
       if (!cond->IsEmittedAtUseSite()) {
@@ -3291,22 +3292,22 @@
     return;
   }
 
-  const Primitive::Type type = cond->GetLeft()->GetType();
+  const DataType::Type type = cond->GetLeft()->GetType();
 
-  if (Primitive::IsFloatingPointType(type)) {
+  if (DataType::IsFloatingPointType(type)) {
     GenerateConditionGeneric(cond, codegen_);
     return;
   }
 
-  DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+  DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
 
   const IfCondition condition = cond->GetCondition();
 
   // A condition with only one boolean input, or two boolean inputs without being equality or
   // inequality results from transformations done by the instruction simplifier, and is handled
   // as a regular condition with integral inputs.
-  if (type == Primitive::kPrimBoolean &&
-      cond->GetRight()->GetType() == Primitive::kPrimBoolean &&
+  if (type == DataType::Type::kBool &&
+      cond->GetRight()->GetType() == DataType::Type::kBool &&
       (condition == kCondEQ || condition == kCondNE)) {
     vixl32::Register left = InputRegisterAt(cond, 0);
     const vixl32::Register out = OutputRegister(cond);
@@ -3669,19 +3670,19 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -3696,11 +3697,11 @@
   Location out = locations->Out();
   Location in = locations->InAt(0);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ Rsb(OutputRegister(neg), InputRegisterAt(neg, 0), 0);
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
       __ Rsbs(LowRegisterFrom(out), LowRegisterFrom(in), 0);
       // We cannot emit an RSC (Reverse Subtract with Carry)
@@ -3714,8 +3715,8 @@
       __ Sub(HighRegisterFrom(out), HighRegisterFrom(out), HighRegisterFrom(in));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Vneg(OutputVRegister(neg), InputVRegister(neg));
       break;
 
@@ -3725,16 +3726,16 @@
 }
 
 void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
 
   // The float-to-long, double-to-long and long-to-float type conversions
   // rely on a call to the runtime.
   LocationSummary::CallKind call_kind =
-      (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
-        && result_type == Primitive::kPrimLong)
-       || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
+      (((input_type == DataType::Type::kFloat32 || input_type == DataType::Type::kFloat64)
+        && result_type == DataType::Type::kInt64)
+       || (input_type == DataType::Type::kInt64 && result_type == DataType::Type::kFloat32))
       ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
   LocationSummary* locations =
@@ -3744,15 +3745,15 @@
   // our bit representation makes it safe.
 
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to byte is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -3764,15 +3765,15 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -3784,22 +3785,22 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
           locations->AddTemp(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
@@ -3812,20 +3813,20 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
           break;
 
-        case Primitive::kPrimFloat: {
+        case DataType::Type::kFloat32: {
           // Processing a Dex `float-to-long' instruction.
           InvokeRuntimeCallingConventionARMVIXL calling_convention;
           locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
@@ -3833,7 +3834,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat64: {
           // Processing a Dex `double-to-long' instruction.
           InvokeRuntimeCallingConventionARMVIXL calling_convention;
           locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0),
@@ -3848,15 +3849,15 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to char is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `int-to-char' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -3868,20 +3869,20 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-float' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong: {
+        case DataType::Type::kInt64: {
           // Processing a Dex `long-to-float' instruction.
           InvokeRuntimeCallingConventionARMVIXL calling_convention;
           locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0),
@@ -3890,7 +3891,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3902,20 +3903,20 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-double' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-double' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
@@ -3923,7 +3924,7 @@
           locations->AddTemp(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3945,21 +3946,21 @@
   LocationSummary* locations = conversion->GetLocations();
   Location out = locations->Out();
   Location in = locations->InAt(0);
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to byte is a result of code transformations.
           __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 8);
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 8);
           break;
@@ -3970,17 +3971,17 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
           __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
           break;
@@ -3991,9 +3992,9 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           DCHECK(out.IsRegister());
           if (in.IsRegisterPair()) {
@@ -4011,7 +4012,7 @@
           }
           break;
 
-        case Primitive::kPrimFloat: {
+        case DataType::Type::kFloat32: {
           // Processing a Dex `float-to-int' instruction.
           vixl32::SRegister temp = LowSRegisterFrom(locations->GetTemp(0));
           __ Vcvt(S32, F32, temp, InputSRegisterAt(conversion, 0));
@@ -4019,7 +4020,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat64: {
           // Processing a Dex `double-to-int' instruction.
           vixl32::SRegister temp_s = LowSRegisterFrom(locations->GetTemp(0));
           __ Vcvt(S32, F64, temp_s, DRegisterFrom(in));
@@ -4033,14 +4034,14 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           DCHECK(out.IsRegisterPair());
           DCHECK(in.IsRegister());
@@ -4049,13 +4050,13 @@
           __ Asr(HighRegisterFrom(out), LowRegisterFrom(out), 31);
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-long' instruction.
           codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-long' instruction.
           codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
@@ -4067,17 +4068,17 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to char is a result of code transformations.
           __ Ubfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `int-to-char' instruction.
           __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
           break;
@@ -4088,27 +4089,27 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar: {
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16: {
           // Processing a Dex `int-to-float' instruction.
           __ Vmov(OutputSRegister(conversion), InputRegisterAt(conversion, 0));
           __ Vcvt(F32, S32, OutputSRegister(conversion), OutputSRegister(conversion));
           break;
         }
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-float' instruction.
           codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
           CheckEntrypointTypes<kQuickL2f, float, int64_t>();
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           __ Vcvt(F32, F64, OutputSRegister(conversion), DRegisterFrom(in));
           break;
@@ -4119,21 +4120,21 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar: {
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16: {
           // Processing a Dex `int-to-double' instruction.
           __ Vmov(LowSRegisterFrom(out), InputRegisterAt(conversion, 0));
           __ Vcvt(F64, S32, DRegisterFrom(out), LowSRegisterFrom(out));
           break;
         }
 
-        case Primitive::kPrimLong: {
+        case DataType::Type::kInt64: {
           // Processing a Dex `long-to-double' instruction.
           vixl32::Register low = LowRegisterFrom(in);
           vixl32::Register high = HighRegisterFrom(in);
@@ -4156,7 +4157,7 @@
           break;
         }
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           __ Vcvt(F64, F32, DRegisterFrom(out), InputSRegisterAt(conversion, 0));
           break;
@@ -4177,22 +4178,22 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -4211,12 +4212,12 @@
   Location second = locations->InAt(1);
 
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       __ Add(OutputRegister(add), InputRegisterAt(add, 0), InputOperandAt(add, 1));
       }
       break;
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsConstant()) {
         uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
         GenerateAddLongConst(out, first, value);
@@ -4228,8 +4229,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Vadd(OutputVRegister(add), InputVRegisterAt(add, 0), InputVRegisterAt(add, 1));
       break;
 
@@ -4242,21 +4243,21 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -4273,12 +4274,12 @@
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       __ Sub(OutputRegister(sub), InputRegisterAt(sub, 0), InputOperandAt(sub, 1));
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsConstant()) {
         uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
         GenerateAddLongConst(out, first, -value);
@@ -4290,8 +4291,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Vsub(OutputVRegister(sub), InputVRegisterAt(sub, 0), InputVRegisterAt(sub, 1));
       break;
 
@@ -4304,16 +4305,16 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:  {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:  {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -4331,11 +4332,11 @@
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       vixl32::Register out_hi = HighRegisterFrom(out);
       vixl32::Register out_lo = LowRegisterFrom(out);
       vixl32::Register in1_hi = HighRegisterFrom(first);
@@ -4368,8 +4369,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Vmul(OutputVRegister(mul), InputVRegisterAt(mul, 0), InputVRegisterAt(mul, 1));
       break;
 
@@ -4380,7 +4381,7 @@
 
 void InstructionCodeGeneratorARMVIXL::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
 
   Location second = instruction->GetLocations()->InAt(1);
   DCHECK(second.IsConstant());
@@ -4403,7 +4404,7 @@
 
 void InstructionCodeGeneratorARMVIXL::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -4437,7 +4438,7 @@
 
 void InstructionCodeGeneratorARMVIXL::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -4480,7 +4481,7 @@
 void InstructionCodeGeneratorARMVIXL::GenerateDivRemConstantIntegral(
     HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
 
   Location second = instruction->GetLocations()->InAt(1);
   DCHECK(second.IsConstant());
@@ -4500,12 +4501,12 @@
 
 void LocationsBuilderARMVIXL::VisitDiv(HDiv* div) {
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
-  if (div->GetResultType() == Primitive::kPrimLong) {
+  if (div->GetResultType() == DataType::Type::kInt64) {
     // pLdiv runtime call.
     call_kind = LocationSummary::kCallOnMainOnly;
-  } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
+  } else if (div->GetResultType() == DataType::Type::kInt32 && div->InputAt(1)->IsConstant()) {
     // sdiv will be replaced by other instruction sequence.
-  } else if (div->GetResultType() == Primitive::kPrimInt &&
+  } else if (div->GetResultType() == DataType::Type::kInt32 &&
              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // pIdivmod runtime call.
     call_kind = LocationSummary::kCallOnMainOnly;
@@ -4514,7 +4515,7 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
 
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (div->InputAt(1)->IsConstant()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
@@ -4542,7 +4543,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConventionARMVIXL calling_convention;
       locations->SetInAt(0, LocationFrom(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -4551,8 +4552,8 @@
       locations->SetOut(LocationFrom(r0, r1));
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -4569,7 +4570,7 @@
   Location rhs = div->GetLocations()->InAt(1);
 
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (rhs.IsConstant()) {
         GenerateDivRemConstantIntegral(div);
       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
@@ -4586,7 +4587,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConventionARMVIXL calling_convention;
       DCHECK(calling_convention.GetRegisterAt(0).Is(LowRegisterFrom(lhs)));
       DCHECK(calling_convention.GetRegisterAt(1).Is(HighRegisterFrom(lhs)));
@@ -4600,8 +4601,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Vdiv(OutputVRegister(div), InputVRegisterAt(div, 0), InputVRegisterAt(div, 1));
       break;
 
@@ -4611,14 +4612,14 @@
 }
 
 void LocationsBuilderARMVIXL::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
 
   // Most remainders are implemented in the runtime.
   LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
-  if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
+  if (rem->GetResultType() == DataType::Type::kInt32 && rem->InputAt(1)->IsConstant()) {
     // sdiv will be replaced by other instruction sequence.
     call_kind = LocationSummary::kNoCall;
-  } else if ((rem->GetResultType() == Primitive::kPrimInt)
+  } else if ((rem->GetResultType() == DataType::Type::kInt32)
              && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // Have hardware divide instruction for int, do it with three instructions.
     call_kind = LocationSummary::kNoCall;
@@ -4627,7 +4628,7 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (rem->InputAt(1)->IsConstant()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
@@ -4656,7 +4657,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConventionARMVIXL calling_convention;
       locations->SetInAt(0, LocationFrom(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -4666,7 +4667,7 @@
       locations->SetOut(LocationFrom(r2, r3));
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       InvokeRuntimeCallingConventionARMVIXL calling_convention;
       locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
       locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
@@ -4674,7 +4675,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       InvokeRuntimeCallingConventionARMVIXL calling_convention;
       locations->SetInAt(0, LocationFrom(
           calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
@@ -4693,9 +4694,9 @@
   LocationSummary* locations = rem->GetLocations();
   Location second = locations->InAt(1);
 
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
         vixl32::Register reg1 = InputRegisterAt(rem, 0);
         vixl32::Register out_reg = OutputRegister(rem);
         if (second.IsConstant()) {
@@ -4720,19 +4721,19 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
         CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
       CheckEntrypointTypes<kQuickFmodf, float, float, float>();
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
       CheckEntrypointTypes<kQuickFmod, double, double, double>();
       break;
@@ -4758,11 +4759,11 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32: {
       if (value.IsRegister()) {
         __ CompareAndBranchIfZero(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
       } else {
@@ -4773,7 +4774,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (value.IsRegisterPair()) {
         UseScratchRegisterScope temps(GetVIXLAssembler());
         vixl32::Register temp = temps.Acquire();
@@ -4890,13 +4891,13 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
   switch (ror->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       if (ror->InputAt(1)->IsConstant()) {
         locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
@@ -4914,13 +4915,13 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitRor(HRor* ror) {
-  Primitive::Type type = ror->GetResultType();
+  DataType::Type type = ror->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       HandleIntegerRotate(ror);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       HandleLongRotate(ror);
       break;
     }
@@ -4937,7 +4938,7 @@
       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
 
   switch (op->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       if (op->InputAt(1)->IsConstant()) {
         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
@@ -4950,7 +4951,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       if (op->InputAt(1)->IsConstant()) {
         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
@@ -4977,9 +4978,9 @@
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
 
-  Primitive::Type type = op->GetResultType();
+  DataType::Type type = op->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       vixl32::Register out_reg = OutputRegister(op);
       vixl32::Register first_reg = InputRegisterAt(op, 0);
       if (second.IsRegister()) {
@@ -5008,7 +5009,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       vixl32::Register o_h = HighRegisterFrom(out);
       vixl32::Register o_l = LowRegisterFrom(out);
 
@@ -5257,11 +5258,11 @@
   Location out = locations->Out();
   Location in = locations->InAt(0);
   switch (not_->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ Mvn(OutputRegister(not_), InputRegisterAt(not_, 0));
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ Mvn(LowRegisterFrom(out), LowRegisterFrom(in));
       __ Mvn(HighRegisterFrom(out), HighRegisterFrom(in));
       break;
@@ -5286,20 +5287,20 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       // Output overlaps because it is written before doing the low comparison.
       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
       locations->SetOut(Location::RequiresRegister());
@@ -5318,21 +5319,21 @@
 
   vixl32::Label less, greater, done;
   vixl32::Label* final_label = codegen_->GetFinalLabel(compare, &done);
-  Primitive::Type type = compare->InputAt(0)->GetType();
+  DataType::Type type = compare->InputAt(0)->GetType();
   vixl32::Condition less_cond = vixl32::Condition(kNone);
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       // Emit move to `out` before the `Cmp`, as `Mov` might affect the status flags.
       __ Mov(out, 0);
       __ Cmp(RegisterFrom(left), RegisterFrom(right));  // Signed compare.
       less_cond = lt;
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       __ Cmp(HighRegisterFrom(left), HighRegisterFrom(right));  // Signed compare.
       __ B(lt, &less, /* far_target */ false);
       __ B(gt, &greater, /* far_target */ false);
@@ -5342,8 +5343,8 @@
       less_cond = lo;
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       __ Mov(out, 0);
       GenerateVcmp(compare, codegen_);
       // To branch on the FP compare result we transfer FPSCR to APSR (encoded as PC in VMRS).
@@ -5454,14 +5455,14 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
 
-  Primitive::Type field_type = field_info.GetFieldType();
-  if (Primitive::IsFloatingPointType(field_type)) {
+  DataType::Type field_type = field_info.GetFieldType();
+  if (DataType::IsFloatingPointType(field_type)) {
     locations->SetInAt(1, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(1, Location::RequiresRegister());
   }
 
-  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
+  bool is_wide = field_type == DataType::Type::kInt64 || field_type == DataType::Type::kFloat64;
   bool generate_volatile = field_info.IsVolatile()
       && is_wide
       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
@@ -5482,7 +5483,7 @@
 
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
-    if (field_type == Primitive::kPrimDouble) {
+    if (field_type == DataType::Type::kFloat64) {
       // For doubles we need two more registers to copy the value.
       locations->AddTemp(LocationFrom(r2));
       locations->AddTemp(LocationFrom(r3));
@@ -5501,7 +5502,7 @@
 
   bool is_volatile = field_info.IsVolatile();
   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
@@ -5511,25 +5512,25 @@
   }
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       GetAssembler()->StoreToOffset(kStoreByte, RegisterFrom(value), base, offset);
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       GetAssembler()->StoreToOffset(kStoreHalfword, RegisterFrom(value), base, offset);
       break;
     }
 
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       if (kPoisonHeapReferences && needs_write_barrier) {
         // Note that in the case where `value` is a null reference,
         // we do not enter this block, as a null reference does not
         // need poisoning.
-        DCHECK_EQ(field_type, Primitive::kPrimNot);
+        DCHECK_EQ(field_type, DataType::Type::kReference);
         vixl32::Register temp = RegisterFrom(locations->GetTemp(0));
         __ Mov(temp, RegisterFrom(value));
         GetAssembler()->PoisonHeapReference(temp);
@@ -5540,7 +5541,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (is_volatile && !atomic_ldrd_strd) {
         GenerateWideAtomicStore(base,
                                 offset,
@@ -5556,12 +5557,12 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       GetAssembler()->StoreSToOffset(SRegisterFrom(value), base, offset);
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       vixl32::DRegister value_reg = DRegisterFrom(value);
       if (is_volatile && !atomic_ldrd_strd) {
         vixl32::Register value_reg_lo = RegisterFrom(locations->GetTemp(0));
@@ -5583,13 +5584,13 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
 
   // Longs and doubles are handled in the switch.
-  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
+  if (field_type != DataType::Type::kInt64 && field_type != DataType::Type::kFloat64) {
     // TODO(VIXL): Here and for other calls to `MaybeRecordImplicitNullCheck` in this method, we
     // should use a scope and the assembler to emit the store instruction to guarantee that we
     // record the pc at the correct position. But the `Assembler` does not automatically handle
@@ -5614,7 +5615,7 @@
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (field_info.GetFieldType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_field_get_with_read_barrier ?
@@ -5626,17 +5627,18 @@
   locations->SetInAt(0, Location::RequiresRegister());
 
   bool volatile_for_double = field_info.IsVolatile()
-      && (field_info.GetFieldType() == Primitive::kPrimDouble)
+      && (field_info.GetFieldType() == DataType::Type::kFloat64)
       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   // The output overlaps in case of volatile long: we don't want the
   // code generated by GenerateWideAtomicLoad to overwrite the
   // object's location.  Likewise, in the case of an object field get
   // with read barriers enabled, we do not want the load to overwrite
   // the object's location, as we need it to emit the read barrier.
-  bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
+  bool overlap =
+      (field_info.IsVolatile() && (field_info.GetFieldType() == DataType::Type::kInt64)) ||
       object_field_get_with_read_barrier;
 
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister());
   } else {
     locations->SetOut(Location::RequiresRegister(),
@@ -5670,7 +5672,7 @@
 }
 
 Location LocationsBuilderARMVIXL::ArithmeticZeroOrFpuRegister(HInstruction* input) {
-  DCHECK(Primitive::IsFloatingPointType(input->GetType())) << input->GetType();
+  DCHECK(DataType::IsFloatingPointType(input->GetType())) << input->GetType();
   if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
       (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
     return Location::ConstantLocation(input->AsConstant());
@@ -5681,7 +5683,7 @@
 
 Location LocationsBuilderARMVIXL::ArmEncodableConstantOrRegister(HInstruction* constant,
                                                                  Opcode opcode) {
-  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
+  DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
   if (constant->IsConstant() &&
       CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
     return Location::ConstantLocation(constant->AsConstant());
@@ -5692,7 +5694,7 @@
 bool LocationsBuilderARMVIXL::CanEncodeConstantAsImmediate(HConstant* input_cst,
                                                            Opcode opcode) {
   uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
-  if (Primitive::Is64BitType(input_cst->GetType())) {
+  if (DataType::Is64BitType(input_cst->GetType())) {
     Opcode high_opcode = opcode;
     SetCc low_set_cc = kCcDontCare;
     switch (opcode) {
@@ -5757,31 +5759,31 @@
   Location out = locations->Out();
   bool is_volatile = field_info.IsVolatile();
   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       GetAssembler()->LoadFromOffset(kLoadUnsignedByte, RegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       GetAssembler()->LoadFromOffset(kLoadSignedByte, RegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       GetAssembler()->LoadFromOffset(kLoadSignedHalfword, RegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, RegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       GetAssembler()->LoadFromOffset(kLoadWord, RegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       // /* HeapReference<Object> */ out = *(base + offset)
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         Location temp_loc = locations->GetTemp(0);
@@ -5806,7 +5808,7 @@
       break;
     }
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (is_volatile && !atomic_ldrd_strd) {
         GenerateWideAtomicLoad(base, offset, LowRegisterFrom(out), HighRegisterFrom(out));
       } else {
@@ -5814,11 +5816,11 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       GetAssembler()->LoadSFromOffset(SRegisterFrom(out), base, offset);
       break;
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       vixl32::DRegister out_dreg = DRegisterFrom(out);
       if (is_volatile && !atomic_ldrd_strd) {
         vixl32::Register lo = RegisterFrom(locations->GetTemp(0));
@@ -5835,12 +5837,12 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
 
-  if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
+  if (field_type == DataType::Type::kReference || field_type == DataType::Type::kFloat64) {
     // Potential implicit null checks, in the case of reference or
     // double fields, are handled in the previous switch statement.
   } else {
@@ -5854,7 +5856,7 @@
   }
 
   if (is_volatile) {
-    if (field_type == Primitive::kPrimNot) {
+    if (field_type == DataType::Type::kReference) {
       // Memory barriers, in the case of references, are also handled
       // in the previous switch statement.
     } else {
@@ -5993,25 +5995,25 @@
   codegen_->GenerateNullCheck(instruction);
 }
 
-static LoadOperandType GetLoadOperandType(Primitive::Type type) {
+static LoadOperandType GetLoadOperandType(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       return kLoadWord;
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       return kLoadUnsignedByte;
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       return kLoadSignedByte;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       return kLoadUnsignedHalfword;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       return kLoadSignedHalfword;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       return kLoadWord;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       return kLoadWordPair;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       return kLoadSWord;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       return kLoadDWord;
     default:
       LOG(FATAL) << "Unreachable type " << type;
@@ -6019,23 +6021,23 @@
   }
 }
 
-static StoreOperandType GetStoreOperandType(Primitive::Type type) {
+static StoreOperandType GetStoreOperandType(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       return kStoreWord;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       return kStoreByte;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       return kStoreHalfword;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       return kStoreWord;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       return kStoreWordPair;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       return kStoreSWord;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       return kStoreDWord;
     default:
       LOG(FATAL) << "Unreachable type " << type;
@@ -6043,66 +6045,66 @@
   }
 }
 
-void CodeGeneratorARMVIXL::LoadFromShiftedRegOffset(Primitive::Type type,
+void CodeGeneratorARMVIXL::LoadFromShiftedRegOffset(DataType::Type type,
                                                     Location out_loc,
                                                     vixl32::Register base,
                                                     vixl32::Register reg_index,
                                                     vixl32::Condition cond) {
-  uint32_t shift_count = Primitive::ComponentSizeShift(type);
+  uint32_t shift_count = DataType::SizeShift(type);
   MemOperand mem_address(base, reg_index, vixl32::LSL, shift_count);
 
   switch (type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       __ Ldrsb(cond, RegisterFrom(out_loc), mem_address);
       break;
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       __ Ldrb(cond, RegisterFrom(out_loc), mem_address);
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ Ldrsh(cond, RegisterFrom(out_loc), mem_address);
       break;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       __ Ldrh(cond, RegisterFrom(out_loc), mem_address);
       break;
-    case Primitive::kPrimNot:
-    case Primitive::kPrimInt:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt32:
       __ Ldr(cond, RegisterFrom(out_loc), mem_address);
       break;
     // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
     default:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
 }
 
-void CodeGeneratorARMVIXL::StoreToShiftedRegOffset(Primitive::Type type,
+void CodeGeneratorARMVIXL::StoreToShiftedRegOffset(DataType::Type type,
                                                    Location loc,
                                                    vixl32::Register base,
                                                    vixl32::Register reg_index,
                                                    vixl32::Condition cond) {
-  uint32_t shift_count = Primitive::ComponentSizeShift(type);
+  uint32_t shift_count = DataType::SizeShift(type);
   MemOperand mem_address(base, reg_index, vixl32::LSL, shift_count);
 
   switch (type) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kInt8:
+    case DataType::Type::kBool:
       __ Strb(cond, RegisterFrom(loc), mem_address);
       break;
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
       __ Strh(cond, RegisterFrom(loc), mem_address);
       break;
-    case Primitive::kPrimNot:
-    case Primitive::kPrimInt:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt32:
       __ Str(cond, RegisterFrom(loc), mem_address);
       break;
     // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
     default:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
@@ -6111,7 +6113,7 @@
 
 void LocationsBuilderARMVIXL::VisitArrayGet(HArrayGet* instruction) {
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier ?
@@ -6122,7 +6124,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps in the case of an object array get with
@@ -6143,7 +6145,7 @@
       // constant index loads we need a temporary only if the offset is too big.
       uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
       uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
-      offset += index << Primitive::ComponentSizeShift(Primitive::kPrimNot);
+      offset += index << DataType::SizeShift(DataType::Type::kReference);
       if (offset >= kReferenceLoadMinFarOffset) {
         locations->AddTemp(Location::RequiresRegister());
       }
@@ -6172,18 +6174,18 @@
   Location index = locations->InAt(1);
   Location out_loc = locations->Out();
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
                                         instruction->IsStringCharAt();
   HInstruction* array_instr = instruction->GetArray();
   bool has_intermediate_address = array_instr->IsIntermediateAddress();
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       vixl32::Register length;
       if (maybe_compressed_char_at) {
         length = RegisterFrom(locations->GetTemp(0));
@@ -6206,7 +6208,7 @@
                                          data_offset + const_index);
           __ B(final_label);
           __ Bind(&uncompressed_load);
-          GetAssembler()->LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
+          GetAssembler()->LoadFromOffset(GetLoadOperandType(DataType::Type::kUint16),
                                          RegisterFrom(out_loc),
                                          obj,
                                          data_offset + (const_index << 1));
@@ -6214,7 +6216,7 @@
             __ Bind(&done);
           }
         } else {
-          uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
+          uint32_t full_offset = data_offset + (const_index << DataType::SizeShift(type));
 
           LoadOperandType load_type = GetLoadOperandType(type);
           GetAssembler()->LoadFromOffset(load_type, RegisterFrom(out_loc), obj, full_offset);
@@ -6256,7 +6258,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       // The read barrier instrumentation of object ArrayGet
       // instructions does not support the HIntermediateAddress
       // instruction.
@@ -6274,7 +6276,7 @@
         DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
         if (index.IsConstant()) {
           // Array load with a constant index can be treated as a field load.
-          data_offset += Int32ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+          data_offset += Int32ConstantFrom(index) << DataType::SizeShift(type);
           codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
                                                           out_loc,
                                                           obj,
@@ -6333,7 +6335,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (index.IsConstant()) {
         size_t offset =
             (Int32ConstantFrom(index) << TIMES_8) + data_offset;
@@ -6347,7 +6349,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       vixl32::SRegister out = SRegisterFrom(out_loc);
       if (index.IsConstant()) {
         size_t offset = (Int32ConstantFrom(index) << TIMES_4) + data_offset;
@@ -6361,7 +6363,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (index.IsConstant()) {
         size_t offset = (Int32ConstantFrom(index) << TIMES_8) + data_offset;
         GetAssembler()->LoadDFromOffset(DRegisterFrom(out_loc), obj, offset);
@@ -6374,12 +6376,12 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Potential implicit null checks, in the case of reference
     // arrays, are handled in the previous switch statement.
   } else if (!maybe_compressed_char_at) {
@@ -6390,7 +6392,7 @@
 }
 
 void LocationsBuilderARMVIXL::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -6404,7 +6406,7 @@
 
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(value_type)) {
+  if (DataType::IsFloatingPointType(value_type)) {
     locations->SetInAt(2, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(2, Location::RequiresRegister());
@@ -6420,26 +6422,26 @@
   LocationSummary* locations = instruction->GetLocations();
   vixl32::Register array = InputRegisterAt(instruction, 0);
   Location index = locations->InAt(1);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
   uint32_t data_offset =
-      mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
+      mirror::Array::DataOffset(DataType::Size(value_type)).Uint32Value();
   Location value_loc = locations->InAt(2);
   HInstruction* array_instr = instruction->GetArray();
   bool has_intermediate_address = array_instr->IsIntermediateAddress();
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       if (index.IsConstant()) {
         int32_t const_index = Int32ConstantFrom(index);
         uint32_t full_offset =
-            data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
+            data_offset + (const_index << DataType::SizeShift(value_type));
         StoreOperandType store_type = GetStoreOperandType(value_type);
         GetAssembler()->StoreToOffset(store_type, RegisterFrom(value_loc), array, full_offset);
       } else {
@@ -6463,7 +6465,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       vixl32::Register value = RegisterFrom(value_loc);
       // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
       // See the comment in instruction_simplifier_shared.cc.
@@ -6576,7 +6578,7 @@
         // Note that in the case where `value` is a null reference,
         // we do not enter this block, as a null reference does not
         // need poisoning.
-        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        DCHECK_EQ(value_type, DataType::Type::kReference);
         __ Mov(temp1, value);
         GetAssembler()->PoisonHeapReference(temp1);
         source = temp1;
@@ -6617,7 +6619,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Location value = locations->InAt(2);
       if (index.IsConstant()) {
         size_t offset =
@@ -6632,7 +6634,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       Location value = locations->InAt(2);
       DCHECK(value.IsFpuRegister());
       if (index.IsConstant()) {
@@ -6647,7 +6649,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       Location value = locations->InAt(2);
       DCHECK(value.IsFpuRegisterPair());
       if (index.IsConstant()) {
@@ -6662,13 +6664,13 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << value_type;
       UNREACHABLE();
   }
 
   // Objects are handled in the switch.
-  if (value_type != Primitive::kPrimNot) {
+  if (value_type != DataType::Type::kReference) {
     // TODO(VIXL): Ensure we record the pc position immediately after the preceding store
     // instruction.
     codegen_->MaybeRecordImplicitNullCheck(instruction);
@@ -7965,7 +7967,7 @@
       // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
       // to further check that this component type is not a primitive type.
       GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
-      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
+      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
       __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
       break;
     }
@@ -8060,8 +8062,8 @@
 void LocationsBuilderARMVIXL::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
-         || instruction->GetResultType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32
+         || instruction->GetResultType() == DataType::Type::kInt64);
   // Note: GVN reorders commutative operations to have the constant on the right hand side.
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
@@ -8083,8 +8085,8 @@
 void LocationsBuilderARMVIXL::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
-         || instruction->GetResultType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32
+         || instruction->GetResultType() == DataType::Type::kInt64);
 
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
@@ -8097,7 +8099,7 @@
   Location second = locations->InAt(1);
   Location out = locations->Out();
 
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     vixl32::Register first_reg = RegisterFrom(first);
     vixl32::Register second_reg = RegisterFrom(second);
     vixl32::Register out_reg = RegisterFrom(out);
@@ -8118,7 +8120,7 @@
     return;
 
   } else {
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
     vixl32::Register first_low = LowRegisterFrom(first);
     vixl32::Register first_high = HighRegisterFrom(first);
     vixl32::Register second_low = LowRegisterFrom(second);
@@ -8146,11 +8148,11 @@
 
 void LocationsBuilderARMVIXL::VisitDataProcWithShifterOp(
     HDataProcWithShifterOp* instruction) {
-  DCHECK(instruction->GetType() == Primitive::kPrimInt ||
-         instruction->GetType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
+         instruction->GetType() == DataType::Type::kInt64);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
+  const bool overlap = instruction->GetType() == DataType::Type::kInt64 &&
                        HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
 
   locations->SetInAt(0, Location::RequiresRegister());
@@ -8165,10 +8167,10 @@
   const HInstruction::InstructionKind kind = instruction->GetInstrKind();
   const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
 
-  if (instruction->GetType() == Primitive::kPrimInt) {
+  if (instruction->GetType() == DataType::Type::kInt32) {
     const vixl32::Register first = InputRegisterAt(instruction, 0);
     const vixl32::Register output = OutputRegister(instruction);
-    const vixl32::Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
+    const vixl32::Register second = instruction->InputAt(1)->GetType() == DataType::Type::kInt64
         ? LowRegisterFrom(locations->InAt(1))
         : InputRegisterAt(instruction, 1);
 
@@ -8202,7 +8204,7 @@
                                   codegen_);
     }
   } else {
-    DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64);
 
     if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
       const vixl32::Register second = InputRegisterAt(instruction, 1);
@@ -8318,7 +8320,7 @@
   if (second.IsConstant()) {
     uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
     uint32_t value_low = Low32Bits(value);
-    if (instruction->GetResultType() == Primitive::kPrimInt) {
+    if (instruction->GetResultType() == DataType::Type::kInt32) {
       vixl32::Register first_reg = InputRegisterAt(instruction, 0);
       vixl32::Register out_reg = OutputRegister(instruction);
       if (instruction->IsAnd()) {
@@ -8330,7 +8332,7 @@
         GenerateEorConst(out_reg, first_reg, value_low);
       }
     } else {
-      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+      DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
       uint32_t value_high = High32Bits(value);
       vixl32::Register first_low = LowRegisterFrom(first);
       vixl32::Register first_high = HighRegisterFrom(first);
@@ -8351,7 +8353,7 @@
     return;
   }
 
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     vixl32::Register first_reg = InputRegisterAt(instruction, 0);
     vixl32::Register second_reg = InputRegisterAt(instruction, 1);
     vixl32::Register out_reg = OutputRegister(instruction);
@@ -8364,7 +8366,7 @@
       __ Eor(out_reg, first_reg, second_reg);
     }
   } else {
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
     vixl32::Register first_low = LowRegisterFrom(first);
     vixl32::Register first_high = HighRegisterFrom(first);
     vixl32::Register second_low = LowRegisterFrom(second);
@@ -8589,7 +8591,7 @@
     //   gray_return_address:
 
     DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>));
-    vixl32::Register ref_reg = RegisterFrom(ref, Primitive::kPrimNot);
+    vixl32::Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
     bool narrow = CanEmitNarrowLdr(ref_reg, obj, offset);
     vixl32::Register base = obj;
     if (offset >= kReferenceLoadMinFarOffset) {
@@ -8685,9 +8687,9 @@
     //   gray_return_address:
 
     DCHECK(index.IsValid());
-    vixl32::Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
-    vixl32::Register ref_reg = RegisterFrom(ref, Primitive::kPrimNot);
-    vixl32::Register data_reg = RegisterFrom(temp, Primitive::kPrimInt);  // Raw pointer.
+    vixl32::Register index_reg = RegisterFrom(index, DataType::Type::kInt32);
+    vixl32::Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
+    vixl32::Register data_reg = RegisterFrom(temp, DataType::Type::kInt32);  // Raw pointer.
     DCHECK(!data_reg.Is(kBakerCcEntrypointRegister));
 
     UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -8835,7 +8837,7 @@
                                                     Location index,
                                                     ScaleFactor scale_factor,
                                                     bool needs_null_check) {
-  Primitive::Type type = Primitive::kPrimNot;
+  DataType::Type type = DataType::Type::kReference;
   vixl32::Register ref_reg = RegisterFrom(ref, type);
 
   // If needed, vixl::EmissionCheckScope guards are used to ensure
@@ -9191,10 +9193,10 @@
       });
 }
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorARMVIXL::EmitPcRelativeLinkerPatches(
     const ArenaDeque<PcRelativePatchInfo>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
     const DexFile& dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
@@ -9211,7 +9213,7 @@
   }
 }
 
-void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() +
@@ -9223,28 +9225,28 @@
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
-                                                                  linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        pc_relative_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        pc_relative_string_patches_, linker_patches);
   } else {
     DCHECK(pc_relative_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        pc_relative_string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
-    linker_patches->push_back(LinkerPatch::BakerReadBarrierBranchPatch(info.label.GetLocation(),
-                                                                       info.custom_data));
+    linker_patches->push_back(linker::LinkerPatch::BakerReadBarrierBranchPatch(
+        info.label.GetLocation(), info.custom_data));
   }
   DCHECK_EQ(size, linker_patches->size());
 }
@@ -9391,13 +9393,13 @@
 }
 
 // Copy the result of a call into the given target.
-void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) {
+void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, DataType::Type type) {
   if (!trg.IsValid()) {
-    DCHECK_EQ(type, Primitive::kPrimVoid);
+    DCHECK_EQ(type, DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
   Location return_loc = InvokeDexCallingConventionVisitorARMVIXL().GetReturnLocation(type);
   if (return_loc.Equals(trg)) {
@@ -9406,9 +9408,9 @@
 
   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
   //       with the last branch.
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     TODO_VIXL32(FATAL);
-  } else if (type == Primitive::kPrimDouble) {
+  } else if (type == DataType::Type::kFloat64) {
     TODO_VIXL32(FATAL);
   } else {
     // Let the parallel move resolver take care of all of this.
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index e78bc15..58b8525 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -173,8 +173,8 @@
   InvokeDexCallingConventionVisitorARMVIXL() {}
   virtual ~InvokeDexCallingConventionVisitorARMVIXL() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE;
   Location GetMethodLocation() const OVERRIDE;
 
  private:
@@ -194,20 +194,20 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return helpers::LocationFrom(vixl::aarch32::r0);
   }
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? helpers::LocationFrom(vixl::aarch32::r0, vixl::aarch32::r1)
         : helpers::LocationFrom(vixl::aarch32::r0);
   }
-  Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetSetValueLocation(DataType::Type type, bool is_instance) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3)
         : (is_instance
             ? helpers::LocationFrom(vixl::aarch32::r2)
             : helpers::LocationFrom(vixl::aarch32::r1));
   }
-  Location GetFpuLocation(Primitive::Type type) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetFpuLocation(DataType::Type type) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? helpers::LocationFrom(vixl::aarch32::s0, vixl::aarch32::s1)
         : helpers::LocationFrom(vixl::aarch32::s0);
   }
@@ -434,7 +434,7 @@
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
@@ -475,12 +475,12 @@
   // Helper method to move a 32-bit value between two locations.
   void Move32(Location destination, Location source);
 
-  void LoadFromShiftedRegOffset(Primitive::Type type,
+  void LoadFromShiftedRegOffset(DataType::Type type,
                                 Location out_loc,
                                 vixl::aarch32::Register base,
                                 vixl::aarch32::Register reg_index,
                                 vixl::aarch32::Condition cond = vixl::aarch32::al);
-  void StoreToShiftedRegOffset(Primitive::Type type,
+  void StoreToShiftedRegOffset(DataType::Type type,
                                Location out_loc,
                                vixl::aarch32::Register base,
                                vixl::aarch32::Register reg_index,
@@ -522,8 +522,8 @@
 
   const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
-    return type == Primitive::kPrimDouble || type == Primitive::kPrimLong;
+  bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE {
+    return type == DataType::Type::kFloat64 || type == DataType::Type::kInt64;
   }
 
   void ComputeSpillMask() OVERRIDE;
@@ -551,7 +551,7 @@
   void GenerateVirtualCall(
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
-  void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
+  void MoveFromReturnRegister(Location trg, DataType::Type type) OVERRIDE;
 
   // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
   // and boot image strings/types. The only difference is the interpretation of the
@@ -594,7 +594,7 @@
                                                 dex::TypeIndex type_index,
                                                 Handle<mirror::Class> handle);
 
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
 
   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
 
@@ -778,9 +778,9 @@
   PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
                                           uint32_t offset_or_index,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
-                                          ArenaVector<LinkerPatch>* linker_patches);
+                                          ArenaVector<linker::LinkerPatch>* linker_patches);
 
   // Labels for each block that will be compiled.
   // We use a deque so that the `vixl::aarch32::Label` objects do not move in memory.
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 6256722..a7c8557 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -29,6 +29,7 @@
 #include "heap_poisoning.h"
 #include "intrinsics.h"
 #include "intrinsics_mips.h"
+#include "linker/linker_patch.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "offsets.h"
@@ -48,30 +49,30 @@
 constexpr bool kBakerReadBarrierThunksEnableForArrays = true;
 constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
 
-Location MipsReturnLocation(Primitive::Type return_type) {
+Location MipsReturnLocation(DataType::Type return_type) {
   switch (return_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
       return Location::RegisterLocation(V0);
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       return Location::RegisterPairLocation(V0, V1);
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       return Location::FpuRegisterLocation(F0);
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       return Location();
   }
   UNREACHABLE();
 }
 
-Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(Primitive::Type type) const {
+Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(DataType::Type type) const {
   return MipsReturnLocation(type);
 }
 
@@ -79,16 +80,16 @@
   return Location::RegisterLocation(kMethodRegisterArgument);
 }
 
-Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type type) {
   Location next_location;
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       uint32_t gp_index = gp_index_++;
       if (gp_index < calling_convention.GetNumberOfRegisters()) {
         next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
@@ -99,7 +100,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t gp_index = gp_index_;
       gp_index_ += 2;
       if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
@@ -122,32 +123,32 @@
     // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
     // will take up the even/odd pair, while floats are stored in even regs only.
     // On 64 bit FPU, both double and float are stored in even registers only.
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       uint32_t float_index = float_index_++;
       if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
         next_location = Location::FpuRegisterLocation(
             calling_convention.GetFpuRegisterAt(float_index));
       } else {
         size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
-        next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
-                                                     : Location::StackSlot(stack_offset);
+        next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
+                                                    : Location::StackSlot(stack_offset);
       }
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
       break;
   }
 
   // Space on the stack is reserved for all arguments.
-  stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
+  stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
 
   return next_location;
 }
 
-Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
+Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type type) {
   return MipsReturnLocation(type);
 }
 
@@ -172,10 +173,10 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimInt,
+                               DataType::Type::kInt32,
                                locations->InAt(1),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimInt);
+                               DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -278,7 +279,7 @@
     // Move the class to the desired location.
     if (out.IsValid()) {
       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
-      Primitive::Type type = instruction_->GetType();
+      DataType::Type type = instruction_->GetType();
       mips_codegen->MoveLocation(out,
                                  Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                  type);
@@ -290,7 +291,9 @@
       // For non-Baker read barriers we need to re-calculate the address of
       // the class entry.
       const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
-      Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
+      const bool has_irreducible_loops = codegen->GetGraph()->HasIrreducibleLoops();
+      Register base =
+          (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
@@ -369,7 +372,7 @@
             &info_low->label);
     }
 
-    Primitive::Type type = instruction_->GetType();
+    DataType::Type type = instruction_->GetType();
     mips_codegen->MoveLocation(locations->Out(),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                type);
@@ -380,7 +383,9 @@
       // For non-Baker read barriers we need to re-calculate the address of
       // the string entry.
       const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
-      Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
+      const bool has_irreducible_loops = codegen->GetGraph()->HasIrreducibleLoops();
+      Register base =
+          (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           mips_codegen->NewStringBssEntryPatch(load->GetDexFile(), string_index);
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
@@ -485,14 +490,14 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimNot,
+                               DataType::Type::kReference,
                                locations->InAt(1),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
-      Primitive::Type ret_type = instruction_->GetType();
+      DataType::Type ret_type = instruction_->GetType();
       Location ret_loc = calling_convention.GetReturnLocation(ret_type);
       mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
     } else {
@@ -554,17 +559,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -964,16 +969,16 @@
     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
     parallel_move.AddMove(ref_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     parallel_move.AddMove(obj_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -987,8 +992,8 @@
     CheckEntrypointTypes<
         kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
     mips_codegen->MoveLocation(out_,
-                               calling_convention.GetReturnLocation(Primitive::kPrimNot),
-                               Primitive::kPrimNot);
+                               calling_convention.GetReturnLocation(DataType::Type::kReference),
+                               DataType::Type::kReference);
 
     RestoreLiveRegisters(codegen, locations);
     __ B(GetExitLabel());
@@ -1053,15 +1058,15 @@
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
     mips_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                root_,
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     mips_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
                                 instruction_,
                                 instruction_->GetDexPc(),
                                 this);
     CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
     mips_codegen->MoveLocation(out_,
-                               calling_convention.GetReturnLocation(Primitive::kPrimNot),
-                               Primitive::kPrimNot);
+                               calling_convention.GetReturnLocation(DataType::Type::kReference),
+                               DataType::Type::kReference);
 
     RestoreLiveRegisters(codegen, locations);
     __ B(GetExitLabel());
@@ -1160,7 +1165,7 @@
 void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
   DCHECK_LT(index, moves_.size());
   MoveOperands* move = moves_[index];
-  Primitive::Type type = move->GetType();
+  DataType::Type type = move->GetType();
   Location loc1 = move->GetDestination();
   Location loc2 = move->GetSource();
 
@@ -1181,12 +1186,12 @@
   } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
     FRegister f1 = loc1.AsFpuRegister<FRegister>();
     FRegister f2 = loc2.AsFpuRegister<FRegister>();
-    if (type == Primitive::kPrimFloat) {
+    if (type == DataType::Type::kFloat32) {
       __ MovS(FTMP, f2);
       __ MovS(f2, f1);
       __ MovS(f1, FTMP);
     } else {
-      DCHECK_EQ(type, Primitive::kPrimDouble);
+      DCHECK_EQ(type, DataType::Type::kFloat64);
       __ MovD(FTMP, f2);
       __ MovD(f2, f1);
       __ MovD(f1, FTMP);
@@ -1194,7 +1199,7 @@
   } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
              (loc1.IsFpuRegister() && loc2.IsRegister())) {
     // Swap FPR and GPR.
-    DCHECK_EQ(type, Primitive::kPrimFloat);  // Can only swap a float.
+    DCHECK_EQ(type, DataType::Type::kFloat32);  // Can only swap a float.
     FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
                                         : loc2.AsFpuRegister<FRegister>();
     Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
@@ -1216,7 +1221,7 @@
   } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
              (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
     // Swap FPR and GPR register pair.
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
                                         : loc2.AsFpuRegister<FRegister>();
     Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
@@ -1262,12 +1267,12 @@
     FRegister reg = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
                                          : loc2.AsFpuRegister<FRegister>();
     intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
-    if (type == Primitive::kPrimFloat) {
+    if (type == DataType::Type::kFloat32) {
       __ MovS(FTMP, reg);
       __ LoadSFromOffset(reg, SP, offset);
       __ StoreSToOffset(FTMP, SP, offset);
     } else {
-      DCHECK_EQ(type, Primitive::kPrimDouble);
+      DCHECK_EQ(type, DataType::Type::kFloat64);
       __ MovD(FTMP, reg);
       __ LoadDFromOffset(reg, SP, offset);
       __ StoreDToOffset(FTMP, SP, offset);
@@ -1457,7 +1462,7 @@
 
 void CodeGeneratorMIPS::MoveLocation(Location destination,
                                      Location source,
-                                     Primitive::Type dst_type) {
+                                     DataType::Type dst_type) {
   if (source.Equals(destination)) {
     return;
   }
@@ -1493,10 +1498,10 @@
       }
     } else if (destination.IsFpuRegister()) {
       if (source.IsRegister()) {
-        DCHECK(!Primitive::Is64BitType(dst_type));
+        DCHECK(!DataType::Is64BitType(dst_type));
         __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
       } else if (source.IsRegisterPair()) {
-        DCHECK(Primitive::Is64BitType(dst_type));
+        DCHECK(DataType::Is64BitType(dst_type));
         FRegister dst = destination.AsFpuRegister<FRegister>();
         Register src_high = source.AsRegisterPairHigh<Register>();
         Register src_low = source.AsRegisterPairLow<Register>();
@@ -1507,20 +1512,20 @@
           __ MoveV(VectorRegisterFrom(destination),
                    VectorRegisterFrom(source));
         } else {
-          if (Primitive::Is64BitType(dst_type)) {
+          if (DataType::Is64BitType(dst_type)) {
             __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
           } else {
-            DCHECK_EQ(dst_type, Primitive::kPrimFloat);
+            DCHECK_EQ(dst_type, DataType::Type::kFloat32);
             __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
           }
         }
       } else if (source.IsSIMDStackSlot()) {
         __ LoadQFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
       } else if (source.IsDoubleStackSlot()) {
-        DCHECK(Primitive::Is64BitType(dst_type));
+        DCHECK(DataType::Is64BitType(dst_type));
         __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
       } else {
-        DCHECK(!Primitive::Is64BitType(dst_type));
+        DCHECK(!DataType::Is64BitType(dst_type));
         DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
         __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
       }
@@ -1628,10 +1633,10 @@
   }
 }
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
     const ArenaDeque<PcRelativePatchInfo>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
     const DexFile& dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
@@ -1647,7 +1652,7 @@
   }
 }
 
-void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       pc_relative_method_patches_.size() +
@@ -1658,25 +1663,25 @@
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
-                                                                  linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        pc_relative_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        pc_relative_string_patches_, linker_patches);
   } else {
     DCHECK(pc_relative_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        pc_relative_string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   DCHECK_EQ(size, linker_patches->size());
 }
 
@@ -2017,9 +2022,9 @@
 void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
   DCHECK_EQ(instruction->InputCount(), 2U);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       HInstruction* right = instruction->InputAt(1);
       bool can_use_imm = false;
@@ -2042,15 +2047,15 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK(instruction->IsAdd() || instruction->IsSub());
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
@@ -2063,11 +2068,11 @@
 }
 
 void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register dst = locations->Out().AsRegister<Register>();
       Register lhs = locations->InAt(0).AsRegister<Register>();
       Location rhs_location = locations->InAt(1);
@@ -2111,7 +2116,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
       Register dst_low = locations->Out().AsRegisterPairLow<Register>();
       Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -2252,20 +2257,20 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FRegister dst = locations->Out().AsFpuRegister<FRegister>();
       FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
       FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
       if (instruction->IsAdd()) {
-        if (type == Primitive::kPrimFloat) {
+        if (type == DataType::Type::kFloat32) {
           __ AddS(dst, lhs, rhs);
         } else {
           __ AddD(dst, lhs, rhs);
         }
       } else {
         DCHECK(instruction->IsSub());
-        if (type == Primitive::kPrimFloat) {
+        if (type == DataType::Type::kFloat32) {
           __ SubS(dst, lhs, rhs);
         } else {
           __ SubD(dst, lhs, rhs);
@@ -2283,14 +2288,14 @@
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
       locations->SetOut(Location::RequiresRegister());
@@ -2305,20 +2310,20 @@
 void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
   LocationSummary* locations = instr->GetLocations();
-  Primitive::Type type = instr->GetType();
+  DataType::Type type = instr->GetType();
 
   Location rhs_location = locations->InAt(1);
   bool use_imm = rhs_location.IsConstant();
   Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
   int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
   const uint32_t shift_mask =
-      (type == Primitive::kPrimInt) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
+      (type == DataType::Type::kInt32) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
   const uint32_t shift_value = rhs_imm & shift_mask;
   // Are the INS (Insert Bit Field) and ROTR instructions supported?
   bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register dst = locations->Out().AsRegister<Register>();
       Register lhs = locations->InAt(0).AsRegister<Register>();
       if (use_imm) {
@@ -2367,7 +2372,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
       Register dst_low = locations->Out().AsRegisterPairLow<Register>();
       Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -2531,9 +2536,9 @@
 }
 
 void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (type == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (type == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier
@@ -2544,7 +2549,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(type)) {
+  if (DataType::IsFloatingPointType(type)) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps in the case of an object array get with
@@ -2583,11 +2588,11 @@
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
                                         instruction->IsStringCharAt();
   switch (type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       Register out = out_loc.AsRegister<Register>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2600,7 +2605,7 @@
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       Register out = out_loc.AsRegister<Register>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2613,7 +2618,7 @@
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       Register out = out_loc.AsRegister<Register>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2626,7 +2631,7 @@
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       Register out = out_loc.AsRegister<Register>();
       if (maybe_compressed_char_at) {
         uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
@@ -2678,7 +2683,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
       Register out = out_loc.AsRegister<Register>();
       if (index.IsConstant()) {
@@ -2692,7 +2697,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       static_assert(
           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -2752,7 +2757,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register out = out_loc.AsRegisterPairLow<Register>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2765,7 +2770,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       FRegister out = out_loc.AsFpuRegister<FRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2778,7 +2783,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       FRegister out = out_loc.AsFpuRegister<FRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2791,7 +2796,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -2836,7 +2841,7 @@
 }
 
 void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -2850,7 +2855,7 @@
 
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
     locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
   } else {
     locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
@@ -2866,7 +2871,7 @@
   Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
   Location value_location = locations->InAt(2);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -2874,8 +2879,8 @@
   Register base_reg = index.IsConstant() ? obj : TMP;
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
@@ -2892,8 +2897,8 @@
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
@@ -2910,7 +2915,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
@@ -2927,7 +2932,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       if (value_location.IsConstant()) {
         // Just setting null.
         uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
@@ -3042,7 +3047,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
@@ -3059,7 +3064,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
@@ -3076,7 +3081,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
@@ -3093,7 +3098,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -3378,31 +3383,31 @@
 }
 
 void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
-  Primitive::Type in_type = compare->InputAt(0)->GetType();
+  DataType::Type in_type = compare->InputAt(0)->GetType();
 
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
 
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       // Output overlaps because it is written before doing the low comparison.
       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -3416,18 +3421,18 @@
 void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   Register res = locations->Out().AsRegister<Register>();
-  Primitive::Type in_type = instruction->InputAt(0)->GetType();
+  DataType::Type in_type = instruction->InputAt(0)->GetType();
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
 
   //  0 if: left == right
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       Register lhs = locations->InAt(0).AsRegister<Register>();
       Register rhs = locations->InAt(1).AsRegister<Register>();
       __ Slt(TMP, lhs, rhs);
@@ -3435,7 +3440,7 @@
       __ Subu(res, res, TMP);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       MipsLabel done;
       Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
       Register lhs_low  = locations->InAt(0).AsRegisterPairLow<Register>();
@@ -3453,7 +3458,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       bool gt_bias = instruction->IsGtBias();
       FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
       FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
@@ -3493,7 +3498,7 @@
       __ Bind(&done);
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       bool gt_bias = instruction->IsGtBias();
       FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
       FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
@@ -3543,13 +3548,13 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->InputAt(0)->GetType()) {
     default:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       break;
@@ -3564,7 +3569,7 @@
     return;
   }
 
-  Primitive::Type type = instruction->InputAt(0)->GetType();
+  DataType::Type type = instruction->InputAt(0)->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
@@ -3573,12 +3578,12 @@
       GenerateIntCompare(instruction->GetCondition(), locations);
       return;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       GenerateLongCompare(instruction->GetCondition(), locations);
       return;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
       return;
   }
@@ -3586,7 +3591,7 @@
 
 void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
+  DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -3610,7 +3615,7 @@
 
 void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
+  DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -3659,7 +3664,7 @@
 
 void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
+  DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -3710,7 +3715,7 @@
 
 void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
+  DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
 
   LocationSummary* locations = instruction->GetLocations();
   Register out = locations->Out().AsRegister<Register>();
@@ -3749,21 +3754,21 @@
 }
 
 void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
-  Primitive::Type type = div->GetResultType();
-  LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
+  DataType::Type type = div->GetResultType();
+  LocationSummary::CallKind call_kind = (type == DataType::Type::kInt64)
       ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::RegisterPairLocation(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -3773,8 +3778,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3786,24 +3791,24 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       GenerateDivRemIntegral(instruction);
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
       CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FRegister dst = locations->Out().AsFpuRegister<FRegister>();
       FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
       FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ DivS(dst, lhs, rhs);
       } else {
         __ DivD(dst, lhs, rhs);
@@ -3824,14 +3829,14 @@
   SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS(instruction);
   codegen_->AddSlowPath(slow_path);
   Location value = instruction->GetLocations()->InAt(0);
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32: {
       if (value.IsConstant()) {
         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
           __ B(slow_path->GetEntryLabel());
@@ -3845,7 +3850,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (value.IsConstant()) {
         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
           __ B(slow_path->GetEntryLabel());
@@ -4781,13 +4786,13 @@
 
 void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
                                                      bool gt_bias,
-                                                     Primitive::Type type,
+                                                     DataType::Type type,
                                                      LocationSummary* locations) {
   Register dst = locations->Out().AsRegister<Register>();
   FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
   FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     if (isR6) {
       switch (cond) {
         case kCondEQ:
@@ -4894,7 +4899,7 @@
       }
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     if (isR6) {
       switch (cond) {
         case kCondEQ:
@@ -5005,13 +5010,13 @@
 
 bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR2(IfCondition cond,
                                                           bool gt_bias,
-                                                          Primitive::Type type,
+                                                          DataType::Type type,
                                                           LocationSummary* input_locations,
                                                           int cc) {
   FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
   FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
   CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     switch (cond) {
       case kCondEQ:
         __ CeqS(cc, lhs, rhs);
@@ -5052,7 +5057,7 @@
         UNREACHABLE();
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     switch (cond) {
       case kCondEQ:
         __ CeqD(cc, lhs, rhs);
@@ -5097,13 +5102,13 @@
 
 bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR6(IfCondition cond,
                                                           bool gt_bias,
-                                                          Primitive::Type type,
+                                                          DataType::Type type,
                                                           LocationSummary* input_locations,
                                                           FRegister dst) {
   FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
   FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
   CHECK(codegen_->GetInstructionSetFeatures().IsR6());
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     switch (cond) {
       case kCondEQ:
         __ CmpEqS(dst, lhs, rhs);
@@ -5144,7 +5149,7 @@
         UNREACHABLE();
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     switch (cond) {
       case kCondEQ:
         __ CmpEqD(dst, lhs, rhs);
@@ -5189,13 +5194,13 @@
 
 void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
                                                               bool gt_bias,
-                                                              Primitive::Type type,
+                                                              DataType::Type type,
                                                               LocationSummary* locations,
                                                               MipsLabel* label) {
   FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
   FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     if (isR6) {
       switch (cond) {
         case kCondEQ:
@@ -5290,7 +5295,7 @@
       }
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     if (isR6) {
       switch (cond) {
         case kCondEQ:
@@ -5432,7 +5437,7 @@
     // The condition instruction has not been materialized, use its inputs as
     // the comparison and its condition as the branch condition.
     HCondition* condition = cond->AsCondition();
-    Primitive::Type type = condition->InputAt(0)->GetType();
+    DataType::Type type = condition->InputAt(0)->GetType();
     LocationSummary* locations = cond->GetLocations();
     IfCondition if_cond = condition->GetCondition();
     MipsLabel* branch_target = true_target;
@@ -5446,11 +5451,11 @@
       default:
         GenerateIntCompareAndBranch(if_cond, locations, branch_target);
         break;
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         GenerateLongCompareAndBranch(if_cond, locations, branch_target);
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
         break;
     }
@@ -5515,8 +5520,9 @@
   HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
   HCondition* condition = cond->AsCondition();
 
-  Primitive::Type cond_type = materialized ? Primitive::kPrimInt : condition->InputAt(0)->GetType();
-  Primitive::Type dst_type = select->GetType();
+  DataType::Type cond_type =
+      materialized ? DataType::Type::kInt32 : condition->InputAt(0)->GetType();
+  DataType::Type dst_type = select->GetType();
 
   HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
   HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
@@ -5558,7 +5564,7 @@
               use_const_for_true_in = is_true_value_zero_constant;
             }
             break;
-          case Primitive::kPrimLong:
+          case DataType::Type::kInt64:
             // Moving long on int condition.
             if (is_r6) {
               if (is_true_value_zero_constant) {
@@ -5581,8 +5587,8 @@
               use_const_for_true_in = is_true_value_zero_constant;
             }
             break;
-          case Primitive::kPrimFloat:
-          case Primitive::kPrimDouble:
+          case DataType::Type::kFloat32:
+          case DataType::Type::kFloat64:
             // Moving float/double on int condition.
             if (is_r6) {
               if (materialized) {
@@ -5613,12 +5619,12 @@
             break;
         }
         break;
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         // We don't materialize long comparison now
         // and use conditional branches instead.
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         switch (dst_type) {
           default:
             // Moving int on float/double condition.
@@ -5646,7 +5652,7 @@
               use_const_for_true_in = is_true_value_zero_constant;
             }
             break;
-          case Primitive::kPrimLong:
+          case DataType::Type::kInt64:
             // Moving long on float/double condition.
             if (is_r6) {
               if (is_true_value_zero_constant) {
@@ -5671,8 +5677,8 @@
               use_const_for_true_in = is_true_value_zero_constant;
             }
             break;
-          case Primitive::kPrimFloat:
-          case Primitive::kPrimDouble:
+          case DataType::Type::kFloat32:
+          case DataType::Type::kFloat64:
             // Moving float/double on float/double condition.
             if (is_r6) {
               can_move_conditionally = true;
@@ -5708,7 +5714,7 @@
       locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
     } else {
       locations_to_set->SetInAt(0,
-                                Primitive::IsFloatingPointType(dst_type)
+                                DataType::IsFloatingPointType(dst_type)
                                     ? Location::RequiresFpuRegister()
                                     : Location::RequiresRegister());
     }
@@ -5716,7 +5722,7 @@
       locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
     } else {
       locations_to_set->SetInAt(1,
-                                Primitive::IsFloatingPointType(dst_type)
+                                DataType::IsFloatingPointType(dst_type)
                                     ? Location::RequiresFpuRegister()
                                     : Location::RequiresRegister());
     }
@@ -5729,7 +5735,7 @@
     if (is_out_same_as_first_in) {
       locations_to_set->SetOut(Location::SameAsFirstInput());
     } else {
-      locations_to_set->SetOut(Primitive::IsFloatingPointType(dst_type)
+      locations_to_set->SetOut(DataType::IsFloatingPointType(dst_type)
                                    ? Location::RequiresFpuRegister()
                                    : Location::RequiresRegister());
     }
@@ -5747,9 +5753,9 @@
   HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
   Register cond_reg = TMP;
   int cond_cc = 0;
-  Primitive::Type cond_type = Primitive::kPrimInt;
+  DataType::Type cond_type = DataType::Type::kInt32;
   bool cond_inverted = false;
-  Primitive::Type dst_type = select->GetType();
+  DataType::Type dst_type = select->GetType();
 
   if (IsBooleanValueOrMaterializedCondition(cond)) {
     cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
@@ -5760,11 +5766,11 @@
     cond_type = condition->InputAt(0)->GetType();
     switch (cond_type) {
       default:
-        DCHECK_NE(cond_type, Primitive::kPrimLong);
+        DCHECK_NE(cond_type, DataType::Type::kInt64);
         cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         cond_inverted = MaterializeFpCompareR2(if_cond,
                                                condition->IsGtBias(),
                                                cond_type,
@@ -5794,7 +5800,7 @@
             __ Movn(dst.AsRegister<Register>(), src_reg, cond_reg);
           }
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           if (cond_inverted) {
             __ Movz(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
             __ Movz(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
@@ -5803,14 +5809,14 @@
             __ Movn(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
           }
           break;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           if (cond_inverted) {
             __ MovzS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
           } else {
             __ MovnS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
           }
           break;
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           if (cond_inverted) {
             __ MovzD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
           } else {
@@ -5819,11 +5825,11 @@
           break;
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       LOG(FATAL) << "Unreachable";
       UNREACHABLE();
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       switch (dst_type) {
         default:
           if (cond_inverted) {
@@ -5832,7 +5838,7 @@
             __ Movt(dst.AsRegister<Register>(), src_reg, cond_cc);
           }
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           if (cond_inverted) {
             __ Movf(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
             __ Movf(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
@@ -5841,14 +5847,14 @@
             __ Movt(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
           }
           break;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           if (cond_inverted) {
             __ MovfS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
           } else {
             __ MovtS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
           }
           break;
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           if (cond_inverted) {
             __ MovfD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
           } else {
@@ -5868,9 +5874,9 @@
   HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
   Register cond_reg = TMP;
   FRegister fcond_reg = FTMP;
-  Primitive::Type cond_type = Primitive::kPrimInt;
+  DataType::Type cond_type = DataType::Type::kInt32;
   bool cond_inverted = false;
-  Primitive::Type dst_type = select->GetType();
+  DataType::Type dst_type = select->GetType();
 
   if (IsBooleanValueOrMaterializedCondition(cond)) {
     cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
@@ -5881,11 +5887,11 @@
     cond_type = condition->InputAt(0)->GetType();
     switch (cond_type) {
       default:
-        DCHECK_NE(cond_type, Primitive::kPrimLong);
+        DCHECK_NE(cond_type, DataType::Type::kInt64);
         cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         cond_inverted = MaterializeFpCompareR6(if_cond,
                                                condition->IsGtBias(),
                                                cond_type,
@@ -5904,7 +5910,7 @@
 
   switch (dst_type) {
     default:
-      if (Primitive::IsFloatingPointType(cond_type)) {
+      if (DataType::IsFloatingPointType(cond_type)) {
         __ Mfc1(cond_reg, fcond_reg);
       }
       if (true_src.IsConstant()) {
@@ -5931,8 +5937,8 @@
         __ Or(dst.AsRegister<Register>(), AT, TMP);
       }
       break;
-    case Primitive::kPrimLong: {
-      if (Primitive::IsFloatingPointType(cond_type)) {
+    case DataType::Type::kInt64: {
+      if (DataType::IsFloatingPointType(cond_type)) {
         __ Mfc1(cond_reg, fcond_reg);
       }
       Register dst_lo = dst.AsRegisterPairLow<Register>();
@@ -5961,8 +5967,8 @@
       }
       break;
     }
-    case Primitive::kPrimFloat: {
-      if (!Primitive::IsFloatingPointType(cond_type)) {
+    case DataType::Type::kFloat32: {
+      if (!DataType::IsFloatingPointType(cond_type)) {
         // sel*.fmt tests bit 0 of the condition register, account for that.
         __ Sltu(TMP, ZERO, cond_reg);
         __ Mtc1(TMP, fcond_reg);
@@ -5996,8 +6002,8 @@
       }
       break;
     }
-    case Primitive::kPrimDouble: {
-      if (!Primitive::IsFloatingPointType(cond_type)) {
+    case DataType::Type::kFloat64: {
+      if (!DataType::IsFloatingPointType(cond_type)) {
         // sel*.fmt tests bit 0 of the condition register, account for that.
         __ Sltu(TMP, ZERO, cond_reg);
         __ Mtc1(TMP, fcond_reg);
@@ -6085,11 +6091,11 @@
 }
 
 void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
-  Primitive::Type field_type = field_info.GetFieldType();
-  bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
+  DataType::Type field_type = field_info.GetFieldType();
+  bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
   bool generate_volatile = field_info.IsVolatile() && is_wide;
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (field_type == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (field_type == DataType::Type::kReference);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
       instruction,
       generate_volatile
@@ -6106,18 +6112,18 @@
     InvokeRuntimeCallingConvention calling_convention;
     // need A0 to hold base + offset
     locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-    if (field_type == Primitive::kPrimLong) {
-      locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimLong));
+    if (field_type == DataType::Type::kInt64) {
+      locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt64));
     } else {
       // Use Location::Any() to prevent situations when running out of available fp registers.
       locations->SetOut(Location::Any());
       // Need some temp core regs since FP results are returned in core registers
-      Location reg = calling_convention.GetReturnLocation(Primitive::kPrimLong);
+      Location reg = calling_convention.GetReturnLocation(DataType::Type::kInt64);
       locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
       locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
     }
   } else {
-    if (Primitive::IsFloatingPointType(instruction->GetType())) {
+    if (DataType::IsFloatingPointType(instruction->GetType())) {
       locations->SetOut(Location::RequiresFpuRegister());
     } else {
       // The output overlaps in the case of an object field get with
@@ -6141,7 +6147,7 @@
 void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
                                                   const FieldInfo& field_info,
                                                   uint32_t dex_pc) {
-  Primitive::Type type = field_info.GetFieldType();
+  DataType::Type type = field_info.GetFieldType();
   LocationSummary* locations = instruction->GetLocations();
   Location obj_loc = locations->InAt(0);
   Register obj = obj_loc.AsRegister<Register>();
@@ -6152,28 +6158,28 @@
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
   switch (type) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       load_type = kLoadUnsignedByte;
       break;
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       load_type = kLoadSignedByte;
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       load_type = kLoadSignedHalfword;
       break;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       load_type = kLoadUnsignedHalfword;
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimNot:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kReference:
       load_type = kLoadWord;
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       load_type = kLoadDoubleword;
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
@@ -6186,7 +6192,7 @@
     codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
     codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
     CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       // FP results are returned in core registers. Need to move them.
       if (dst_loc.IsFpuRegister()) {
         __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), dst_loc.AsFpuRegister<FRegister>());
@@ -6205,7 +6211,7 @@
       }
     }
   } else {
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       // /* HeapReference<Object> */ dst = *(obj + offset)
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         Location temp_loc =
@@ -6231,9 +6237,9 @@
         // reference, if heap poisoning is enabled).
         codegen_->MaybeGenerateReadBarrierSlow(instruction, dst_loc, dst_loc, obj_loc, offset);
       }
-    } else if (!Primitive::IsFloatingPointType(type)) {
+    } else if (!DataType::IsFloatingPointType(type)) {
       Register dst;
-      if (type == Primitive::kPrimLong) {
+      if (type == DataType::Type::kInt64) {
         DCHECK(dst_loc.IsRegisterPair());
         dst = dst_loc.AsRegisterPairLow<Register>();
       } else {
@@ -6244,7 +6250,7 @@
     } else {
       DCHECK(dst_loc.IsFpuRegister());
       FRegister dst = dst_loc.AsFpuRegister<FRegister>();
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ LoadSFromOffset(dst, obj, offset, null_checker);
       } else {
         __ LoadDFromOffset(dst, obj, offset, null_checker);
@@ -6254,14 +6260,14 @@
 
   // Memory barriers, in the case of references, are handled in the
   // previous switch statement.
-  if (is_volatile && (type != Primitive::kPrimNot)) {
+  if (is_volatile && (type != DataType::Type::kReference)) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
 }
 
 void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
-  Primitive::Type field_type = field_info.GetFieldType();
-  bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
+  DataType::Type field_type = field_info.GetFieldType();
+  bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
   bool generate_volatile = field_info.IsVolatile() && is_wide;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
       instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
@@ -6271,7 +6277,7 @@
     InvokeRuntimeCallingConvention calling_convention;
     // need A0 to hold base + offset
     locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-    if (field_type == Primitive::kPrimLong) {
+    if (field_type == DataType::Type::kInt64) {
       locations->SetInAt(1, Location::RegisterPairLocation(
           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
     } else {
@@ -6282,7 +6288,7 @@
       locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
     }
   } else {
-    if (Primitive::IsFloatingPointType(field_type)) {
+    if (DataType::IsFloatingPointType(field_type)) {
       locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
     } else {
       locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
@@ -6294,7 +6300,7 @@
                                                   const FieldInfo& field_info,
                                                   uint32_t dex_pc,
                                                   bool value_can_be_null) {
-  Primitive::Type type = field_info.GetFieldType();
+  DataType::Type type = field_info.GetFieldType();
   LocationSummary* locations = instruction->GetLocations();
   Register obj = locations->InAt(0).AsRegister<Register>();
   Location value_location = locations->InAt(1);
@@ -6305,24 +6311,24 @@
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       store_type = kStoreByte;
       break;
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
       store_type = kStoreHalfword;
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimNot:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kReference:
       store_type = kStoreWord;
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       store_type = kStoreDoubleword;
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
@@ -6337,7 +6343,7 @@
     // Do implicit Null check.
     __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
     codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       // Pass FP parameters in core registers.
       if (value_location.IsFpuRegister()) {
         __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
@@ -6368,9 +6374,9 @@
     if (value_location.IsConstant()) {
       int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
       __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
-    } else if (!Primitive::IsFloatingPointType(type)) {
+    } else if (!DataType::IsFloatingPointType(type)) {
       Register src;
-      if (type == Primitive::kPrimLong) {
+      if (type == DataType::Type::kInt64) {
         src = value_location.AsRegisterPairLow<Register>();
       } else {
         src = value_location.AsRegister<Register>();
@@ -6379,7 +6385,7 @@
         // Note that in the case where `value` is a null reference,
         // we do not enter this block, as a null reference does not
         // need poisoning.
-        DCHECK_EQ(type, Primitive::kPrimNot);
+        DCHECK_EQ(type, DataType::Type::kReference);
         __ PoisonHeapReference(TMP, src);
         __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
       } else {
@@ -6387,7 +6393,7 @@
       }
     } else {
       FRegister src = value_location.AsFpuRegister<FRegister>();
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ StoreSToOffset(src, obj, offset, null_checker);
       } else {
         __ StoreDToOffset(src, obj, offset, null_checker);
@@ -7332,7 +7338,8 @@
   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
 
   bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
-  bool has_extra_input = invoke->HasPcRelativeMethodLoadKind() && !is_r6;
+  bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
+  bool has_extra_input = invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops;
 
   IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
   if (intrinsic.TryDispatch(invoke)) {
@@ -7370,75 +7377,49 @@
 
 HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
     HLoadString::LoadKind desired_string_load_kind) {
-  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
-  // is incompatible with it.
-  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
-  // with irreducible loops.
-  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
-  bool is_r6 = GetInstructionSetFeatures().IsR6();
-  bool fallback_load = has_irreducible_loops && !is_r6;
   switch (desired_string_load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
     case HLoadString::LoadKind::kBootImageInternTable:
     case HLoadString::LoadKind::kBssEntry:
       DCHECK(!Runtime::Current()->UseJitCompilation());
       break;
-    case HLoadString::LoadKind::kBootImageAddress:
-      break;
     case HLoadString::LoadKind::kJitTableAddress:
       DCHECK(Runtime::Current()->UseJitCompilation());
-      fallback_load = false;
       break;
+    case HLoadString::LoadKind::kBootImageAddress:
     case HLoadString::LoadKind::kRuntimeCall:
-      fallback_load = false;
       break;
   }
-  if (fallback_load) {
-    desired_string_load_kind = HLoadString::LoadKind::kRuntimeCall;
-  }
   return desired_string_load_kind;
 }
 
 HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
     HLoadClass::LoadKind desired_class_load_kind) {
-  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
-  // is incompatible with it.
-  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
-  // with irreducible loops.
-  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
-  bool is_r6 = GetInstructionSetFeatures().IsR6();
-  bool fallback_load = has_irreducible_loops && !is_r6;
   switch (desired_class_load_kind) {
     case HLoadClass::LoadKind::kInvalid:
       LOG(FATAL) << "UNREACHABLE";
       UNREACHABLE();
     case HLoadClass::LoadKind::kReferrersClass:
-      fallback_load = false;
       break;
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
     case HLoadClass::LoadKind::kBootImageClassTable:
     case HLoadClass::LoadKind::kBssEntry:
       DCHECK(!Runtime::Current()->UseJitCompilation());
       break;
-    case HLoadClass::LoadKind::kBootImageAddress:
-      break;
     case HLoadClass::LoadKind::kJitTableAddress:
       DCHECK(Runtime::Current()->UseJitCompilation());
-      fallback_load = false;
       break;
+    case HLoadClass::LoadKind::kBootImageAddress:
     case HLoadClass::LoadKind::kRuntimeCall:
-      fallback_load = false;
       break;
   }
-  if (fallback_load) {
-    desired_class_load_kind = HLoadClass::LoadKind::kRuntimeCall;
-  }
   return desired_class_load_kind;
 }
 
 Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
                                                                   Register temp) {
   CHECK(!GetInstructionSetFeatures().IsR6());
+  CHECK(!GetGraph()->HasIrreducibleLoops());
   CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
   Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   if (!invoke->GetLocations()->Intrinsified()) {
@@ -7466,27 +7447,7 @@
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
       HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
-  HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
-  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
-  // is incompatible with it.
-  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
-  // with irreducible loops.
-  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
-  bool is_r6 = GetInstructionSetFeatures().IsR6();
-  bool fallback_load = has_irreducible_loops && !is_r6;
-  switch (dispatch_info.method_load_kind) {
-    case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative:
-    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry:
-      break;
-    default:
-      fallback_load = false;
-      break;
-  }
-  if (fallback_load) {
-    dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall;
-    dispatch_info.method_load_data = 0;
-  }
-  return dispatch_info;
+  return desired_dispatch_info;
 }
 
 void CodeGeneratorMIPS::GenerateStaticOrDirectCall(
@@ -7496,7 +7457,8 @@
   HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
   HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
   bool is_r6 = GetInstructionSetFeatures().IsR6();
-  Register base_reg = (invoke->HasPcRelativeMethodLoadKind() && !is_r6)
+  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
+  Register base_reg = (invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops)
       ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
       : ZERO;
 
@@ -7635,6 +7597,7 @@
   }
   DCHECK(!cls->NeedsAccessCheck());
   const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+  const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
   const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
   LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
       ? LocationSummary::kCallOnSlowPath
@@ -7652,6 +7615,10 @@
       if (isR6) {
         break;
       }
+      if (has_irreducible_loops) {
+        codegen_->ClobberRA();
+        break;
+      }
       FALLTHROUGH_INTENDED;
     case HLoadClass::LoadKind::kReferrersClass:
       locations->SetInAt(0, Location::RequiresRegister());
@@ -7690,12 +7657,15 @@
   Register out = out_loc.AsRegister<Register>();
   Register base_or_current_method_reg;
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
   switch (load_kind) {
     // We need an extra register for PC-relative literals on R2.
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
     case HLoadClass::LoadKind::kBootImageAddress:
+    case HLoadClass::LoadKind::kBootImageClassTable:
     case HLoadClass::LoadKind::kBssEntry:
-      base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
+      base_or_current_method_reg =
+          (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
       break;
     case HLoadClass::LoadKind::kReferrersClass:
     case HLoadClass::LoadKind::kRuntimeCall:
@@ -7741,9 +7711,13 @@
       uint32_t address = dchecked_integral_cast<uint32_t>(
           reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
       DCHECK_NE(address, 0u);
-      __ LoadLiteral(out,
-                     base_or_current_method_reg,
-                     codegen_->DeduplicateBootImageAddressLiteral(address));
+      if (isR6 || !has_irreducible_loops) {
+        __ LoadLiteral(out,
+                       base_or_current_method_reg,
+                       codegen_->DeduplicateBootImageAddressLiteral(address));
+      } else {
+        __ LoadConst32(out, address);
+      }
       break;
     }
     case HLoadClass::LoadKind::kBootImageClassTable: {
@@ -7848,6 +7822,7 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
   HLoadString::LoadKind load_kind = load->GetLoadKind();
   const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+  const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
   switch (load_kind) {
     // We need an extra register for PC-relative literals on R2.
     case HLoadString::LoadKind::kBootImageAddress:
@@ -7857,6 +7832,10 @@
       if (isR6) {
         break;
       }
+      if (has_irreducible_loops) {
+        codegen_->ClobberRA();
+        break;
+      }
       FALLTHROUGH_INTENDED;
     // We need an extra register for PC-relative dex cache accesses.
     case HLoadString::LoadKind::kRuntimeCall:
@@ -7895,13 +7874,15 @@
   Register out = out_loc.AsRegister<Register>();
   Register base_or_current_method_reg;
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
   switch (load_kind) {
     // We need an extra register for PC-relative literals on R2.
     case HLoadString::LoadKind::kBootImageAddress:
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
     case HLoadString::LoadKind::kBootImageInternTable:
     case HLoadString::LoadKind::kBssEntry:
-      base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
+      base_or_current_method_reg =
+          (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
       break;
     default:
       base_or_current_method_reg = ZERO;
@@ -7925,9 +7906,13 @@
       uint32_t address = dchecked_integral_cast<uint32_t>(
           reinterpret_cast<uintptr_t>(load->GetString().Get()));
       DCHECK_NE(address, 0u);
-      __ LoadLiteral(out,
-                     base_or_current_method_reg,
-                     codegen_->DeduplicateBootImageAddressLiteral(address));
+      if (isR6 || !has_irreducible_loops) {
+        __ LoadLiteral(out,
+                       base_or_current_method_reg,
+                       codegen_->DeduplicateBootImageAddressLiteral(address));
+      } else {
+        __ LoadConst32(out, address);
+      }
       return;
     }
     case HLoadString::LoadKind::kBootImageInternTable: {
@@ -8026,15 +8011,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -8046,12 +8031,12 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register dst = locations->Out().AsRegister<Register>();
       Register lhs = locations->InAt(0).AsRegister<Register>();
       Register rhs = locations->InAt(1).AsRegister<Register>();
@@ -8063,7 +8048,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
       Register dst_low = locations->Out().AsRegisterPairLow<Register>();
       Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -8100,12 +8085,12 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FRegister dst = locations->Out().AsFpuRegister<FRegister>();
       FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
       FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ MulS(dst, lhs, rhs);
       } else {
         __ MulD(dst, lhs, rhs);
@@ -8121,14 +8106,14 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -8139,17 +8124,17 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register dst = locations->Out().AsRegister<Register>();
       Register src = locations->InAt(0).AsRegister<Register>();
       __ Subu(dst, ZERO, src);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
       Register dst_low = locations->Out().AsRegisterPairLow<Register>();
       Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -8160,11 +8145,11 @@
       __ Subu(dst_high, dst_high, TMP);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FRegister dst = locations->Out().AsFpuRegister<FRegister>();
       FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ NegS(dst, src);
       } else {
         __ NegD(dst, src);
@@ -8180,7 +8165,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
   InvokeRuntimeCallingConvention calling_convention;
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
 }
@@ -8204,7 +8189,7 @@
   } else {
     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   }
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
@@ -8232,18 +8217,18 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register dst = locations->Out().AsRegister<Register>();
       Register src = locations->InAt(0).AsRegister<Register>();
       __ Nor(dst, src, ZERO);
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
       Register dst_low = locations->Out().AsRegisterPairLow<Register>();
       Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -8355,19 +8340,20 @@
 }
 
 void LocationsBuilderMIPS::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
-  LocationSummary::CallKind call_kind =
-      (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCallOnMainOnly;
+  DataType::Type type = rem->GetResultType();
+  LocationSummary::CallKind call_kind = (type == DataType::Type::kInt32)
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCallOnMainOnly;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::RegisterPairLocation(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -8377,8 +8363,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
       locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
@@ -8392,23 +8378,23 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       GenerateDivRemIntegral(instruction);
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
       CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
       CheckEntrypointTypes<kQuickFmodf, float, float, float>();
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
       CheckEntrypointTypes<kQuickFmod, double, double, double>();
       break;
@@ -8437,7 +8423,7 @@
 
 void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
-  Primitive::Type return_type = ret->InputAt(0)->GetType();
+  DataType::Type return_type = ret->InputAt(0)->GetType();
   locations->SetInAt(0, MipsReturnLocation(return_type));
 }
 
@@ -8613,33 +8599,33 @@
 }
 
 void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
-  Primitive::Type input_type = conversion->GetInputType();
-  Primitive::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
   DCHECK_NE(input_type, result_type);
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
 
-  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
-      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+  if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
+      (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
     LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
   }
 
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   if (!isR6 &&
-      ((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
-       (result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
+      ((DataType::IsFloatingPointType(result_type) && input_type == DataType::Type::kInt64) ||
+       (result_type == DataType::Type::kInt64 && DataType::IsFloatingPointType(input_type)))) {
     call_kind = LocationSummary::kCallOnMainOnly;
   }
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
 
   if (call_kind == LocationSummary::kNoCall) {
-    if (Primitive::IsFloatingPointType(input_type)) {
+    if (DataType::IsFloatingPointType(input_type)) {
       locations->SetInAt(0, Location::RequiresFpuRegister());
     } else {
       locations->SetInAt(0, Location::RequiresRegister());
     }
 
-    if (Primitive::IsFloatingPointType(result_type)) {
+    if (DataType::IsFloatingPointType(result_type)) {
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
     } else {
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -8647,10 +8633,10 @@
   } else {
     InvokeRuntimeCallingConvention calling_convention;
 
-    if (Primitive::IsFloatingPointType(input_type)) {
+    if (DataType::IsFloatingPointType(input_type)) {
       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
     } else {
-      DCHECK_EQ(input_type, Primitive::kPrimLong);
+      DCHECK_EQ(input_type, DataType::Type::kInt64);
       locations->SetInAt(0, Location::RegisterPairLocation(
                  calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
     }
@@ -8661,14 +8647,14 @@
 
 void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
   LocationSummary* locations = conversion->GetLocations();
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
   bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
 
   DCHECK_NE(input_type, result_type);
 
-  if (result_type == Primitive::kPrimLong && Primitive::IsIntegralType(input_type)) {
+  if (result_type == DataType::Type::kInt64 && DataType::IsIntegralType(input_type)) {
     Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
     Register dst_low = locations->Out().AsRegisterPairLow<Register>();
     Register src = locations->InAt(0).AsRegister<Register>();
@@ -8677,17 +8663,17 @@
       __ Move(dst_low, src);
     }
     __ Sra(dst_high, src, 31);
-  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
+  } else if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
     Register dst = locations->Out().AsRegister<Register>();
-    Register src = (input_type == Primitive::kPrimLong)
+    Register src = (input_type == DataType::Type::kInt64)
         ? locations->InAt(0).AsRegisterPairLow<Register>()
         : locations->InAt(0).AsRegister<Register>();
 
     switch (result_type) {
-      case Primitive::kPrimChar:
+      case DataType::Type::kUint16:
         __ Andi(dst, src, 0xFFFF);
         break;
-      case Primitive::kPrimByte:
+      case DataType::Type::kInt8:
         if (has_sign_extension) {
           __ Seb(dst, src);
         } else {
@@ -8695,7 +8681,7 @@
           __ Sra(dst, dst, 24);
         }
         break;
-      case Primitive::kPrimShort:
+      case DataType::Type::kInt16:
         if (has_sign_extension) {
           __ Seh(dst, src);
         } else {
@@ -8703,7 +8689,7 @@
           __ Sra(dst, dst, 16);
         }
         break;
-      case Primitive::kPrimInt:
+      case DataType::Type::kInt32:
         if (dst != src) {
           __ Move(dst, src);
         }
@@ -8713,8 +8699,8 @@
         LOG(FATAL) << "Unexpected type conversion from " << input_type
                    << " to " << result_type;
     }
-  } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
-    if (input_type == Primitive::kPrimLong) {
+  } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
+    if (input_type == DataType::Type::kInt64) {
       if (isR6) {
         // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
         // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
@@ -8723,16 +8709,16 @@
         FRegister dst = locations->Out().AsFpuRegister<FRegister>();
         __ Mtc1(src_low, FTMP);
         __ Mthc1(src_high, FTMP);
-        if (result_type == Primitive::kPrimFloat) {
+        if (result_type == DataType::Type::kFloat32) {
           __ Cvtsl(dst, FTMP);
         } else {
           __ Cvtdl(dst, FTMP);
         }
       } else {
-        QuickEntrypointEnum entrypoint = (result_type == Primitive::kPrimFloat) ? kQuickL2f
-                                                                                : kQuickL2d;
+        QuickEntrypointEnum entrypoint =
+            (result_type == DataType::Type::kFloat32) ? kQuickL2f : kQuickL2d;
         codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
-        if (result_type == Primitive::kPrimFloat) {
+        if (result_type == DataType::Type::kFloat32) {
           CheckEntrypointTypes<kQuickL2f, float, int64_t>();
         } else {
           CheckEntrypointTypes<kQuickL2d, double, int64_t>();
@@ -8742,14 +8728,14 @@
       Register src = locations->InAt(0).AsRegister<Register>();
       FRegister dst = locations->Out().AsFpuRegister<FRegister>();
       __ Mtc1(src, FTMP);
-      if (result_type == Primitive::kPrimFloat) {
+      if (result_type == DataType::Type::kFloat32) {
         __ Cvtsw(dst, FTMP);
       } else {
         __ Cvtdw(dst, FTMP);
       }
     }
-  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
-    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
+  } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
+    CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
 
     // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
     // value of the output type if the input is outside of the range after the truncation or
@@ -8767,7 +8753,7 @@
     // instruction, which will handle such an input the same way irrespective of NAN2008.
     // Otherwise the input is compared to itself to determine whether it is a NaN or not
     // in order to return either zero or the minimum value.
-    if (result_type == Primitive::kPrimLong) {
+    if (result_type == DataType::Type::kInt64) {
       if (isR6) {
         // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
         // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
@@ -8775,7 +8761,7 @@
         Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
         Register dst_low = locations->Out().AsRegisterPairLow<Register>();
 
-        if (input_type == Primitive::kPrimFloat) {
+        if (input_type == DataType::Type::kFloat32) {
           __ TruncLS(FTMP, src);
         } else {
           __ TruncLD(FTMP, src);
@@ -8783,10 +8769,10 @@
         __ Mfc1(dst_low, FTMP);
         __ Mfhc1(dst_high, FTMP);
       } else {
-        QuickEntrypointEnum entrypoint = (input_type == Primitive::kPrimFloat) ? kQuickF2l
-                                                                               : kQuickD2l;
+        QuickEntrypointEnum entrypoint =
+            (input_type == DataType::Type::kFloat32) ? kQuickF2l : kQuickD2l;
         codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
-        if (input_type == Primitive::kPrimFloat) {
+        if (input_type == DataType::Type::kFloat32) {
           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
         } else {
           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
@@ -8799,7 +8785,7 @@
       MipsLabel done;
 
       if (!isR6) {
-        if (input_type == Primitive::kPrimFloat) {
+        if (input_type == DataType::Type::kFloat32) {
           uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
           __ LoadConst32(TMP, min_val);
           __ Mtc1(TMP, FTMP);
@@ -8810,14 +8796,14 @@
           __ MoveToFpuHigh(TMP, FTMP);
         }
 
-        if (input_type == Primitive::kPrimFloat) {
+        if (input_type == DataType::Type::kFloat32) {
           __ ColeS(0, FTMP, src);
         } else {
           __ ColeD(0, FTMP, src);
         }
         __ Bc1t(0, &truncate);
 
-        if (input_type == Primitive::kPrimFloat) {
+        if (input_type == DataType::Type::kFloat32) {
           __ CeqS(0, src, src);
         } else {
           __ CeqD(0, src, src);
@@ -8830,7 +8816,7 @@
         __ Bind(&truncate);
       }
 
-      if (input_type == Primitive::kPrimFloat) {
+      if (input_type == DataType::Type::kFloat32) {
         __ TruncWS(FTMP, src);
       } else {
         __ TruncWD(FTMP, src);
@@ -8841,11 +8827,11 @@
         __ Bind(&done);
       }
     }
-  } else if (Primitive::IsFloatingPointType(result_type) &&
-             Primitive::IsFloatingPointType(input_type)) {
+  } else if (DataType::IsFloatingPointType(result_type) &&
+             DataType::IsFloatingPointType(input_type)) {
     FRegister dst = locations->Out().AsFpuRegister<FRegister>();
     FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
-    if (result_type == Primitive::kPrimFloat) {
+    if (result_type == DataType::Type::kFloat32) {
       __ Cvtsd(dst, src);
     } else {
       __ Cvtds(dst, src);
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index f15f8c6..5f2f900 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -81,8 +81,8 @@
   InvokeDexCallingConventionVisitorMIPS() {}
   virtual ~InvokeDexCallingConventionVisitorMIPS() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE;
   Location GetMethodLocation() const OVERRIDE;
 
  private:
@@ -100,7 +100,7 @@
                           kRuntimeParameterFpuRegistersLength,
                           kMipsPointerSize) {}
 
-  Location GetReturnLocation(Primitive::Type return_type);
+  Location GetReturnLocation(DataType::Type return_type);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
@@ -116,17 +116,17 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return Location::RegisterLocation(A0);
   }
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? Location::RegisterPairLocation(V0, V1)
         : Location::RegisterLocation(V0);
   }
-  Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetSetValueLocation(DataType::Type type, bool is_instance) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? Location::RegisterPairLocation(A2, A3)
         : (is_instance ? Location::RegisterLocation(A2) : Location::RegisterLocation(A1));
   }
-  Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::FpuRegisterLocation(F0);
   }
 
@@ -304,14 +304,14 @@
                                     MipsLabel* label);
   void GenerateFpCompare(IfCondition cond,
                          bool gt_bias,
-                         Primitive::Type type,
+                         DataType::Type type,
                          LocationSummary* locations);
   // When the function returns `false` it means that the condition holds if the condition
   // code flag `cc` is non-zero and doesn't hold if `cc` is zero. If it returns `true`,
   // the roles of zero and non-zero values of the `cc` flag are exchanged.
   bool MaterializeFpCompareR2(IfCondition cond,
                               bool gt_bias,
-                              Primitive::Type type,
+                              DataType::Type type,
                               LocationSummary* input_locations,
                               int cc);
   // When the function returns `false` it means that the condition holds if `dst` is non-zero
@@ -319,12 +319,12 @@
   // `dst` are exchanged.
   bool MaterializeFpCompareR6(IfCondition cond,
                               bool gt_bias,
-                              Primitive::Type type,
+                              DataType::Type type,
                               LocationSummary* input_locations,
                               FRegister dst);
   void GenerateFpCompareAndBranch(IfCondition cond,
                                   bool gt_bias,
-                                  Primitive::Type type,
+                                  DataType::Type type,
                                   LocationSummary* locations,
                                   MipsLabel* label);
   void GenerateTestAndBranch(HInstruction* instruction,
@@ -395,7 +395,7 @@
   const MipsAssembler& GetAssembler() const OVERRIDE { return assembler_; }
 
   // Emit linker patches.
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
 
   // Fast path implementation of ReadBarrier::Barrier for a heap
@@ -518,7 +518,7 @@
 
   // Code generation helpers.
 
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
 
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
 
@@ -541,8 +541,8 @@
 
   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
-    return type == Primitive::kPrimLong;
+  bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE {
+    return type == DataType::Type::kInt64;
   }
 
   // Check if the desired_string_load_kind is supported. If it is, return it,
@@ -567,7 +567,7 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
-                              Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
+                              DataType::Type type ATTRIBUTE_UNUSED) OVERRIDE {
     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
   }
 
@@ -679,9 +679,9 @@
                                           const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
 
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
-                                   ArenaVector<LinkerPatch>* linker_patches);
+                                   ArenaVector<linker::LinkerPatch>* linker_patches);
 
   // Labels for each block that will be compiled.
   MipsLabel* block_labels_;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index e8ae2db..7051cce 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -27,6 +27,7 @@
 #include "heap_poisoning.h"
 #include "intrinsics.h"
 #include "intrinsics_mips64.h"
+#include "linker/linker_patch.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "offsets.h"
@@ -46,28 +47,28 @@
 constexpr bool kBakerReadBarrierThunksEnableForArrays = true;
 constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
 
-Location Mips64ReturnLocation(Primitive::Type return_type) {
+Location Mips64ReturnLocation(DataType::Type return_type) {
   switch (return_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
       return Location::RegisterLocation(V0);
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       return Location::FpuRegisterLocation(F0);
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       return Location();
   }
   UNREACHABLE();
 }
 
-Location InvokeDexCallingConventionVisitorMIPS64::GetReturnLocation(Primitive::Type type) const {
+Location InvokeDexCallingConventionVisitorMIPS64::GetReturnLocation(DataType::Type type) const {
   return Mips64ReturnLocation(type);
 }
 
@@ -75,34 +76,34 @@
   return Location::RegisterLocation(kMethodRegisterArgument);
 }
 
-Location InvokeDexCallingConventionVisitorMIPS64::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorMIPS64::GetNextLocation(DataType::Type type) {
   Location next_location;
-  if (type == Primitive::kPrimVoid) {
+  if (type == DataType::Type::kVoid) {
     LOG(FATAL) << "Unexpected parameter type " << type;
   }
 
-  if (Primitive::IsFloatingPointType(type) &&
+  if (DataType::IsFloatingPointType(type) &&
       (float_index_ < calling_convention.GetNumberOfFpuRegisters())) {
     next_location = Location::FpuRegisterLocation(
         calling_convention.GetFpuRegisterAt(float_index_++));
     gp_index_++;
-  } else if (!Primitive::IsFloatingPointType(type) &&
+  } else if (!DataType::IsFloatingPointType(type) &&
              (gp_index_ < calling_convention.GetNumberOfRegisters())) {
     next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index_++));
     float_index_++;
   } else {
     size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
-    next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
-                                                 : Location::StackSlot(stack_offset);
+    next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
+                                                : Location::StackSlot(stack_offset);
   }
 
   // Space on the stack is reserved for all arguments.
-  stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
+  stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
 
   return next_location;
 }
 
-Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
+Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type type) {
   return Mips64ReturnLocation(type);
 }
 
@@ -127,10 +128,10 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimInt,
+                               DataType::Type::kInt32,
                                locations->InAt(1),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimInt);
+                               DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -235,7 +236,7 @@
     // Move the class to the desired location.
     if (out.IsValid()) {
       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
-      Primitive::Type type = instruction_->GetType();
+      DataType::Type type = instruction_->GetType();
       mips64_codegen->MoveLocation(out,
                                    Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                    type);
@@ -330,7 +331,7 @@
                        /* placeholder */ 0x5678);
     }
 
-    Primitive::Type type = instruction_->GetType();
+    DataType::Type type = instruction_->GetType();
     mips64_codegen->MoveLocation(locations->Out(),
                                  Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                  type);
@@ -445,14 +446,14 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimNot,
+                               DataType::Type::kReference,
                                locations->InAt(1),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       mips64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
-      Primitive::Type ret_type = instruction_->GetType();
+      DataType::Type ret_type = instruction_->GetType();
       Location ret_loc = calling_convention.GetReturnLocation(ret_type);
       mips64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
     } else {
@@ -514,17 +515,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -822,7 +823,7 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
     LocationSummary* locations = instruction_->GetLocations();
-    Primitive::Type type = Primitive::kPrimNot;
+    DataType::Type type = DataType::Type::kReference;
     GpuRegister reg_out = out_.AsRegister<GpuRegister>();
     DCHECK(locations->CanCall());
     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
@@ -911,16 +912,16 @@
     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
     parallel_move.AddMove(ref_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     parallel_move.AddMove(obj_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -986,7 +987,7 @@
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     LocationSummary* locations = instruction_->GetLocations();
-    Primitive::Type type = Primitive::kPrimNot;
+    DataType::Type type = DataType::Type::kReference;
     GpuRegister reg_out = out_.AsRegister<GpuRegister>();
     DCHECK(locations->CanCall());
     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
@@ -1001,7 +1002,7 @@
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
     mips64_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                  root_,
-                                 Primitive::kPrimNot);
+                                 DataType::Type::kReference);
     mips64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
                                   instruction_,
                                   instruction_->GetDexPc(),
@@ -1253,7 +1254,7 @@
 
 void CodeGeneratorMIPS64::MoveLocation(Location destination,
                                        Location source,
-                                       Primitive::Type dst_type) {
+                                       DataType::Type dst_type) {
   if (source.Equals(destination)) {
     return;
   }
@@ -1261,7 +1262,7 @@
   // A valid move can always be inferred from the destination and source
   // locations. When moving from and to a register, the argument type can be
   // used to generate 32bit instead of 64bit moves.
-  bool unspecified_type = (dst_type == Primitive::kPrimVoid);
+  bool unspecified_type = (dst_type == DataType::Type::kVoid);
   DCHECK_EQ(unspecified_type, false);
 
   if (destination.IsRegister() || destination.IsFpuRegister()) {
@@ -1272,27 +1273,27 @@
                                   || src_cst->IsFloatConstant()
                                   || src_cst->IsNullConstant()))) {
         // For stack slots and 32bit constants, a 64bit type is appropriate.
-        dst_type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
+        dst_type = destination.IsRegister() ? DataType::Type::kInt32 : DataType::Type::kFloat32;
       } else {
         // If the source is a double stack slot or a 64bit constant, a 64bit
         // type is appropriate. Else the source is a register, and since the
         // type has not been specified, we chose a 64bit type to force a 64bit
         // move.
-        dst_type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
+        dst_type = destination.IsRegister() ? DataType::Type::kInt64 : DataType::Type::kFloat64;
       }
     }
-    DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(dst_type)) ||
-           (destination.IsRegister() && !Primitive::IsFloatingPointType(dst_type)));
+    DCHECK((destination.IsFpuRegister() && DataType::IsFloatingPointType(dst_type)) ||
+           (destination.IsRegister() && !DataType::IsFloatingPointType(dst_type)));
     if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
       // Move to GPR/FPR from stack
       LoadOperandType load_type = source.IsStackSlot() ? kLoadWord : kLoadDoubleword;
-      if (Primitive::IsFloatingPointType(dst_type)) {
+      if (DataType::IsFloatingPointType(dst_type)) {
         __ LoadFpuFromOffset(load_type,
                              destination.AsFpuRegister<FpuRegister>(),
                              SP,
                              source.GetStackIndex());
       } else {
-        // TODO: use load_type = kLoadUnsignedWord when type == Primitive::kPrimNot.
+        // TODO: use load_type = kLoadUnsignedWord when type == DataType::Type::kReference.
         __ LoadFromOffset(load_type,
                           destination.AsRegister<GpuRegister>(),
                           SP,
@@ -1306,27 +1307,27 @@
     } else if (source.IsConstant()) {
       // Move to GPR/FPR from constant
       GpuRegister gpr = AT;
-      if (!Primitive::IsFloatingPointType(dst_type)) {
+      if (!DataType::IsFloatingPointType(dst_type)) {
         gpr = destination.AsRegister<GpuRegister>();
       }
-      if (dst_type == Primitive::kPrimInt || dst_type == Primitive::kPrimFloat) {
+      if (dst_type == DataType::Type::kInt32 || dst_type == DataType::Type::kFloat32) {
         int32_t value = GetInt32ValueOf(source.GetConstant()->AsConstant());
-        if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
+        if (DataType::IsFloatingPointType(dst_type) && value == 0) {
           gpr = ZERO;
         } else {
           __ LoadConst32(gpr, value);
         }
       } else {
         int64_t value = GetInt64ValueOf(source.GetConstant()->AsConstant());
-        if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
+        if (DataType::IsFloatingPointType(dst_type) && value == 0) {
           gpr = ZERO;
         } else {
           __ LoadConst64(gpr, value);
         }
       }
-      if (dst_type == Primitive::kPrimFloat) {
+      if (dst_type == DataType::Type::kFloat32) {
         __ Mtc1(gpr, destination.AsFpuRegister<FpuRegister>());
-      } else if (dst_type == Primitive::kPrimDouble) {
+      } else if (dst_type == DataType::Type::kFloat64) {
         __ Dmtc1(gpr, destination.AsFpuRegister<FpuRegister>());
       }
     } else if (source.IsRegister()) {
@@ -1335,7 +1336,7 @@
         __ Move(destination.AsRegister<GpuRegister>(), source.AsRegister<GpuRegister>());
       } else {
         DCHECK(destination.IsFpuRegister());
-        if (Primitive::Is64BitType(dst_type)) {
+        if (DataType::Is64BitType(dst_type)) {
           __ Dmtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
         } else {
           __ Mtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
@@ -1348,16 +1349,16 @@
                    VectorRegisterFrom(source));
         } else {
           // Move to FPR from FPR
-          if (dst_type == Primitive::kPrimFloat) {
+          if (dst_type == DataType::Type::kFloat32) {
             __ MovS(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
           } else {
-            DCHECK_EQ(dst_type, Primitive::kPrimDouble);
+            DCHECK_EQ(dst_type, DataType::Type::kFloat64);
             __ MovD(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
           }
         }
       } else {
         DCHECK(destination.IsRegister());
-        if (Primitive::Is64BitType(dst_type)) {
+        if (DataType::Is64BitType(dst_type)) {
           __ Dmfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
         } else {
           __ Mfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
@@ -1386,13 +1387,14 @@
     if (source.IsRegister() || source.IsFpuRegister()) {
       if (unspecified_type) {
         if (source.IsRegister()) {
-          dst_type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
+          dst_type = destination.IsStackSlot() ? DataType::Type::kInt32 : DataType::Type::kInt64;
         } else {
-          dst_type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
+          dst_type =
+              destination.IsStackSlot() ? DataType::Type::kFloat32 : DataType::Type::kFloat64;
         }
       }
-      DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(dst_type)) &&
-             (source.IsFpuRegister() == Primitive::IsFloatingPointType(dst_type)));
+      DCHECK((destination.IsDoubleStackSlot() == DataType::Is64BitType(dst_type)) &&
+             (source.IsFpuRegister() == DataType::IsFloatingPointType(dst_type)));
       // Move to stack from GPR/FPR
       StoreOperandType store_type = destination.IsStackSlot() ? kStoreWord : kStoreDoubleword;
       if (source.IsRegister()) {
@@ -1441,7 +1443,7 @@
   }
 }
 
-void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, Primitive::Type type) {
+void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, DataType::Type type) {
   DCHECK(!loc1.IsConstant());
   DCHECK(!loc2.IsConstant());
 
@@ -1465,12 +1467,12 @@
     // Swap 2 FPRs
     FpuRegister r1 = loc1.AsFpuRegister<FpuRegister>();
     FpuRegister r2 = loc2.AsFpuRegister<FpuRegister>();
-    if (type == Primitive::kPrimFloat) {
+    if (type == DataType::Type::kFloat32) {
       __ MovS(FTMP, r1);
       __ MovS(r1, r2);
       __ MovS(r2, FTMP);
     } else {
-      DCHECK_EQ(type, Primitive::kPrimDouble);
+      DCHECK_EQ(type, DataType::Type::kFloat64);
       __ MovD(FTMP, r1);
       __ MovD(r1, r2);
       __ MovD(r2, FTMP);
@@ -1481,7 +1483,7 @@
     Location mem_loc = is_slot1 ? loc1 : loc2;
     LoadOperandType load_type = mem_loc.IsStackSlot() ? kLoadWord : kLoadDoubleword;
     StoreOperandType store_type = mem_loc.IsStackSlot() ? kStoreWord : kStoreDoubleword;
-    // TODO: use load_type = kLoadUnsignedWord when type == Primitive::kPrimNot.
+    // TODO: use load_type = kLoadUnsignedWord when type == DataType::Type::kReference.
     __ LoadFromOffset(load_type, TMP, SP, mem_loc.GetStackIndex());
     if (reg_loc.IsFpuRegister()) {
       __ StoreFpuToOffset(store_type,
@@ -1541,10 +1543,10 @@
   }
 }
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorMIPS64::EmitPcRelativeLinkerPatches(
     const ArenaDeque<PcRelativePatchInfo>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
     const DexFile& dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
@@ -1556,7 +1558,7 @@
   }
 }
 
-void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       pc_relative_method_patches_.size() +
@@ -1567,25 +1569,25 @@
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
-                                                                  linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        pc_relative_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        pc_relative_string_patches_, linker_patches);
   } else {
     DCHECK(pc_relative_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        pc_relative_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        pc_relative_string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   DCHECK_EQ(size, linker_patches->size());
 }
 
@@ -1858,10 +1860,10 @@
 void LocationsBuilderMIPS64::HandleBinaryOp(HBinaryOperation* instruction) {
   DCHECK_EQ(instruction->InputCount(), 2U);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       HInstruction* right = instruction->InputAt(1);
       bool can_use_imm = false;
@@ -1884,8 +1886,8 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -1897,12 +1899,12 @@
 }
 
 void InstructionCodeGeneratorMIPS64::HandleBinaryOp(HBinaryOperation* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
       Location rhs_location = locations->InAt(1);
@@ -1932,7 +1934,7 @@
         else
           __ Xor(dst, lhs, rhs_reg);
       } else if (instruction->IsAdd()) {
-        if (type == Primitive::kPrimInt) {
+        if (type == DataType::Type::kInt32) {
           if (use_imm)
             __ Addiu(dst, lhs, rhs_imm);
           else
@@ -1945,7 +1947,7 @@
         }
       } else {
         DCHECK(instruction->IsSub());
-        if (type == Primitive::kPrimInt) {
+        if (type == DataType::Type::kInt32) {
           if (use_imm)
             __ Addiu(dst, lhs, -rhs_imm);
           else
@@ -1959,18 +1961,18 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
       FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
       FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
       if (instruction->IsAdd()) {
-        if (type == Primitive::kPrimFloat)
+        if (type == DataType::Type::kFloat32)
           __ AddS(dst, lhs, rhs);
         else
           __ AddD(dst, lhs, rhs);
       } else if (instruction->IsSub()) {
-        if (type == Primitive::kPrimFloat)
+        if (type == DataType::Type::kFloat32)
           __ SubS(dst, lhs, rhs);
         else
           __ SubD(dst, lhs, rhs);
@@ -1988,10 +1990,10 @@
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2005,11 +2007,11 @@
 void InstructionCodeGeneratorMIPS64::HandleShift(HBinaryOperation* instr) {
   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
   LocationSummary* locations = instr->GetLocations();
-  Primitive::Type type = instr->GetType();
+  DataType::Type type = instr->GetType();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
       Location rhs_location = locations->InAt(1);
@@ -2025,13 +2027,13 @@
 
       if (use_imm) {
         uint32_t shift_value = rhs_imm &
-            (type == Primitive::kPrimInt ? kMaxIntShiftDistance : kMaxLongShiftDistance);
+            (type == DataType::Type::kInt32 ? kMaxIntShiftDistance : kMaxLongShiftDistance);
 
         if (shift_value == 0) {
           if (dst != lhs) {
             __ Move(dst, lhs);
           }
-        } else if (type == Primitive::kPrimInt) {
+        } else if (type == DataType::Type::kInt32) {
           if (instr->IsShl()) {
             __ Sll(dst, lhs, shift_value);
           } else if (instr->IsShr()) {
@@ -2066,7 +2068,7 @@
           }
         }
       } else {
-        if (type == Primitive::kPrimInt) {
+        if (type == DataType::Type::kInt32) {
           if (instr->IsShl()) {
             __ Sllv(dst, lhs, rhs_reg);
           } else if (instr->IsShr()) {
@@ -2112,9 +2114,9 @@
 }
 
 void LocationsBuilderMIPS64::VisitArrayGet(HArrayGet* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (type == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (type == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier
@@ -2125,7 +2127,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(type)) {
+  if (DataType::IsFloatingPointType(type)) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps in the case of an object array get with
@@ -2164,11 +2166,11 @@
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
                                         instruction->IsStringCharAt();
   switch (type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2181,7 +2183,7 @@
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2194,7 +2196,7 @@
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2207,7 +2209,7 @@
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
       if (maybe_compressed_char_at) {
         uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
@@ -2259,10 +2261,11 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
-      LoadOperandType load_type = (type == Primitive::kPrimNot) ? kLoadUnsignedWord : kLoadWord;
+      LoadOperandType load_type =
+          (type == DataType::Type::kReference) ? kLoadUnsignedWord : kLoadWord;
       if (index.IsConstant()) {
         size_t offset =
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
@@ -2274,7 +2277,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       static_assert(
           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -2334,7 +2337,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       GpuRegister out = out_loc.AsRegister<GpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2347,7 +2350,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       FpuRegister out = out_loc.AsFpuRegister<FpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2360,7 +2363,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       FpuRegister out = out_loc.AsFpuRegister<FpuRegister>();
       if (index.IsConstant()) {
         size_t offset =
@@ -2373,7 +2376,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -2418,7 +2421,7 @@
 }
 
 void LocationsBuilderMIPS64::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -2432,7 +2435,7 @@
 
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
     locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
   } else {
     locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
@@ -2448,7 +2451,7 @@
   GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();
   Location index = locations->InAt(1);
   Location value_location = locations->InAt(2);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -2456,8 +2459,8 @@
   GpuRegister base_reg = index.IsConstant() ? obj : TMP;
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
@@ -2474,8 +2477,8 @@
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
@@ -2492,7 +2495,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
@@ -2509,7 +2512,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       if (value_location.IsConstant()) {
         // Just setting null.
         uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
@@ -2624,7 +2627,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
@@ -2641,7 +2644,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
@@ -2658,7 +2661,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
       if (index.IsConstant()) {
         data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
@@ -2675,7 +2678,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -2960,24 +2963,24 @@
 }
 
 void LocationsBuilderMIPS64::VisitCompare(HCompare* compare) {
-  Primitive::Type in_type = compare->InputAt(0)->GetType();
+  DataType::Type in_type = compare->InputAt(0)->GetType();
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
 
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2991,24 +2994,24 @@
 void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   GpuRegister res = locations->Out().AsRegister<GpuRegister>();
-  Primitive::Type in_type = instruction->InputAt(0)->GetType();
+  DataType::Type in_type = instruction->InputAt(0)->GetType();
 
   //  0 if: left == right
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
       Location rhs_location = locations->InAt(1);
       bool use_imm = rhs_location.IsConstant();
       GpuRegister rhs = ZERO;
       if (use_imm) {
-        if (in_type == Primitive::kPrimLong) {
+        if (in_type == DataType::Type::kInt64) {
           int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
           if (value != 0) {
             rhs = AT;
@@ -3030,7 +3033,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
       FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
       Mips64Label done;
@@ -3052,7 +3055,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
       FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
       Mips64Label done;
@@ -3083,13 +3086,13 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->InputAt(0)->GetType()) {
     default:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       break;
@@ -3104,18 +3107,18 @@
     return;
   }
 
-  Primitive::Type type = instruction->InputAt(0)->GetType();
+  DataType::Type type = instruction->InputAt(0)->GetType();
   LocationSummary* locations = instruction->GetLocations();
   switch (type) {
     default:
       // Integer case.
       GenerateIntLongCompare(instruction->GetCondition(), /* is64bit */ false, locations);
       return;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       GenerateIntLongCompare(instruction->GetCondition(), /* is64bit */ true, locations);
       return;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
      return;
   }
@@ -3123,7 +3126,7 @@
 
 void InstructionCodeGeneratorMIPS64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -3138,10 +3141,10 @@
     __ Move(out, ZERO);
   } else {
     if (imm == -1) {
-      if (type == Primitive::kPrimInt) {
+      if (type == DataType::Type::kInt32) {
         __ Subu(out, ZERO, dividend);
       } else {
-        DCHECK_EQ(type, Primitive::kPrimLong);
+        DCHECK_EQ(type, DataType::Type::kInt64);
         __ Dsubu(out, ZERO, dividend);
       }
     } else if (out != dividend) {
@@ -3152,7 +3155,7 @@
 
 void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
 
   LocationSummary* locations = instruction->GetLocations();
   Location second = locations->InAt(1);
@@ -3165,7 +3168,7 @@
   int ctz_imm = CTZ(abs_imm);
 
   if (instruction->IsDiv()) {
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       if (ctz_imm == 1) {
         // Fast path for division by +/-2, which is very common.
         __ Srl(TMP, dividend, 31);
@@ -3179,7 +3182,7 @@
         __ Subu(out, ZERO, out);
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimLong);
+      DCHECK_EQ(type, DataType::Type::kInt64);
       if (ctz_imm == 1) {
         // Fast path for division by +/-2, which is very common.
         __ Dsrl32(TMP, dividend, 31);
@@ -3202,7 +3205,7 @@
       }
     }
   } else {
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       if (ctz_imm == 1) {
         // Fast path for modulo +/-2, which is very common.
         __ Sra(TMP, dividend, 31);
@@ -3222,7 +3225,7 @@
         __ Subu(out, out, TMP);
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimLong);
+      DCHECK_EQ(type, DataType::Type::kInt64);
       if (ctz_imm == 1) {
         // Fast path for modulo +/-2, which is very common.
         __ Dsra32(TMP, dividend, 31);
@@ -3265,17 +3268,17 @@
   GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
   int64_t imm = Int64FromConstant(second.GetConstant());
 
-  Primitive::Type type = instruction->GetResultType();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << type;
+  DataType::Type type = instruction->GetResultType();
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
 
   int64_t magic;
   int shift;
   CalculateMagicAndShiftForDivRem(imm,
-                                  (type == Primitive::kPrimLong),
+                                  (type == DataType::Type::kInt64),
                                   &magic,
                                   &shift);
 
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     __ LoadConst32(TMP, magic);
     __ MuhR6(TMP, dividend, TMP);
 
@@ -3330,8 +3333,8 @@
 
 void InstructionCodeGeneratorMIPS64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  Primitive::Type type = instruction->GetResultType();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << type;
+  DataType::Type type = instruction->GetResultType();
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
 
   LocationSummary* locations = instruction->GetLocations();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
@@ -3353,12 +3356,12 @@
     GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
     GpuRegister divisor = second.AsRegister<GpuRegister>();
     if (instruction->IsDiv()) {
-      if (type == Primitive::kPrimInt)
+      if (type == DataType::Type::kInt32)
         __ DivR6(out, dividend, divisor);
       else
         __ Ddiv(out, dividend, divisor);
     } else {
-      if (type == Primitive::kPrimInt)
+      if (type == DataType::Type::kInt32)
         __ ModR6(out, dividend, divisor);
       else
         __ Dmod(out, dividend, divisor);
@@ -3370,15 +3373,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -3390,20 +3393,20 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitDiv(HDiv* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       GenerateDivRemIntegral(instruction);
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
       FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
       FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
-      if (type == Primitive::kPrimFloat)
+      if (type == DataType::Type::kFloat32)
         __ DivS(dst, lhs, rhs);
       else
         __ DivD(dst, lhs, rhs);
@@ -3425,9 +3428,9 @@
   codegen_->AddSlowPath(slow_path);
   Location value = instruction->GetLocations()->InAt(0);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
-  if (!Primitive::IsIntegralType(type)) {
+  if (!DataType::IsIntegralType(type)) {
     LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
     return;
   }
@@ -3863,12 +3866,12 @@
 
 void InstructionCodeGeneratorMIPS64::GenerateFpCompare(IfCondition cond,
                                                        bool gt_bias,
-                                                       Primitive::Type type,
+                                                       DataType::Type type,
                                                        LocationSummary* locations) {
   GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
   FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
   FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     switch (cond) {
       case kCondEQ:
         __ CmpEqS(FTMP, lhs, rhs);
@@ -3921,7 +3924,7 @@
         UNREACHABLE();
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     switch (cond) {
       case kCondEQ:
         __ CmpEqD(FTMP, lhs, rhs);
@@ -3978,12 +3981,12 @@
 
 bool InstructionCodeGeneratorMIPS64::MaterializeFpCompare(IfCondition cond,
                                                           bool gt_bias,
-                                                          Primitive::Type type,
+                                                          DataType::Type type,
                                                           LocationSummary* input_locations,
                                                           FpuRegister dst) {
   FpuRegister lhs = input_locations->InAt(0).AsFpuRegister<FpuRegister>();
   FpuRegister rhs = input_locations->InAt(1).AsFpuRegister<FpuRegister>();
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     switch (cond) {
       case kCondEQ:
         __ CmpEqS(dst, lhs, rhs);
@@ -4024,7 +4027,7 @@
         UNREACHABLE();
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     switch (cond) {
       case kCondEQ:
         __ CmpEqD(dst, lhs, rhs);
@@ -4069,12 +4072,12 @@
 
 void InstructionCodeGeneratorMIPS64::GenerateFpCompareAndBranch(IfCondition cond,
                                                                 bool gt_bias,
-                                                                Primitive::Type type,
+                                                                DataType::Type type,
                                                                 LocationSummary* locations,
                                                                 Mips64Label* label) {
   FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
   FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
-  if (type == Primitive::kPrimFloat) {
+  if (type == DataType::Type::kFloat32) {
     switch (cond) {
       case kCondEQ:
         __ CmpEqS(FTMP, lhs, rhs);
@@ -4121,7 +4124,7 @@
         UNREACHABLE();
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     switch (cond) {
       case kCondEQ:
         __ CmpEqD(FTMP, lhs, rhs);
@@ -4215,7 +4218,7 @@
     // The condition instruction has not been materialized, use its inputs as
     // the comparison and its condition as the branch condition.
     HCondition* condition = cond->AsCondition();
-    Primitive::Type type = condition->InputAt(0)->GetType();
+    DataType::Type type = condition->InputAt(0)->GetType();
     LocationSummary* locations = cond->GetLocations();
     IfCondition if_cond = condition->GetCondition();
     Mips64Label* branch_target = true_target;
@@ -4229,11 +4232,11 @@
       default:
         GenerateIntLongCompareAndBranch(if_cond, /* is64bit */ false, locations, branch_target);
         break;
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         GenerateIntLongCompareAndBranch(if_cond, /* is64bit */ true, locations, branch_target);
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
         break;
     }
@@ -4298,8 +4301,9 @@
   HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
   HCondition* condition = cond->AsCondition();
 
-  Primitive::Type cond_type = materialized ? Primitive::kPrimInt : condition->InputAt(0)->GetType();
-  Primitive::Type dst_type = select->GetType();
+  DataType::Type cond_type =
+      materialized ? DataType::Type::kInt32 : condition->InputAt(0)->GetType();
+  DataType::Type dst_type = select->GetType();
 
   HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
   HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
@@ -4313,8 +4317,8 @@
   bool use_const_for_true_in = false;
 
   if (!cond->IsConstant()) {
-    if (!Primitive::IsFloatingPointType(cond_type)) {
-      if (!Primitive::IsFloatingPointType(dst_type)) {
+    if (!DataType::IsFloatingPointType(cond_type)) {
+      if (!DataType::IsFloatingPointType(dst_type)) {
         // Moving int/long on int/long condition.
         if (is_true_value_zero_constant) {
           // seleqz out_reg, false_reg, cond_reg
@@ -4357,7 +4361,7 @@
         }
       }
     } else {
-      if (!Primitive::IsFloatingPointType(dst_type)) {
+      if (!DataType::IsFloatingPointType(dst_type)) {
         // Moving int/long on float/double condition.
         can_move_conditionally = true;
         if (is_true_value_zero_constant) {
@@ -4403,7 +4407,7 @@
       locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
     } else {
       locations_to_set->SetInAt(0,
-                                Primitive::IsFloatingPointType(dst_type)
+                                DataType::IsFloatingPointType(dst_type)
                                     ? Location::RequiresFpuRegister()
                                     : Location::RequiresRegister());
     }
@@ -4411,7 +4415,7 @@
       locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
     } else {
       locations_to_set->SetInAt(1,
-                                Primitive::IsFloatingPointType(dst_type)
+                                DataType::IsFloatingPointType(dst_type)
                                     ? Location::RequiresFpuRegister()
                                     : Location::RequiresRegister());
     }
@@ -4420,7 +4424,7 @@
     }
 
     if (can_move_conditionally) {
-      locations_to_set->SetOut(Primitive::IsFloatingPointType(dst_type)
+      locations_to_set->SetOut(DataType::IsFloatingPointType(dst_type)
                                    ? Location::RequiresFpuRegister()
                                    : Location::RequiresRegister());
     } else {
@@ -4440,9 +4444,9 @@
   HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
   GpuRegister cond_reg = TMP;
   FpuRegister fcond_reg = FTMP;
-  Primitive::Type cond_type = Primitive::kPrimInt;
+  DataType::Type cond_type = DataType::Type::kInt32;
   bool cond_inverted = false;
-  Primitive::Type dst_type = select->GetType();
+  DataType::Type dst_type = select->GetType();
 
   if (IsBooleanValueOrMaterializedCondition(cond)) {
     cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<GpuRegister>();
@@ -4458,14 +4462,14 @@
                                                   cond_locations,
                                                   cond_reg);
         break;
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         cond_inverted = MaterializeIntLongCompare(if_cond,
                                                   /* is64bit */ true,
                                                   cond_locations,
                                                   cond_reg);
         break;
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         cond_inverted = MaterializeFpCompare(if_cond,
                                              condition->IsGtBias(),
                                              cond_type,
@@ -4484,7 +4488,7 @@
 
   switch (dst_type) {
     default:
-      if (Primitive::IsFloatingPointType(cond_type)) {
+      if (DataType::IsFloatingPointType(cond_type)) {
         __ Mfc1(cond_reg, fcond_reg);
       }
       if (true_src.IsConstant()) {
@@ -4511,8 +4515,8 @@
         __ Or(dst.AsRegister<GpuRegister>(), AT, TMP);
       }
       break;
-    case Primitive::kPrimFloat: {
-      if (!Primitive::IsFloatingPointType(cond_type)) {
+    case DataType::Type::kFloat32: {
+      if (!DataType::IsFloatingPointType(cond_type)) {
         // sel*.fmt tests bit 0 of the condition register, account for that.
         __ Sltu(TMP, ZERO, cond_reg);
         __ Mtc1(TMP, fcond_reg);
@@ -4546,8 +4550,8 @@
       }
       break;
     }
-    case Primitive::kPrimDouble: {
-      if (!Primitive::IsFloatingPointType(cond_type)) {
+    case DataType::Type::kFloat64: {
+      if (!DataType::IsFloatingPointType(cond_type)) {
         // sel*.fmt tests bit 0 of the condition register, account for that.
         __ Sltu(TMP, ZERO, cond_reg);
         __ Mtc1(TMP, fcond_reg);
@@ -4631,9 +4635,9 @@
 
 void LocationsBuilderMIPS64::HandleFieldGet(HInstruction* instruction,
                                             const FieldInfo& field_info) {
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (field_type == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (field_type == DataType::Type::kReference);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
       instruction,
       object_field_get_with_read_barrier
@@ -4643,7 +4647,7 @@
     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister());
   } else {
     // The output overlaps in the case of an object field get with
@@ -4665,7 +4669,7 @@
 
 void InstructionCodeGeneratorMIPS64::HandleFieldGet(HInstruction* instruction,
                                                     const FieldInfo& field_info) {
-  Primitive::Type type = field_info.GetFieldType();
+  DataType::Type type = field_info.GetFieldType();
   LocationSummary* locations = instruction->GetLocations();
   Location obj_loc = locations->InAt(0);
   GpuRegister obj = obj_loc.AsRegister<GpuRegister>();
@@ -4676,37 +4680,37 @@
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
   switch (type) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       load_type = kLoadUnsignedByte;
       break;
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       load_type = kLoadSignedByte;
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       load_type = kLoadSignedHalfword;
       break;
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       load_type = kLoadUnsignedHalfword;
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       load_type = kLoadWord;
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       load_type = kLoadDoubleword;
       break;
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       load_type = kLoadUnsignedWord;
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
-  if (!Primitive::IsFloatingPointType(type)) {
+  if (!DataType::IsFloatingPointType(type)) {
     DCHECK(dst_loc.IsRegister());
     GpuRegister dst = dst_loc.AsRegister<GpuRegister>();
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       // /* HeapReference<Object> */ dst = *(obj + offset)
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         Location temp_loc =
@@ -4743,7 +4747,7 @@
 
   // Memory barriers, in the case of references, are handled in the
   // previous switch statement.
-  if (is_volatile && (type != Primitive::kPrimNot)) {
+  if (is_volatile && (type != DataType::Type::kReference)) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
 }
@@ -4753,7 +4757,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
     locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
   } else {
     locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
@@ -4763,7 +4767,7 @@
 void InstructionCodeGeneratorMIPS64::HandleFieldSet(HInstruction* instruction,
                                                     const FieldInfo& field_info,
                                                     bool value_can_be_null) {
-  Primitive::Type type = field_info.GetFieldType();
+  DataType::Type type = field_info.GetFieldType();
   LocationSummary* locations = instruction->GetLocations();
   GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();
   Location value_location = locations->InAt(1);
@@ -4774,24 +4778,24 @@
   auto null_checker = GetImplicitNullChecker(instruction, codegen_);
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       store_type = kStoreByte;
       break;
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
       store_type = kStoreHalfword;
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimNot:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kReference:
       store_type = kStoreWord;
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       store_type = kStoreDoubleword;
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
@@ -4804,14 +4808,14 @@
     int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
     __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
   } else {
-    if (!Primitive::IsFloatingPointType(type)) {
+    if (!DataType::IsFloatingPointType(type)) {
       DCHECK(value_location.IsRegister());
       GpuRegister src = value_location.AsRegister<GpuRegister>();
       if (kPoisonHeapReferences && needs_write_barrier) {
         // Note that in the case where `value` is a null reference,
         // we do not enter this block, as a null reference does not
         // need poisoning.
-        DCHECK_EQ(type, Primitive::kPrimNot);
+        DCHECK_EQ(type, DataType::Type::kReference);
         __ PoisonHeapReference(TMP, src);
         __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
       } else {
@@ -6246,15 +6250,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -6266,27 +6270,27 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitMul(HMul* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
       GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>();
-      if (type == Primitive::kPrimInt)
+      if (type == DataType::Type::kInt32)
         __ MulR6(dst, lhs, rhs);
       else
         __ Dmul(dst, lhs, rhs);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
       FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
       FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
-      if (type == Primitive::kPrimFloat)
+      if (type == DataType::Type::kFloat32)
         __ MulS(dst, lhs, rhs);
       else
         __ MulD(dst, lhs, rhs);
@@ -6301,14 +6305,14 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -6319,25 +6323,25 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNeg(HNeg* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
       GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
-      if (type == Primitive::kPrimInt)
+      if (type == DataType::Type::kInt32)
         __ Subu(dst, ZERO, src);
       else
         __ Dsubu(dst, ZERO, src);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
       FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
-      if (type == Primitive::kPrimFloat)
+      if (type == DataType::Type::kFloat32)
         __ NegS(dst, src);
       else
         __ NegD(dst, src);
@@ -6352,7 +6356,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
   InvokeRuntimeCallingConvention calling_convention;
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
 }
@@ -6376,7 +6380,7 @@
   } else {
     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   }
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) {
@@ -6405,12 +6409,12 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNot(HNot* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   LocationSummary* locations = instruction->GetLocations();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
       GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
       __ Nor(dst, src, ZERO);
@@ -6519,22 +6523,22 @@
 }
 
 void LocationsBuilderMIPS64::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   LocationSummary::CallKind call_kind =
-      Primitive::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
-                                           : LocationSummary::kNoCall;
+      DataType::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
+                                          : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
       locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
@@ -6548,19 +6552,20 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitRem(HRem* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       GenerateDivRemIntegral(instruction);
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
-      QuickEntrypointEnum entrypoint = (type == Primitive::kPrimFloat) ? kQuickFmodf : kQuickFmod;
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
+      QuickEntrypointEnum entrypoint =
+          (type == DataType::Type::kFloat32) ? kQuickFmodf : kQuickFmod;
       codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         CheckEntrypointTypes<kQuickFmodf, float, float, float>();
       } else {
         CheckEntrypointTypes<kQuickFmod, double, double, double>();
@@ -6591,7 +6596,7 @@
 
 void LocationsBuilderMIPS64::VisitReturn(HReturn* ret) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
-  Primitive::Type return_type = ret->InputAt(0)->GetType();
+  DataType::Type return_type = ret->InputAt(0)->GetType();
   locations->SetInAt(0, Mips64ReturnLocation(return_type));
 }
 
@@ -6760,24 +6765,24 @@
 }
 
 void LocationsBuilderMIPS64::VisitTypeConversion(HTypeConversion* conversion) {
-  Primitive::Type input_type = conversion->GetInputType();
-  Primitive::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
   DCHECK_NE(input_type, result_type);
 
-  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
-      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+  if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
+      (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
     LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
   }
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion);
 
-  if (Primitive::IsFloatingPointType(input_type)) {
+  if (DataType::IsFloatingPointType(input_type)) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(0, Location::RequiresRegister());
   }
 
-  if (Primitive::IsFloatingPointType(result_type)) {
+  if (DataType::IsFloatingPointType(result_type)) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -6786,21 +6791,21 @@
 
 void InstructionCodeGeneratorMIPS64::VisitTypeConversion(HTypeConversion* conversion) {
   LocationSummary* locations = conversion->GetLocations();
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
 
   DCHECK_NE(input_type, result_type);
 
-  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
+  if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
     GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
     GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
 
     switch (result_type) {
-      case Primitive::kPrimChar:
+      case DataType::Type::kUint16:
         __ Andi(dst, src, 0xFFFF);
         break;
-      case Primitive::kPrimByte:
-        if (input_type == Primitive::kPrimLong) {
+      case DataType::Type::kInt8:
+        if (input_type == DataType::Type::kInt64) {
           // Type conversion from long to types narrower than int is a result of code
           // transformations. To avoid unpredictable results for SEB and SEH, we first
           // need to sign-extend the low 32-bit value into bits 32 through 63.
@@ -6810,8 +6815,8 @@
           __ Seb(dst, src);
         }
         break;
-      case Primitive::kPrimShort:
-        if (input_type == Primitive::kPrimLong) {
+      case DataType::Type::kInt16:
+        if (input_type == DataType::Type::kInt64) {
           // Type conversion from long to types narrower than int is a result of code
           // transformations. To avoid unpredictable results for SEB and SEH, we first
           // need to sign-extend the low 32-bit value into bits 32 through 63.
@@ -6821,12 +6826,12 @@
           __ Seh(dst, src);
         }
         break;
-      case Primitive::kPrimInt:
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt32:
+      case DataType::Type::kInt64:
         // Sign-extend 32-bit int into bits 32 through 63 for int-to-long and long-to-int
         // conversions, except when the input and output registers are the same and we are not
         // converting longs to shorter types. In these cases, do nothing.
-        if ((input_type == Primitive::kPrimLong) || (dst != src)) {
+        if ((input_type == DataType::Type::kInt64) || (dst != src)) {
           __ Sll(dst, src, 0);
         }
         break;
@@ -6835,49 +6840,49 @@
         LOG(FATAL) << "Unexpected type conversion from " << input_type
                    << " to " << result_type;
     }
-  } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
+  } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
     FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
     GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
-    if (input_type == Primitive::kPrimLong) {
+    if (input_type == DataType::Type::kInt64) {
       __ Dmtc1(src, FTMP);
-      if (result_type == Primitive::kPrimFloat) {
+      if (result_type == DataType::Type::kFloat32) {
         __ Cvtsl(dst, FTMP);
       } else {
         __ Cvtdl(dst, FTMP);
       }
     } else {
       __ Mtc1(src, FTMP);
-      if (result_type == Primitive::kPrimFloat) {
+      if (result_type == DataType::Type::kFloat32) {
         __ Cvtsw(dst, FTMP);
       } else {
         __ Cvtdw(dst, FTMP);
       }
     }
-  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
-    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
+  } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
+    CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
     GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
     FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
 
-    if (result_type == Primitive::kPrimLong) {
-      if (input_type == Primitive::kPrimFloat) {
+    if (result_type == DataType::Type::kInt64) {
+      if (input_type == DataType::Type::kFloat32) {
         __ TruncLS(FTMP, src);
       } else {
         __ TruncLD(FTMP, src);
       }
       __ Dmfc1(dst, FTMP);
     } else {
-      if (input_type == Primitive::kPrimFloat) {
+      if (input_type == DataType::Type::kFloat32) {
         __ TruncWS(FTMP, src);
       } else {
         __ TruncWD(FTMP, src);
       }
       __ Mfc1(dst, FTMP);
     }
-  } else if (Primitive::IsFloatingPointType(result_type) &&
-             Primitive::IsFloatingPointType(input_type)) {
+  } else if (DataType::IsFloatingPointType(result_type) &&
+             DataType::IsFloatingPointType(input_type)) {
     FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
     FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
-    if (result_type == Primitive::kPrimFloat) {
+    if (result_type == DataType::Type::kFloat32) {
       __ Cvtsd(dst, src);
     } else {
       __ Cvtds(dst, src);
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 3035621..2a95b37 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -79,8 +79,8 @@
   InvokeDexCallingConventionVisitorMIPS64() {}
   virtual ~InvokeDexCallingConventionVisitorMIPS64() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE;
   Location GetMethodLocation() const OVERRIDE;
 
  private:
@@ -98,7 +98,7 @@
                           kRuntimeParameterFpuRegistersLength,
                           kMips64PointerSize) {}
 
-  Location GetReturnLocation(Primitive::Type return_type);
+  Location GetReturnLocation(DataType::Type return_type);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
@@ -114,16 +114,16 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return Location::RegisterLocation(A0);
   }
-  Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::RegisterLocation(V0);
   }
-  Location GetSetValueLocation(Primitive::Type type ATTRIBUTE_UNUSED,
+  Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,
                                bool is_instance) const OVERRIDE {
     return is_instance
         ? Location::RegisterLocation(A2)
         : Location::RegisterLocation(A1);
   }
-  Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::FpuRegisterLocation(F0);
   }
 
@@ -306,19 +306,19 @@
                                        Mips64Label* label);
   void GenerateFpCompare(IfCondition cond,
                          bool gt_bias,
-                         Primitive::Type type,
+                         DataType::Type type,
                          LocationSummary* locations);
   // When the function returns `false` it means that the condition holds if `dst` is non-zero
   // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero
   // `dst` are exchanged.
   bool MaterializeFpCompare(IfCondition cond,
                             bool gt_bias,
-                            Primitive::Type type,
+                            DataType::Type type,
                             LocationSummary* input_locations,
                             FpuRegister dst);
   void GenerateFpCompareAndBranch(IfCondition cond,
                                   bool gt_bias,
-                                  Primitive::Type type,
+                                  DataType::Type type,
                                   LocationSummary* locations,
                                   Mips64Label* label);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
@@ -374,7 +374,7 @@
   const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
 
   // Emit linker patches.
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
 
   // Fast path implementation of ReadBarrier::Barrier for a heap
@@ -497,14 +497,14 @@
   void Finalize(CodeAllocator* allocator) OVERRIDE;
 
   // Code generation helpers.
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
 
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
 
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
 
-  void SwapLocations(Location loc1, Location loc2, Primitive::Type type);
+  void SwapLocations(Location loc1, Location loc2, DataType::Type type);
 
   // Generate code to invoke a runtime entry point.
   void InvokeRuntime(QuickEntrypointEnum entrypoint,
@@ -522,7 +522,7 @@
 
   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { return false; }
+  bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE { return false; }
 
   // Check if the desired_string_load_kind is supported. If it is, return it,
   // otherwise return a fall-back kind that should be used instead.
@@ -546,7 +546,7 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
-                              Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
+                              DataType::Type type ATTRIBUTE_UNUSED) OVERRIDE {
     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64";
   }
 
@@ -643,9 +643,9 @@
                                           const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
 
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
-                                   ArenaVector<LinkerPatch>* linker_patches);
+                                   ArenaVector<linker::LinkerPatch>* linker_patches);
 
   // Labels for each block that will be compiled.
   Mips64Label* block_labels_;  // Indexed by block id.
diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc
index 18a55c8..5d5623b 100644
--- a/compiler/optimizing/code_generator_vector_arm64.cc
+++ b/compiler/optimizing/code_generator_vector_arm64.cc
@@ -41,17 +41,17 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   HInstruction* input = instruction->InputAt(0);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, ARM64EncodableConstantOrRegister(input, instruction));
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       if (input->IsConstant() &&
           Arm64CanEncodeConstantAsImmediate(input->AsConstant(), instruction)) {
         locations->SetInAt(0, Location::ConstantLocation(input->AsConstant()));
@@ -72,8 +72,8 @@
   Location src_loc = locations->InAt(0);
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Movi(dst.V16B(), Int64ConstantFrom(src_loc));
@@ -81,8 +81,8 @@
         __ Dup(dst.V16B(), InputRegisterAt(instruction, 0));
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Movi(dst.V8H(), Int64ConstantFrom(src_loc));
@@ -90,7 +90,7 @@
         __ Dup(dst.V8H(), InputRegisterAt(instruction, 0));
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Movi(dst.V4S(), Int64ConstantFrom(src_loc));
@@ -98,7 +98,7 @@
         __ Dup(dst.V4S(), InputRegisterAt(instruction, 0));
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Movi(dst.V2D(), Int64ConstantFrom(src_loc));
@@ -106,7 +106,7 @@
         __ Dup(dst.V2D(), XRegisterFrom(src_loc));
       }
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Fmov(dst.V4S(), src_loc.GetConstant()->AsFloatConstant()->GetValue());
@@ -114,7 +114,7 @@
         __ Dup(dst.V4S(), VRegisterFrom(src_loc).V4S(), 0);
       }
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (src_loc.IsConstant()) {
         __ Fmov(dst.V2D(), src_loc.GetConstant()->AsDoubleConstant()->GetValue());
@@ -131,17 +131,17 @@
 void LocationsBuilderARM64::VisitVecExtractScalar(HVecExtractScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
@@ -155,16 +155,16 @@
   LocationSummary* locations = instruction->GetLocations();
   VRegister src = VRegisterFrom(locations->InAt(0));
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Umov(OutputRegister(instruction), src.V4S(), 0);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Umov(OutputRegister(instruction), src.V2D(), 0);
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 4u);
       DCHECK(locations->InAt(0).Equals(locations->Out()));  // no code required
@@ -179,19 +179,19 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         instruction->IsVecNot() ? Location::kOutputOverlap
                                                 : Location::kNoOutputOverlap);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -210,7 +210,7 @@
   VRegister src = VRegisterFrom(locations->InAt(0));
   VRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       switch (instruction->GetKind()) {
         case HVecReduce::kSum:
@@ -224,7 +224,7 @@
           break;
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       switch (instruction->GetKind()) {
         case HVecReduce::kSum:
@@ -249,9 +249,9 @@
   LocationSummary* locations = instruction->GetLocations();
   VRegister src = VRegisterFrom(locations->InAt(0));
   VRegister dst = VRegisterFrom(locations->Out());
-  Primitive::Type from = instruction->GetInputType();
-  Primitive::Type to = instruction->GetResultType();
-  if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+  DataType::Type from = instruction->GetInputType();
+  DataType::Type to = instruction->GetResultType();
+  if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
     DCHECK_EQ(4u, instruction->GetVectorLength());
     __ Scvtf(dst.V4S(), src.V4S());
   } else {
@@ -268,28 +268,28 @@
   VRegister src = VRegisterFrom(locations->InAt(0));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Neg(dst.V16B(), src.V16B());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Neg(dst.V8H(), src.V8H());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Neg(dst.V4S(), src.V4S());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Neg(dst.V2D(), src.V2D());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fneg(dst.V4S(), src.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fneg(dst.V2D(), src.V2D());
       break;
@@ -308,28 +308,28 @@
   VRegister src = VRegisterFrom(locations->InAt(0));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Abs(dst.V16B(), src.V16B());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Abs(dst.V8H(), src.V8H());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Abs(dst.V4S(), src.V4S());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Abs(dst.V2D(), src.V2D());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fabs(dst.V4S(), src.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fabs(dst.V2D(), src.V2D());
       break;
@@ -348,16 +348,16 @@
   VRegister src = VRegisterFrom(locations->InAt(0));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:  // special case boolean-not
+    case DataType::Type::kBool:  // special case boolean-not
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Movi(dst.V16B(), 1);
       __ Eor(dst.V16B(), dst.V16B(), src.V16B());
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       __ Not(dst.V16B(), src.V16B());  // lanes do not matter
       break;
     default:
@@ -370,14 +370,14 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -398,28 +398,28 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Add(dst.V16B(), lhs.V16B(), rhs.V16B());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Add(dst.V8H(), lhs.V8H(), rhs.V8H());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Add(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Add(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fadd(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fadd(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
@@ -439,7 +439,7 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -451,8 +451,8 @@
             : __ Shadd(dst.V16B(), lhs.V16B(), rhs.V16B());
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -480,28 +480,28 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Sub(dst.V16B(), lhs.V16B(), rhs.V16B());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Sub(dst.V8H(), lhs.V8H(), rhs.V8H());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Sub(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Sub(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fsub(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fsub(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
@@ -521,24 +521,24 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Mul(dst.V16B(), lhs.V16B(), rhs.V16B());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Mul(dst.V8H(), lhs.V8H(), rhs.V8H());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Mul(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fmul(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fmul(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
@@ -558,11 +558,11 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Fdiv(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Fdiv(dst.V2D(), lhs.V2D(), rhs.V2D());
       break;
@@ -582,7 +582,7 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umin(dst.V16B(), lhs.V16B(), rhs.V16B());
@@ -590,8 +590,8 @@
         __ Smin(dst.V16B(), lhs.V16B(), rhs.V16B());
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umin(dst.V8H(), lhs.V8H(), rhs.V8H());
@@ -599,7 +599,7 @@
         __ Smin(dst.V8H(), lhs.V8H(), rhs.V8H());
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umin(dst.V4S(), lhs.V4S(), rhs.V4S());
@@ -607,12 +607,12 @@
         __ Smin(dst.V4S(), lhs.V4S(), rhs.V4S());
       }
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ Fmin(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ Fmin(dst.V2D(), lhs.V2D(), rhs.V2D());
@@ -633,7 +633,7 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umax(dst.V16B(), lhs.V16B(), rhs.V16B());
@@ -641,8 +641,8 @@
         __ Smax(dst.V16B(), lhs.V16B(), rhs.V16B());
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umax(dst.V8H(), lhs.V8H(), rhs.V8H());
@@ -650,7 +650,7 @@
         __ Smax(dst.V8H(), lhs.V8H(), rhs.V8H());
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Umax(dst.V4S(), lhs.V4S(), rhs.V4S());
@@ -658,12 +658,12 @@
         __ Smax(dst.V4S(), lhs.V4S(), rhs.V4S());
       }
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ Fmax(dst.V4S(), lhs.V4S(), rhs.V4S());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ Fmax(dst.V2D(), lhs.V2D(), rhs.V2D());
@@ -684,14 +684,14 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ And(dst.V16B(), lhs.V16B(), rhs.V16B());  // lanes do not matter
       break;
     default:
@@ -718,14 +718,14 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Orr(dst.V16B(), lhs.V16B(), rhs.V16B());  // lanes do not matter
       break;
     default:
@@ -744,14 +744,14 @@
   VRegister rhs = VRegisterFrom(locations->InAt(1));
   VRegister dst = VRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       __ Eor(dst.V16B(), lhs.V16B(), rhs.V16B());  // lanes do not matter
       break;
     default:
@@ -764,11 +764,11 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -789,20 +789,20 @@
   VRegister dst = VRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Shl(dst.V16B(), lhs.V16B(), value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Shl(dst.V8H(), lhs.V8H(), value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Shl(dst.V4S(), lhs.V4S(), value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Shl(dst.V2D(), lhs.V2D(), value);
       break;
@@ -822,20 +822,20 @@
   VRegister dst = VRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Sshr(dst.V16B(), lhs.V16B(), value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Sshr(dst.V8H(), lhs.V8H(), value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Sshr(dst.V4S(), lhs.V4S(), value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Sshr(dst.V2D(), lhs.V2D(), value);
       break;
@@ -855,20 +855,20 @@
   VRegister dst = VRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Ushr(dst.V16B(), lhs.V16B(), value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Ushr(dst.V8H(), lhs.V8H(), value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Ushr(dst.V4S(), lhs.V4S(), value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Ushr(dst.V2D(), lhs.V2D(), value);
       break;
@@ -887,18 +887,18 @@
   bool is_zero = IsZeroBitPattern(input);
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister());
@@ -925,21 +925,21 @@
 
   // Set required elements.
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ Mov(dst.V16B(), 0, InputRegisterAt(instruction, 0));
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Mov(dst.V8H(), 0, InputRegisterAt(instruction, 0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Mov(dst.V4S(), 0, InputRegisterAt(instruction, 0));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Mov(dst.V2D(), 0, InputRegisterAt(instruction, 0));
       break;
@@ -949,20 +949,18 @@
   }
 }
 
-void LocationsBuilderARM64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputAccumulatorIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulRightIndex, Location::RequiresFpuRegister());
-      DCHECK_EQ(HVecMultiplyAccumulate::kInputAccumulatorIndex, 0);
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     default:
@@ -971,35 +969,42 @@
   }
 }
 
+void LocationsBuilderARM64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
 // Some early revisions of the Cortex-A53 have an erratum (835769) whereby it is possible for a
 // 64-bit scalar multiply-accumulate instruction in AArch64 state to generate an incorrect result.
 // However vector MultiplyAccumulate instruction is not affected.
-void InstructionCodeGeneratorARM64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = instr->GetLocations();
-  VRegister acc = VRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputAccumulatorIndex));
-  VRegister left = VRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulLeftIndex));
-  VRegister right = VRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulRightIndex));
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-      DCHECK_EQ(16u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+void InstructionCodeGeneratorARM64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  VRegister acc = VRegisterFrom(locations->InAt(0));
+  VRegister left = VRegisterFrom(locations->InAt(1));
+  VRegister right = VRegisterFrom(locations->InAt(2));
+
+  DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ Mla(acc.V16B(), left.V16B(), right.V16B());
       } else {
         __ Mls(acc.V16B(), left.V16B(), right.V16B());
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      DCHECK_EQ(8u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ Mla(acc.V8H(), left.V8H(), right.V8H());
       } else {
         __ Mls(acc.V8H(), left.V8H(), right.V8H());
       }
       break;
-    case Primitive::kPrimInt:
-      DCHECK_EQ(4u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ Mla(acc.V4S(), left.V4S(), right.V4S());
       } else {
         __ Mls(acc.V4S(), left.V4S(), right.V4S());
@@ -1007,6 +1012,186 @@
       break;
     default:
       LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
+}
+
+void LocationsBuilderARM64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+  // Some conversions require temporary registers.
+  LocationSummary* locations = instruction->GetLocations();
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
+  switch (a->GetPackedType()) {
+    case DataType::Type::kInt8:
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt64:
+          locations->AddTemp(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          FALLTHROUGH_INTENDED;
+        case DataType::Type::kInt32:
+          locations->AddTemp(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+        default:
+          break;
+      }
+      break;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      if (instruction->GetPackedType() == DataType::Type::kInt64) {
+        locations->AddTemp(Location::RequiresFpuRegister());
+        locations->AddTemp(Location::RequiresFpuRegister());
+      }
+      break;
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      if (instruction->GetPackedType() == a->GetPackedType()) {
+        locations->AddTemp(Location::RequiresFpuRegister());
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  VRegister acc = VRegisterFrom(locations->InAt(0));
+  VRegister left = VRegisterFrom(locations->InAt(1));
+  VRegister right = VRegisterFrom(locations->InAt(2));
+
+  DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+  // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
+  switch (a->GetPackedType()) {
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+          DCHECK_EQ(8u, instruction->GetVectorLength());
+          __ Sabal(acc.V8H(), left.V8B(), right.V8B());
+          __ Sabal2(acc.V8H(), left.V16B(), right.V16B());
+          break;
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VRegister tmp1 = VRegisterFrom(locations->GetTemp(0));
+          VRegister tmp2 = VRegisterFrom(locations->GetTemp(1));
+          __ Sxtl(tmp1.V8H(), left.V8B());
+          __ Sxtl(tmp2.V8H(), right.V8B());
+          __ Sabal(acc.V4S(), tmp1.V4H(), tmp2.V4H());
+          __ Sabal2(acc.V4S(), tmp1.V8H(), tmp2.V8H());
+          __ Sxtl2(tmp1.V8H(), left.V16B());
+          __ Sxtl2(tmp2.V8H(), right.V16B());
+          __ Sabal(acc.V4S(), tmp1.V4H(), tmp2.V4H());
+          __ Sabal2(acc.V4S(), tmp1.V8H(), tmp2.V8H());
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VRegister tmp1 = VRegisterFrom(locations->GetTemp(0));
+          VRegister tmp2 = VRegisterFrom(locations->GetTemp(1));
+          VRegister tmp3 = VRegisterFrom(locations->GetTemp(2));
+          VRegister tmp4 = VRegisterFrom(locations->GetTemp(3));
+          __ Sxtl(tmp1.V8H(), left.V8B());
+          __ Sxtl(tmp2.V8H(), right.V8B());
+          __ Sxtl(tmp3.V4S(), tmp1.V4H());
+          __ Sxtl(tmp4.V4S(), tmp2.V4H());
+          __ Sabal(acc.V2D(), tmp3.V2S(), tmp4.V2S());
+          __ Sabal2(acc.V2D(), tmp3.V4S(), tmp4.V4S());
+          __ Sxtl2(tmp3.V4S(), tmp1.V8H());
+          __ Sxtl2(tmp4.V4S(), tmp2.V8H());
+          __ Sabal(acc.V2D(), tmp3.V2S(), tmp4.V2S());
+          __ Sabal2(acc.V2D(), tmp3.V4S(), tmp4.V4S());
+          __ Sxtl2(tmp1.V8H(), left.V16B());
+          __ Sxtl2(tmp2.V8H(), right.V16B());
+          __ Sxtl(tmp3.V4S(), tmp1.V4H());
+          __ Sxtl(tmp4.V4S(), tmp2.V4H());
+          __ Sabal(acc.V2D(), tmp3.V2S(), tmp4.V2S());
+          __ Sabal2(acc.V2D(), tmp3.V4S(), tmp4.V4S());
+          __ Sxtl2(tmp3.V4S(), tmp1.V8H());
+          __ Sxtl2(tmp4.V4S(), tmp2.V8H());
+          __ Sabal(acc.V2D(), tmp3.V2S(), tmp4.V2S());
+          __ Sabal2(acc.V2D(), tmp3.V4S(), tmp4.V4S());
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32:
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          __ Sabal(acc.V4S(), left.V4H(), right.V4H());
+          __ Sabal2(acc.V4S(), left.V8H(), right.V8H());
+          break;
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VRegister tmp1 = VRegisterFrom(locations->GetTemp(0));
+          VRegister tmp2 = VRegisterFrom(locations->GetTemp(1));
+          __ Sxtl(tmp1.V4S(), left.V4H());
+          __ Sxtl(tmp2.V4S(), right.V4H());
+          __ Sabal(acc.V2D(), tmp1.V2S(), tmp2.V2S());
+          __ Sabal2(acc.V2D(), tmp1.V4S(), tmp2.V4S());
+          __ Sxtl2(tmp1.V4S(), left.V8H());
+          __ Sxtl2(tmp2.V4S(), right.V8H());
+          __ Sabal(acc.V2D(), tmp1.V2S(), tmp2.V2S());
+          __ Sabal2(acc.V2D(), tmp1.V4S(), tmp2.V4S());
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VRegister tmp = VRegisterFrom(locations->GetTemp(0));
+          __ Sub(tmp.V4S(), left.V4S(), right.V4S());
+          __ Abs(tmp.V4S(), tmp.V4S());
+          __ Add(acc.V4S(), acc.V4S(), tmp.V4S());
+          break;
+        }
+        case DataType::Type::kInt64:
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          __ Sabal(acc.V2D(), left.V2S(), right.V2S());
+          __ Sabal2(acc.V2D(), left.V4S(), right.V4S());
+          break;
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt64:
+      DCHECK_EQ(2u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VRegister tmp = VRegisterFrom(locations->GetTemp(0));
+          __ Sub(tmp.V2D(), left.V2D(), right.V2D());
+          __ Abs(tmp.V2D(), tmp.V2D());
+          __ Add(acc.V2D(), acc.V2D(), tmp.V2D());
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
   }
 }
 
@@ -1016,14 +1201,14 @@
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -1080,13 +1265,13 @@
 
 void InstructionCodeGeneratorARM64::VisitVecLoad(HVecLoad* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VRegister reg = VRegisterFrom(locations->Out());
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register scratch;
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
       if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
@@ -1114,13 +1299,13 @@
         return;
       }
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ Ldr(reg, VecAddress(instruction, &temps, size, instruction->IsStringCharAt(), &scratch));
@@ -1137,20 +1322,20 @@
 
 void InstructionCodeGeneratorARM64::VisitVecStore(HVecStore* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VRegister reg = VRegisterFrom(locations->InAt(2));
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register scratch;
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ Str(reg, VecAddress(instruction, &temps, size, /*is_string_char_at*/ false, &scratch));
diff --git a/compiler/optimizing/code_generator_vector_arm_vixl.cc b/compiler/optimizing/code_generator_vector_arm_vixl.cc
index 7a11dff..333d108 100644
--- a/compiler/optimizing/code_generator_vector_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_vector_arm_vixl.cc
@@ -35,11 +35,11 @@
 void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
@@ -53,17 +53,17 @@
   LocationSummary* locations = instruction->GetLocations();
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0));
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vdup(Untyped16, dst, InputRegisterAt(instruction, 0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vdup(Untyped32, dst, InputRegisterAt(instruction, 0));
       break;
@@ -85,16 +85,16 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         instruction->IsVecNot() ? Location::kOutputOverlap
                                                 : Location::kNoOutputOverlap);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -129,16 +129,16 @@
   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vneg(DataTypeValue::S8, dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vneg(DataTypeValue::S16, dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vneg(DataTypeValue::S32, dst, src);
       break;
@@ -157,16 +157,16 @@
   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vabs(DataTypeValue::S8, dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vabs(DataTypeValue::S16, dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vabs(DataTypeValue::S32, dst, src);
       break;
@@ -185,15 +185,15 @@
   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:  // special case boolean-not
+    case DataType::Type::kBool:  // special case boolean-not
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vmov(I8, dst, 1);
       __ Veor(dst, dst, src);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       __ Vmvn(I8, dst, src);  // lanes do not matter
       break;
     default:
@@ -206,11 +206,11 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -231,16 +231,16 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vadd(I8, dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vadd(I16, dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vadd(I32, dst, lhs, rhs);
       break;
@@ -260,7 +260,7 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -272,8 +272,8 @@
             : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -301,16 +301,16 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vsub(I8, dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vsub(I16, dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vsub(I32, dst, lhs, rhs);
       break;
@@ -330,16 +330,16 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vmul(I8, dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vmul(I16, dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vmul(I32, dst, lhs, rhs);
       break;
@@ -367,7 +367,7 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
@@ -375,8 +375,8 @@
         __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
@@ -384,7 +384,7 @@
         __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmin(DataTypeValue::U32, dst, lhs, rhs);
@@ -408,7 +408,7 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
@@ -416,8 +416,8 @@
         __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
@@ -425,7 +425,7 @@
         __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Vmax(DataTypeValue::U32, dst, lhs, rhs);
@@ -449,11 +449,11 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       __ Vand(I8, dst, lhs, rhs);
       break;
     default:
@@ -480,11 +480,11 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       __ Vorr(I8, dst, lhs, rhs);
       break;
     default:
@@ -503,11 +503,11 @@
   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       __ Veor(I8, dst, lhs, rhs);
       break;
     default:
@@ -520,10 +520,10 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -544,16 +544,16 @@
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vshl(I8, dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vshl(I16, dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vshl(I32, dst, lhs, value);
       break;
@@ -573,16 +573,16 @@
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::S8, dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::S16, dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::S32, dst, lhs, value);
       break;
@@ -602,16 +602,16 @@
   vixl32::DRegister dst = DRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::U8, dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::U16, dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Vshr(DataTypeValue::U32, dst, lhs, value);
       break;
@@ -629,12 +629,40 @@
   LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
-void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LOG(FATAL) << "No SIMD for " << instr->GetId();
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
-void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LOG(FATAL) << "No SIMD for " << instr->GetId();
+void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+}
+
+void LocationsBuilderARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
@@ -649,11 +677,11 @@
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -679,7 +707,7 @@
   vixl32::Register base = InputRegisterAt(instruction, 0);
 
   Location index = locations->InAt(1);
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
   size_t shift = ComponentSizeShiftWidth(size);
 
@@ -705,7 +733,7 @@
   vixl32::Register base = InputRegisterAt(instruction, 0);
 
   Location index = locations->InAt(1);
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
   size_t shift = ComponentSizeShiftWidth(size);
 
@@ -732,11 +760,11 @@
   UseScratchRegisterScope temps(GetVIXLAssembler());
   vixl32::Register scratch;
 
-  DCHECK(instruction->GetPackedType() != Primitive::kPrimChar || !instruction->IsStringCharAt());
+  DCHECK(instruction->GetPackedType() != DataType::Type::kUint16 || !instruction->IsStringCharAt());
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
@@ -746,8 +774,8 @@
             VecAddressUnaligned(instruction, &temps, &scratch));
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
@@ -757,7 +785,7 @@
             VecAddressUnaligned(instruction, &temps, &scratch));
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
@@ -782,8 +810,8 @@
   UseScratchRegisterScope temps(GetVIXLAssembler());
   vixl32::Register scratch;
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
@@ -793,8 +821,8 @@
                 VecAddressUnaligned(instruction, &temps, &scratch));
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
@@ -804,7 +832,7 @@
                 VecAddressUnaligned(instruction, &temps, &scratch));
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (IsWordAligned(instruction)) {
         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
diff --git a/compiler/optimizing/code_generator_vector_mips.cc b/compiler/optimizing/code_generator_vector_mips.cc
index c2fbf7f..c25f5ac 100644
--- a/compiler/optimizing/code_generator_vector_mips.cc
+++ b/compiler/optimizing/code_generator_vector_mips.cc
@@ -26,17 +26,17 @@
 void LocationsBuilderMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -50,33 +50,33 @@
   LocationSummary* locations = instruction->GetLocations();
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, locations->InAt(0).AsRegister<Register>());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, locations->InAt(0).AsRegister<Register>());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, locations->InAt(0).AsRegister<Register>());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ Mtc1(locations->InAt(0).AsRegisterPairLow<Register>(), FTMP);
       __ MoveToFpuHigh(locations->InAt(0).AsRegisterPairHigh<Register>(), FTMP);
       __ ReplicateFPToVectorRegister(dst, FTMP, /* is_double */ true);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ ReplicateFPToVectorRegister(dst,
                                      locations->InAt(0).AsFpuRegister<FRegister>(),
                                      /* is_double */ false);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ ReplicateFPToVectorRegister(dst,
                                      locations->InAt(0).AsFpuRegister<FRegister>(),
@@ -100,19 +100,19 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         instruction->IsVecNot() ? Location::kOutputOverlap
                                                 : Location::kNoOutputOverlap);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         (instruction->IsVecNeg() || instruction->IsVecAbs())
@@ -141,9 +141,9 @@
   LocationSummary* locations = instruction->GetLocations();
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
-  Primitive::Type from = instruction->GetInputType();
-  Primitive::Type to = instruction->GetResultType();
-  if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+  DataType::Type from = instruction->GetInputType();
+  DataType::Type to = instruction->GetResultType();
+  if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
     DCHECK_EQ(4u, instruction->GetVectorLength());
     __ Ffint_sW(dst, src);
   } else {
@@ -160,33 +160,33 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, ZERO);
       __ SubvB(dst, dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, ZERO);
       __ SubvH(dst, dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ SubvW(dst, dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ SubvD(dst, dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ FsubW(dst, dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ FsubD(dst, dst, src);
@@ -206,34 +206,34 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, ZERO);       // all zeroes
       __ Add_aB(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, ZERO);       // all zeroes
       __ Add_aH(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);       // all zeroes
       __ Add_aW(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);       // all zeroes
       __ Add_aD(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ LdiW(dst, -1);          // all ones
       __ SrliW(dst, dst, 1);
       __ AndV(dst, dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ LdiD(dst, -1);          // all ones
       __ SrliD(dst, dst, 1);
@@ -254,18 +254,18 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:  // special case boolean-not
+    case DataType::Type::kBool:  // special case boolean-not
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ LdiB(dst, 1);
       __ XorV(dst, dst, src);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ NorV(dst, src, src);  // lanes do not matter
@@ -280,14 +280,14 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -308,28 +308,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ AddvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ AddvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ AddvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ AddvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FaddW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FaddD(dst, lhs, rhs);
       break;
@@ -349,7 +349,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -361,8 +361,8 @@
             : __ Ave_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -390,28 +390,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SubvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SubvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SubvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SubvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FsubW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FsubD(dst, lhs, rhs);
       break;
@@ -431,28 +431,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ MulvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ MulvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ MulvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ MulvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FmulW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FmulD(dst, lhs, rhs);
       break;
@@ -472,11 +472,11 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FdivW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FdivD(dst, lhs, rhs);
       break;
@@ -496,7 +496,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uB(dst, lhs, rhs);
@@ -504,8 +504,8 @@
         __ Min_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uH(dst, lhs, rhs);
@@ -513,7 +513,7 @@
         __ Min_sH(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uW(dst, lhs, rhs);
@@ -521,7 +521,7 @@
         __ Min_sW(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uD(dst, lhs, rhs);
@@ -531,12 +531,12 @@
       break;
     // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
     // TODO: Fix min(x, NaN) cases for float and double.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FminW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FminD(dst, lhs, rhs);
@@ -557,7 +557,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uB(dst, lhs, rhs);
@@ -565,8 +565,8 @@
         __ Max_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uH(dst, lhs, rhs);
@@ -574,7 +574,7 @@
         __ Max_sH(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uW(dst, lhs, rhs);
@@ -582,7 +582,7 @@
         __ Max_sW(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uD(dst, lhs, rhs);
@@ -592,12 +592,12 @@
       break;
     // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
     // TODO: Fix max(x, NaN) cases for float and double.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FmaxW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FmaxD(dst, lhs, rhs);
@@ -618,14 +618,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ AndV(dst, lhs, rhs);  // lanes do not matter
@@ -654,14 +654,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ OrV(dst, lhs, rhs);  // lanes do not matter
@@ -682,14 +682,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ XorV(dst, lhs, rhs);  // lanes do not matter
@@ -704,11 +704,11 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -729,20 +729,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SlliB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SlliH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SlliW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SlliD(dst, lhs, value);
       break;
@@ -762,20 +762,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SraiB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SraiH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SraiW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SraiD(dst, lhs, value);
       break;
@@ -795,20 +795,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SrliB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SrliH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SrliW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SrliD(dst, lhs, value);
       break;
@@ -826,21 +826,18 @@
   LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
-void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputAccumulatorIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulRightIndex, Location::RequiresFpuRegister());
-      DCHECK_EQ(HVecMultiplyAccumulate::kInputAccumulatorIndex, 0);
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     default:
@@ -849,43 +846,44 @@
   }
 }
 
-void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = instr->GetLocations();
-  VectorRegister acc =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputAccumulatorIndex));
-  VectorRegister left =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulLeftIndex));
-  VectorRegister right =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulRightIndex));
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-      DCHECK_EQ(16u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+  VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+  VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvB(acc, left, right);
       } else {
         __ MsubvB(acc, left, right);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      DCHECK_EQ(8u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvH(acc, left, right);
       } else {
         __ MsubvH(acc, left, right);
       }
       break;
-    case Primitive::kPrimInt:
-      DCHECK_EQ(4u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvW(acc, left, right);
       } else {
         __ MsubvW(acc, left, right);
       }
       break;
-    case Primitive::kPrimLong:
-      DCHECK_EQ(2u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kInt64:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvD(acc, left, right);
       } else {
         __ MsubvD(acc, left, right);
@@ -897,20 +895,29 @@
   }
 }
 
+void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  // TODO: implement this, location helper already filled out (shared with MulAcc).
+}
+
 // Helper to set up locations for vector memory operations.
 static void CreateVecMemLocations(ArenaAllocator* arena,
                                   HVecMemoryOperation* instruction,
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -963,18 +970,18 @@
 
 void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VectorRegister reg = VectorRegisterFrom(locations->Out());
   Register base;
   int32_t offset = VecAddress(locations, size, &base);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ LdB(reg, base, offset);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
       // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
       // loads and stores.
@@ -983,13 +990,13 @@
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ LdH(reg, base, offset);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ LdW(reg, base, offset);
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ LdD(reg, base, offset);
       break;
@@ -1005,28 +1012,28 @@
 
 void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
   Register base;
   int32_t offset = VecAddress(locations, size, &base);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ StB(reg, base, offset);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ StH(reg, base, offset);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ StW(reg, base, offset);
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ StD(reg, base, offset);
       break;
diff --git a/compiler/optimizing/code_generator_vector_mips64.cc b/compiler/optimizing/code_generator_vector_mips64.cc
index 9d3a777..f60f708 100644
--- a/compiler/optimizing/code_generator_vector_mips64.cc
+++ b/compiler/optimizing/code_generator_vector_mips64.cc
@@ -31,17 +31,17 @@
 void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
@@ -55,31 +55,31 @@
   LocationSummary* locations = instruction->GetLocations();
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>());
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>());
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>());
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ ReplicateFPToVectorRegister(dst,
                                      locations->InAt(0).AsFpuRegister<FpuRegister>(),
                                      /* is_double */ false);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ ReplicateFPToVectorRegister(dst,
                                      locations->InAt(0).AsFpuRegister<FpuRegister>(),
@@ -103,19 +103,19 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
+    case DataType::Type::kBool:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         instruction->IsVecNot() ? Location::kOutputOverlap
                                                 : Location::kNoOutputOverlap);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(),
                         (instruction->IsVecNeg() || instruction->IsVecAbs())
@@ -144,9 +144,9 @@
   LocationSummary* locations = instruction->GetLocations();
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
-  Primitive::Type from = instruction->GetInputType();
-  Primitive::Type to = instruction->GetResultType();
-  if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+  DataType::Type from = instruction->GetInputType();
+  DataType::Type to = instruction->GetResultType();
+  if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
     DCHECK_EQ(4u, instruction->GetVectorLength());
     __ Ffint_sW(dst, src);
   } else {
@@ -164,33 +164,33 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, ZERO);
       __ SubvB(dst, dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, ZERO);
       __ SubvH(dst, dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ SubvW(dst, dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillD(dst, ZERO);
       __ SubvD(dst, dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);
       __ FsubW(dst, dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillD(dst, ZERO);
       __ FsubD(dst, dst, src);
@@ -210,34 +210,34 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ FillB(dst, ZERO);       // all zeroes
       __ Add_aB(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ FillH(dst, ZERO);       // all zeroes
       __ Add_aH(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FillW(dst, ZERO);       // all zeroes
       __ Add_aW(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FillD(dst, ZERO);       // all zeroes
       __ Add_aD(dst, dst, src);  // dst = abs(0) + abs(src)
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ LdiW(dst, -1);          // all ones
       __ SrliW(dst, dst, 1);
       __ AndV(dst, dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ LdiD(dst, -1);          // all ones
       __ SrliD(dst, dst, 1);
@@ -258,18 +258,18 @@
   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:  // special case boolean-not
+    case DataType::Type::kBool:  // special case boolean-not
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ LdiB(dst, 1);
       __ XorV(dst, dst, src);
       break;
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ NorV(dst, src, src);  // lanes do not matter
@@ -284,14 +284,14 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -312,28 +312,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ AddvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ AddvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ AddvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ AddvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FaddW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FaddD(dst, lhs, rhs);
       break;
@@ -353,7 +353,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -365,8 +365,8 @@
             : __ Ave_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         instruction->IsRounded()
@@ -394,28 +394,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SubvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SubvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SubvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SubvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FsubW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FsubD(dst, lhs, rhs);
       break;
@@ -435,28 +435,28 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ MulvB(dst, lhs, rhs);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ MulvH(dst, lhs, rhs);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ MulvW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ MulvD(dst, lhs, rhs);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FmulW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FmulD(dst, lhs, rhs);
       break;
@@ -476,11 +476,11 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ FdivW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ FdivD(dst, lhs, rhs);
       break;
@@ -500,7 +500,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uB(dst, lhs, rhs);
@@ -508,8 +508,8 @@
         __ Min_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uH(dst, lhs, rhs);
@@ -517,7 +517,7 @@
         __ Min_sH(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uW(dst, lhs, rhs);
@@ -525,7 +525,7 @@
         __ Min_sW(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Min_uD(dst, lhs, rhs);
@@ -535,12 +535,12 @@
       break;
     // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
     // TODO: Fix min(x, NaN) cases for float and double.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FminW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FminD(dst, lhs, rhs);
@@ -561,7 +561,7 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uB(dst, lhs, rhs);
@@ -569,8 +569,8 @@
         __ Max_sB(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uH(dst, lhs, rhs);
@@ -578,7 +578,7 @@
         __ Max_sH(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uW(dst, lhs, rhs);
@@ -586,7 +586,7 @@
         __ Max_sW(dst, lhs, rhs);
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ Max_uD(dst, lhs, rhs);
@@ -596,12 +596,12 @@
       break;
     // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
     // TODO: Fix max(x, NaN) cases for float and double.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FmaxW(dst, lhs, rhs);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ FmaxD(dst, lhs, rhs);
@@ -622,14 +622,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ AndV(dst, lhs, rhs);  // lanes do not matter
@@ -658,14 +658,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ OrV(dst, lhs, rhs);  // lanes do not matter
@@ -686,14 +686,14 @@
   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ XorV(dst, lhs, rhs);  // lanes do not matter
@@ -708,11 +708,11 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -733,20 +733,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SlliB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SlliH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SlliW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SlliD(dst, lhs, value);
       break;
@@ -766,20 +766,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SraiB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SraiH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SraiW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SraiD(dst, lhs, value);
       break;
@@ -799,20 +799,20 @@
   VectorRegister dst = VectorRegisterFrom(locations->Out());
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ SrliB(dst, lhs, value);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ SrliH(dst, lhs, value);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ SrliW(dst, lhs, value);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ SrliD(dst, lhs, value);
       break;
@@ -830,21 +830,18 @@
   LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
-void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputAccumulatorIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresFpuRegister());
-      locations->SetInAt(
-          HVecMultiplyAccumulate::kInputMulRightIndex, Location::RequiresFpuRegister());
-      DCHECK_EQ(HVecMultiplyAccumulate::kInputAccumulatorIndex, 0);
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     default:
@@ -853,43 +850,44 @@
   }
 }
 
-void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LocationSummary* locations = instr->GetLocations();
-  VectorRegister acc =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputAccumulatorIndex));
-  VectorRegister left =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulLeftIndex));
-  VectorRegister right =
-      VectorRegisterFrom(locations->InAt(HVecMultiplyAccumulate::kInputMulRightIndex));
-  switch (instr->GetPackedType()) {
-    case Primitive::kPrimByte:
-      DCHECK_EQ(16u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+  VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+  VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvB(acc, left, right);
       } else {
         __ MsubvB(acc, left, right);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      DCHECK_EQ(8u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvH(acc, left, right);
       } else {
         __ MsubvH(acc, left, right);
       }
       break;
-    case Primitive::kPrimInt:
-      DCHECK_EQ(4u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvW(acc, left, right);
       } else {
         __ MsubvW(acc, left, right);
       }
       break;
-    case Primitive::kPrimLong:
-      DCHECK_EQ(2u, instr->GetVectorLength());
-      if (instr->GetOpKind() == HInstruction::kAdd) {
+    case DataType::Type::kInt64:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (instruction->GetOpKind() == HInstruction::kAdd) {
         __ MaddvD(acc, left, right);
       } else {
         __ MsubvD(acc, left, right);
@@ -901,20 +899,29 @@
   }
 }
 
+void LocationsBuilderMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  // TODO: implement this, location helper already filled out (shared with MulAcc).
+}
+
 // Helper to set up locations for vector memory operations.
 static void CreateVecMemLocations(ArenaAllocator* arena,
                                   HVecMemoryOperation* instruction,
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -967,18 +974,18 @@
 
 void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VectorRegister reg = VectorRegisterFrom(locations->Out());
   GpuRegister base;
   int32_t offset = VecAddress(locations, size, &base);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ LdB(reg, base, offset);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
       // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
       // loads and stores.
@@ -987,13 +994,13 @@
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ LdH(reg, base, offset);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ LdW(reg, base, offset);
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ LdD(reg, base, offset);
       break;
@@ -1009,28 +1016,28 @@
 
 void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
   GpuRegister base;
   int32_t offset = VecAddress(locations, size, &base);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ StB(reg, base, offset);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ StH(reg, base, offset);
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kInt32:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ StW(reg, base, offset);
       break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ StD(reg, base, offset);
       break;
diff --git a/compiler/optimizing/code_generator_vector_x86.cc b/compiler/optimizing/code_generator_vector_x86.cc
index 37190f8..6515dbe 100644
--- a/compiler/optimizing/code_generator_vector_x86.cc
+++ b/compiler/optimizing/code_generator_vector_x86.cc
@@ -30,28 +30,27 @@
   HInstruction* input = instruction->InputAt(0);
   bool is_zero = IsZeroBitPattern(input);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // Long needs extra temporary to load from the register pair.
       if (!is_zero) {
         locations->AddTemp(Location::RequiresFpuRegister());
       }
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresFpuRegister());
       locations->SetOut(is_zero ? Location::RequiresFpuRegister()
                                 : Location::SameAsFirstInput());
-
       break;
     default:
       LOG(FATAL) << "Unsupported SIMD type";
@@ -70,27 +69,27 @@
   }
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<Register>());
       __ punpcklbw(dst, dst);
       __ punpcklwd(dst, dst);
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<Register>());
       __ punpcklwd(dst, dst);
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<Register>());
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegisterPairLow<Register>());
@@ -99,12 +98,12 @@
       __ punpcklqdq(dst, dst);
       break;
     }
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK(locations->InAt(0).Equals(locations->Out()));
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ shufps(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK(locations->InAt(0).Equals(locations->Out()));
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ shufpd(dst, dst, Immediate(0));
@@ -118,20 +117,20 @@
 void LocationsBuilderX86::VisitVecExtractScalar(HVecExtractScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // Long needs extra temporary to store into the register pair.
       locations->AddTemp(Location::RequiresFpuRegister());
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
@@ -145,18 +144,18 @@
   LocationSummary* locations = instruction->GetLocations();
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:  // TODO: up to here, and?
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:  // TODO: up to here, and?
       LOG(FATAL) << "Unsupported SIMD type";
       UNREACHABLE();
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_LE(4u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ movd(locations->Out().AsRegister<Register>(), src);
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movd(locations->Out().AsRegisterPairLow<Register>(), src);
@@ -164,8 +163,8 @@
       __ movd(locations->Out().AsRegisterPairHigh<Register>(), tmp);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 4u);
       DCHECK(locations->InAt(0).Equals(locations->Out()));  // no code required
@@ -180,14 +179,14 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
@@ -200,7 +199,7 @@
 void LocationsBuilderX86::VisitVecReduce(HVecReduce* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Long reduction or min/max require a temporary.
-  if (instruction->GetPackedType() == Primitive::kPrimLong ||
+  if (instruction->GetPackedType() == DataType::Type::kInt64 ||
       instruction->GetKind() == HVecReduce::kMin ||
       instruction->GetKind() == HVecReduce::kMax) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
@@ -212,7 +211,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       switch (instruction->GetKind()) {
         case HVecReduce::kSum:
@@ -242,7 +241,7 @@
         }
       }
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       DCHECK_EQ(2u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       switch (instruction->GetKind()) {
@@ -272,9 +271,9 @@
   LocationSummary* locations = instruction->GetLocations();
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
-  Primitive::Type from = instruction->GetInputType();
-  Primitive::Type to = instruction->GetResultType();
-  if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+  DataType::Type from = instruction->GetInputType();
+  DataType::Type to = instruction->GetResultType();
+  if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
     DCHECK_EQ(4u, instruction->GetVectorLength());
     __ cvtdq2ps(dst, src);
   } else {
@@ -291,33 +290,33 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ xorps(dst, dst);
       __ subps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ xorpd(dst, dst);
       __ subpd(dst, src);
@@ -331,7 +330,7 @@
 void LocationsBuilderX86::VisitVecAbs(HVecAbs* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Integral-abs requires a temporary for the comparison.
-  if (instruction->GetPackedType() == Primitive::kPrimInt) {
+  if (instruction->GetPackedType() == DataType::Type::kInt32) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
   }
 }
@@ -341,7 +340,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK_EQ(4u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       __ movaps(dst, src);
@@ -351,13 +350,13 @@
       __ psubd(dst, tmp);
       break;
     }
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ psrld(dst, Immediate(1));
       __ andps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ psrlq(dst, Immediate(1));
@@ -372,7 +371,7 @@
 void LocationsBuilderX86::VisitVecNot(HVecNot* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Boolean-not requires a temporary to construct the 16 x one.
-  if (instruction->GetPackedType() == Primitive::kPrimBoolean) {
+  if (instruction->GetPackedType() == DataType::Type::kBool) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
   }
 }
@@ -382,7 +381,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean: {  // special case boolean-not
+    case DataType::Type::kBool: {  // special case boolean-not
       DCHECK_EQ(16u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       __ pxor(dst, dst);
@@ -391,22 +390,22 @@
       __ pxor(dst, src);
       break;
     }
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pcmpeqb(dst, dst);  // all ones
       __ pxor(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ xorps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ xorpd(dst, src);
@@ -421,14 +420,14 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
@@ -449,28 +448,28 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ paddb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ paddw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ paddd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ paddq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ addps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ addpd(dst, src);
       break;
@@ -494,12 +493,12 @@
   DCHECK(instruction->IsUnsigned());
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
      __ pavgb(dst, src);
      return;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pavgw(dst, src);
       return;
@@ -519,28 +518,28 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ psubb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psubw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psubd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psubq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ subps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ subpd(dst, src);
       break;
@@ -560,20 +559,20 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pmullw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pmulld(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ mulps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ mulpd(dst, src);
       break;
@@ -593,11 +592,11 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ divps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ divpd(dst, src);
       break;
@@ -617,7 +616,7 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminub(dst, src);
@@ -625,8 +624,8 @@
         __ pminsb(dst, src);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminuw(dst, src);
@@ -634,7 +633,7 @@
         __ pminsw(dst, src);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminud(dst, src);
@@ -643,12 +642,12 @@
       }
       break;
     // Next cases are sloppy wrt 0.0 vs -0.0.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ minps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ minpd(dst, src);
@@ -669,7 +668,7 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxub(dst, src);
@@ -677,8 +676,8 @@
         __ pmaxsb(dst, src);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxuw(dst, src);
@@ -686,7 +685,7 @@
         __ pmaxsw(dst, src);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxud(dst, src);
@@ -695,12 +694,12 @@
       }
       break;
     // Next cases are sloppy wrt 0.0 vs -0.0.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ maxps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ maxpd(dst, src);
@@ -721,21 +720,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pand(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ andps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ andpd(dst, src);
       break;
@@ -755,21 +754,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pandn(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ andnps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ andnpd(dst, src);
       break;
@@ -789,21 +788,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ por(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ orps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ orpd(dst, src);
       break;
@@ -823,21 +822,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pxor(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ xorps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ xorpd(dst, src);
       break;
@@ -851,10 +850,10 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::SameAsFirstInput());
@@ -875,16 +874,16 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psllw(dst, Immediate(static_cast<uint8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pslld(dst, Immediate(static_cast<uint8_t>(value)));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psllq(dst, Immediate(static_cast<uint8_t>(value)));
       break;
@@ -904,12 +903,12 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psraw(dst, Immediate(static_cast<uint8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psrad(dst, Immediate(static_cast<uint8_t>(value)));
       break;
@@ -929,16 +928,16 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psrlw(dst, Immediate(static_cast<uint8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psrld(dst, Immediate(static_cast<uint8_t>(value)));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psrlq(dst, Immediate(static_cast<uint8_t>(value)));
       break;
@@ -957,23 +956,23 @@
   bool is_zero = IsZeroBitPattern(input);
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // Long needs extra temporary to load from register pairs.
       if (!is_zero) {
         locations->AddTemp(Location::RequiresFpuRegister());
       }
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister());
@@ -1000,17 +999,17 @@
 
   // Set required elements.
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:  // TODO: up to here, and?
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:  // TODO: up to here, and?
       LOG(FATAL) << "Unsupported SIMD type";
       UNREACHABLE();
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<Register>());
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ xorps(tmp, tmp);
@@ -1019,11 +1018,11 @@
       __ punpckldq(dst, tmp);
       break;
     }
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movss(dst, locations->InAt(1).AsFpuRegister<XmmRegister>());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movsd(dst, locations->InAt(1).AsFpuRegister<XmmRegister>());
       break;
@@ -1033,12 +1032,42 @@
   }
 }
 
-void LocationsBuilderX86::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LOG(FATAL) << "No SIMD for " << instr->GetId();
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
-void InstructionCodeGeneratorX86::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
-  LOG(FATAL) << "No SIMD for " << instr->GetId();
+void LocationsBuilderX86::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  // TODO: pmaddwd?
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+}
+
+void LocationsBuilderX86::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  // TODO: psadbw for unsigned?
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
 // Helper to set up locations for vector memory operations.
@@ -1047,14 +1076,14 @@
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -1097,12 +1126,12 @@
 
 void InstructionCodeGeneratorX86::VisitVecLoad(HVecLoad* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   Address address = VecAddress(locations, size, instruction->IsStringCharAt());
   XmmRegister reg = locations->Out().AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
       if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
@@ -1126,20 +1155,20 @@
         return;
       }
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       is_aligned16 ? __ movdqa(reg, address) : __ movdqu(reg, address);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       is_aligned16 ? __ movaps(reg, address) : __ movups(reg, address);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       is_aligned16 ? __ movapd(reg, address) : __ movupd(reg, address);
       break;
@@ -1155,26 +1184,26 @@
 
 void InstructionCodeGeneratorX86::VisitVecStore(HVecStore* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   Address address = VecAddress(locations, size, /*is_string_char_at*/ false);
   XmmRegister reg = locations->InAt(2).AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       is_aligned16 ? __ movdqa(address, reg) : __ movdqu(address, reg);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       is_aligned16 ? __ movaps(address, reg) : __ movups(address, reg);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       is_aligned16 ? __ movapd(address, reg) : __ movupd(address, reg);
       break;
diff --git a/compiler/optimizing/code_generator_vector_x86_64.cc b/compiler/optimizing/code_generator_vector_x86_64.cc
index edd0209..4241042 100644
--- a/compiler/optimizing/code_generator_vector_x86_64.cc
+++ b/compiler/optimizing/code_generator_vector_x86_64.cc
@@ -30,18 +30,18 @@
   HInstruction* input = instruction->InputAt(0);
   bool is_zero = IsZeroBitPattern(input);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresFpuRegister());
       locations->SetOut(is_zero ? Location::RequiresFpuRegister()
@@ -64,37 +64,37 @@
   }
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>(), /*64-bit*/ false);
       __ punpcklbw(dst, dst);
       __ punpcklwd(dst, dst);
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>(), /*64-bit*/ false);
       __ punpcklwd(dst, dst);
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>(), /*64-bit*/ false);
       __ pshufd(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>(), /*64-bit*/ true);
       __ punpcklqdq(dst, dst);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(locations->InAt(0).Equals(locations->Out()));
       __ shufps(dst, dst, Immediate(0));
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(locations->InAt(0).Equals(locations->Out()));
       __ shufpd(dst, dst, Immediate(0));
@@ -108,17 +108,17 @@
 void LocationsBuilderX86_64::VisitVecExtractScalar(HVecExtractScalar* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
@@ -132,22 +132,22 @@
   LocationSummary* locations = instruction->GetLocations();
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:  // TODO: up to here, and?
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:  // TODO: up to here, and?
       LOG(FATAL) << "Unsupported SIMD type";
       UNREACHABLE();
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movd(locations->Out().AsRegister<CpuRegister>(), src, /*64-bit*/ false);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movd(locations->Out().AsRegister<CpuRegister>(), src, /*64-bit*/ true);
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 4u);
       DCHECK(locations->InAt(0).Equals(locations->Out()));  // no code required
@@ -162,14 +162,14 @@
 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
@@ -182,7 +182,7 @@
 void LocationsBuilderX86_64::VisitVecReduce(HVecReduce* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Long reduction or min/max require a temporary.
-  if (instruction->GetPackedType() == Primitive::kPrimLong ||
+  if (instruction->GetPackedType() == DataType::Type::kInt64 ||
       instruction->GetKind() == HVecReduce::kMin ||
       instruction->GetKind() == HVecReduce::kMax) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
@@ -194,7 +194,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       switch (instruction->GetKind()) {
         case HVecReduce::kSum:
@@ -224,7 +224,7 @@
         }
       }
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       DCHECK_EQ(2u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       switch (instruction->GetKind()) {
@@ -254,9 +254,9 @@
   LocationSummary* locations = instruction->GetLocations();
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
-  Primitive::Type from = instruction->GetInputType();
-  Primitive::Type to = instruction->GetResultType();
-  if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+  DataType::Type from = instruction->GetInputType();
+  DataType::Type to = instruction->GetResultType();
+  if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
     DCHECK_EQ(4u, instruction->GetVectorLength());
     __ cvtdq2ps(dst, src);
   } else {
@@ -273,33 +273,33 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pxor(dst, dst);
       __ psubq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ xorps(dst, dst);
       __ subps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ xorpd(dst, dst);
       __ subpd(dst, src);
@@ -313,7 +313,7 @@
 void LocationsBuilderX86_64::VisitVecAbs(HVecAbs* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Integral-abs requires a temporary for the comparison.
-  if (instruction->GetPackedType() == Primitive::kPrimInt) {
+  if (instruction->GetPackedType() == DataType::Type::kInt32) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
   }
 }
@@ -323,7 +323,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK_EQ(4u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       __ movaps(dst, src);
@@ -333,13 +333,13 @@
       __ psubd(dst, tmp);
       break;
     }
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ psrld(dst, Immediate(1));
       __ andps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ psrlq(dst, Immediate(1));
@@ -354,7 +354,7 @@
 void LocationsBuilderX86_64::VisitVecNot(HVecNot* instruction) {
   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
   // Boolean-not requires a temporary to construct the 16 x one.
-  if (instruction->GetPackedType() == Primitive::kPrimBoolean) {
+  if (instruction->GetPackedType() == DataType::Type::kBool) {
     instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
   }
 }
@@ -364,7 +364,7 @@
   XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean: {  // special case boolean-not
+    case DataType::Type::kBool: {  // special case boolean-not
       DCHECK_EQ(16u, instruction->GetVectorLength());
       XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       __ pxor(dst, dst);
@@ -373,22 +373,22 @@
       __ pxor(dst, src);
       break;
     }
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pcmpeqb(dst, dst);  // all ones
       __ pxor(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ xorps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ pcmpeqb(dst, dst);  // all ones
       __ xorpd(dst, src);
@@ -403,14 +403,14 @@
 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
@@ -431,28 +431,28 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ paddb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ paddw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ paddd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ paddq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ addps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ addpd(dst, src);
       break;
@@ -476,12 +476,12 @@
   DCHECK(instruction->IsUnsigned());
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
      __ pavgb(dst, src);
      return;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pavgw(dst, src);
       return;
@@ -501,28 +501,28 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       __ psubb(dst, src);
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psubw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psubd(dst, src);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psubq(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ subps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ subpd(dst, src);
       break;
@@ -542,20 +542,20 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ pmullw(dst, src);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pmulld(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ mulps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ mulpd(dst, src);
       break;
@@ -575,11 +575,11 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ divps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ divpd(dst, src);
       break;
@@ -599,7 +599,7 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminub(dst, src);
@@ -607,8 +607,8 @@
         __ pminsb(dst, src);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminuw(dst, src);
@@ -616,7 +616,7 @@
         __ pminsw(dst, src);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pminud(dst, src);
@@ -625,12 +625,12 @@
       }
       break;
     // Next cases are sloppy wrt 0.0 vs -0.0.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ minps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ minpd(dst, src);
@@ -651,7 +651,7 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       DCHECK_EQ(16u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxub(dst, src);
@@ -659,8 +659,8 @@
         __ pmaxsb(dst, src);
       }
       break;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxuw(dst, src);
@@ -668,7 +668,7 @@
         __ pmaxsw(dst, src);
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       if (instruction->IsUnsigned()) {
         __ pmaxud(dst, src);
@@ -677,12 +677,12 @@
       }
       break;
     // Next cases are sloppy wrt 0.0 vs -0.0.
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ maxps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       DCHECK(!instruction->IsUnsigned());
       __ maxpd(dst, src);
@@ -703,21 +703,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pand(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ andps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ andpd(dst, src);
       break;
@@ -737,21 +737,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pandn(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ andnps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ andnpd(dst, src);
       break;
@@ -771,21 +771,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ por(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ orps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ orpd(dst, src);
       break;
@@ -805,21 +805,21 @@
   XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       __ pxor(dst, src);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ xorps(dst, src);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ xorpd(dst, src);
       break;
@@ -833,10 +833,10 @@
 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
       locations->SetOut(Location::SameAsFirstInput());
@@ -857,16 +857,16 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psllw(dst, Immediate(static_cast<int8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ pslld(dst, Immediate(static_cast<int8_t>(value)));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psllq(dst, Immediate(static_cast<int8_t>(value)));
       break;
@@ -886,12 +886,12 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psraw(dst, Immediate(static_cast<int8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psrad(dst, Immediate(static_cast<int8_t>(value)));
       break;
@@ -911,16 +911,16 @@
   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
   XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       __ psrlw(dst, Immediate(static_cast<int8_t>(value)));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ psrld(dst, Immediate(static_cast<int8_t>(value)));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ psrlq(dst, Immediate(static_cast<int8_t>(value)));
       break;
@@ -939,18 +939,18 @@
   bool is_zero = IsZeroBitPattern(input);
 
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresRegister());
       locations->SetOut(Location::RequiresFpuRegister());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
                                     : Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresFpuRegister());
@@ -977,25 +977,25 @@
 
   // Set required elements.
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:  // TODO: up to here, and?
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:  // TODO: up to here, and?
       LOG(FATAL) << "Unsupported SIMD type";
       UNREACHABLE();
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>());
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movd(dst, locations->InAt(0).AsRegister<CpuRegister>());  // is 64-bit
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       __ movss(dst, locations->InAt(0).AsFpuRegister<XmmRegister>());
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       __ movsd(dst, locations->InAt(0).AsFpuRegister<XmmRegister>());
       break;
@@ -1005,11 +1005,41 @@
   }
 }
 
+// Helper to set up locations for vector accumulations.
+static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(2, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
+}
+
 void LocationsBuilderX86_64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
 }
 
 void InstructionCodeGeneratorX86_64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
+  // TODO: pmaddwd?
+  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+}
+
+void LocationsBuilderX86_64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  CreateVecAccumLocations(GetGraph()->GetArena(), instruction);
+}
+
+void InstructionCodeGeneratorX86_64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
+  // TODO: psadbw for unsigned?
   LOG(FATAL) << "No SIMD for " << instruction->GetId();
 }
 
@@ -1019,14 +1049,14 @@
                                   bool is_load) {
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
       if (is_load) {
@@ -1069,12 +1099,12 @@
 
 void InstructionCodeGeneratorX86_64::VisitVecLoad(HVecLoad* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   Address address = VecAddress(locations, size, instruction->IsStringCharAt());
   XmmRegister reg = locations->Out().AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
       if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
@@ -1098,20 +1128,20 @@
         return;
       }
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       is_aligned16 ? __ movdqa(reg, address) : __ movdqu(reg, address);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       is_aligned16 ? __ movaps(reg, address) : __ movups(reg, address);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       is_aligned16 ? __ movapd(reg, address) : __ movupd(reg, address);
       break;
@@ -1127,26 +1157,26 @@
 
 void InstructionCodeGeneratorX86_64::VisitVecStore(HVecStore* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  size_t size = DataType::Size(instruction->GetPackedType());
   Address address = VecAddress(locations, size, /*is_string_char_at*/ false);
   XmmRegister reg = locations->InAt(2).AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
       DCHECK_LE(instruction->GetVectorLength(), 16u);
       is_aligned16 ? __ movdqa(address, reg) : __ movdqu(address, reg);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       DCHECK_EQ(4u, instruction->GetVectorLength());
       is_aligned16 ? __ movaps(address, reg) : __ movups(address, reg);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       DCHECK_EQ(2u, instruction->GetVectorLength());
       is_aligned16 ? __ movapd(address, reg) : __ movupd(address, reg);
       break;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 0b9130f..70e270e 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -26,6 +26,7 @@
 #include "heap_poisoning.h"
 #include "intrinsics.h"
 #include "intrinsics_x86.h"
+#include "linker/linker_patch.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
@@ -160,10 +161,10 @@
     x86_codegen->EmitParallelMoves(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         length_loc,
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt);
+        DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -341,10 +342,10 @@
     InvokeRuntimeCallingConvention calling_convention;
     x86_codegen->EmitParallelMoves(locations->InAt(0),
                                    Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                                   Primitive::kPrimNot,
+                                   DataType::Type::kReference,
                                    locations->InAt(1),
                                    Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                                   Primitive::kPrimNot);
+                                   DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       x86_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
                                  instruction_,
@@ -417,17 +418,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -813,16 +814,16 @@
     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
     parallel_move.AddMove(ref_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     parallel_move.AddMove(obj_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -1128,24 +1129,24 @@
   __ Bind(GetLabelOf(block));
 }
 
-Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
+Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
       return Location::RegisterLocation(EAX);
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       return Location::RegisterPairLocation(EAX, EDX);
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       return Location::NoLocation();
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat64:
+    case DataType::Type::kFloat32:
       return Location::FpuRegisterLocation(XMM0);
   }
 
@@ -1156,14 +1157,14 @@
   return Location::RegisterLocation(kMethodRegisterArgument);
 }
 
-Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       uint32_t index = gp_index_++;
       stack_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
@@ -1173,7 +1174,7 @@
       }
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t index = gp_index_;
       gp_index_ += 2;
       stack_index_ += 2;
@@ -1186,7 +1187,7 @@
       }
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t index = float_index_++;
       stack_index_++;
       if (index < calling_convention.GetNumberOfFpuRegisters()) {
@@ -1196,7 +1197,7 @@
       }
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t index = float_index_++;
       stack_index_ += 2;
       if (index < calling_convention.GetNumberOfFpuRegisters()) {
@@ -1206,7 +1207,7 @@
       }
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
       break;
   }
@@ -1262,10 +1263,10 @@
       EmitParallelMoves(
           Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
           Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
-          Primitive::kPrimInt,
+          DataType::Type::kInt32,
           Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
           Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
-          Primitive::kPrimInt);
+          DataType::Type::kInt32);
     } else if (source.IsFpuRegister()) {
       XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
       __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
@@ -1284,7 +1285,7 @@
     } else if (source.IsDoubleStackSlot()) {
       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
     } else if (source.IsRegisterPair()) {
-      size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt);
+      size_t elem_size = DataType::Size(DataType::Type::kInt32);
       // Create stack space for 2 elements.
       __ subl(ESP, Immediate(2 * elem_size));
       __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>());
@@ -1316,10 +1317,10 @@
       EmitParallelMoves(
           Location::StackSlot(source.GetStackIndex()),
           Location::StackSlot(destination.GetStackIndex()),
-          Primitive::kPrimInt,
+          DataType::Type::kInt32,
           Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
           Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
-          Primitive::kPrimInt);
+          DataType::Type::kInt32);
     }
   }
 }
@@ -1329,11 +1330,11 @@
   __ movl(location.AsRegister<Register>(), Immediate(value));
 }
 
-void CodeGeneratorX86::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
+void CodeGeneratorX86::MoveLocation(Location dst, Location src, DataType::Type dst_type) {
   HParallelMove move(GetGraph()->GetArena());
-  if (dst_type == Primitive::kPrimLong && !src.IsConstant() && !src.IsFpuRegister()) {
-    move.AddMove(src.ToLow(), dst.ToLow(), Primitive::kPrimInt, nullptr);
-    move.AddMove(src.ToHigh(), dst.ToHigh(), Primitive::kPrimInt, nullptr);
+  if (dst_type == DataType::Type::kInt64 && !src.IsConstant() && !src.IsFpuRegister()) {
+    move.AddMove(src.ToLow(), dst.ToLow(), DataType::Type::kInt32, nullptr);
+    move.AddMove(src.ToHigh(), dst.ToHigh(), DataType::Type::kInt32, nullptr);
   } else {
     move.AddMove(src, dst, dst_type, nullptr);
   }
@@ -1556,16 +1557,16 @@
   Location left = locations->InAt(0);
   Location right = locations->InAt(1);
 
-  Primitive::Type type = condition->InputAt(0)->GetType();
+  DataType::Type type = condition->InputAt(0)->GetType();
   switch (type) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       GenerateLongComparesAndJumps(condition, true_target, false_target);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       GenerateFPCompare(left, right, condition, false);
       GenerateFPJumps(condition, true_target, false_target);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       GenerateFPCompare(left, right, condition, true);
       GenerateFPJumps(condition, true_target, false_target);
       break;
@@ -1588,8 +1589,8 @@
   // conditions if they are materialized due to the complex branching.
   return cond->IsCondition() &&
          cond->GetNext() == branch &&
-         cond->InputAt(0)->GetType() != Primitive::kPrimLong &&
-         !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
+         cond->InputAt(0)->GetType() != DataType::Type::kInt64 &&
+         !DataType::IsFloatingPointType(cond->InputAt(0)->GetType());
 }
 
 template<class LabelType>
@@ -1653,8 +1654,8 @@
 
     // If this is a long or FP comparison that has been folded into
     // the HCondition, generate the comparison directly.
-    Primitive::Type type = condition->InputAt(0)->GetType();
-    if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+    DataType::Type type = condition->InputAt(0)->GetType();
+    if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
       GenerateCompareTestAndBranch(condition, true_target, false_target);
       return;
     }
@@ -1727,7 +1728,7 @@
 
 static bool SelectCanUseCMOV(HSelect* select) {
   // There are no conditional move instructions for XMMs.
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     return false;
   }
 
@@ -1735,9 +1736,9 @@
   // In 32 bit mode, a long condition doesn't generate a single CC either.
   HInstruction* condition = select->GetCondition();
   if (condition->IsCondition()) {
-    Primitive::Type compare_type = condition->InputAt(0)->GetType();
-    if (compare_type == Primitive::kPrimLong ||
-        Primitive::IsFloatingPointType(compare_type)) {
+    DataType::Type compare_type = condition->InputAt(0)->GetType();
+    if (compare_type == DataType::Type::kInt64 ||
+        DataType::IsFloatingPointType(compare_type)) {
       return false;
     }
   }
@@ -1748,7 +1749,7 @@
 
 void LocationsBuilderX86::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
     locations->SetInAt(1, Location::Any());
   } else {
@@ -1796,8 +1797,8 @@
         }
       } else {
         // We can't handle FP or long here.
-        DCHECK_NE(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
-        DCHECK(!Primitive::IsFloatingPointType(condition->InputAt(0)->GetType()));
+        DCHECK_NE(condition->InputAt(0)->GetType(), DataType::Type::kInt64);
+        DCHECK(!DataType::IsFloatingPointType(condition->InputAt(0)->GetType()));
         LocationSummary* cond_locations = condition->GetLocations();
         codegen_->GenerateIntCompare(cond_locations->InAt(0), cond_locations->InAt(1));
         cond = X86Condition(condition->GetCondition());
@@ -1811,7 +1812,7 @@
     // If the condition is true, overwrite the output, which already contains false.
     Location false_loc = locations->InAt(0);
     Location true_loc = locations->InAt(1);
-    if (select->GetType() == Primitive::kPrimLong) {
+    if (select->GetType() == DataType::Type::kInt64) {
       // 64 bit conditional move.
       Register false_high = false_loc.AsRegisterPairHigh<Register>();
       Register false_low = false_loc.AsRegisterPairLow<Register>();
@@ -1857,7 +1858,7 @@
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   // Handle the long/FP comparisons made in instruction simplification.
   switch (cond->InputAt(0)->GetType()) {
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       if (!cond->IsEmittedAtUseSite()) {
@@ -1865,8 +1866,8 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (cond->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(cond->InputAt(1)->IsEmittedAtUseSite());
@@ -1912,14 +1913,14 @@
       __ setb(X86Condition(cond->GetCondition()), reg);
       return;
     }
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       GenerateLongComparesAndJumps(cond, &true_label, &false_label);
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       GenerateFPCompare(lhs, rhs, cond, false);
       GenerateFPJumps(cond, &true_label, &false_label);
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       GenerateFPCompare(lhs, rhs, cond, true);
       GenerateFPJumps(cond, &true_label, &false_label);
       break;
@@ -2098,22 +2099,22 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
   switch (ret->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
       locations->SetInAt(0, Location::RegisterLocation(EAX));
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(
           0, Location::RegisterPairLocation(EAX, EDX));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(
           0, Location::FpuRegisterLocation(XMM0));
       break;
@@ -2126,22 +2127,22 @@
 void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
   if (kIsDebugBuild) {
     switch (ret->InputAt(0)->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
+      case DataType::Type::kBool:
+      case DataType::Type::kInt8:
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+      case DataType::Type::kInt32:
+      case DataType::Type::kReference:
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
         break;
 
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
         break;
 
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
         break;
 
@@ -2297,20 +2298,20 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       locations->AddTemp(Location::RequiresRegister());
       locations->AddTemp(Location::RequiresFpuRegister());
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       locations->AddTemp(Location::RequiresFpuRegister());
@@ -2326,13 +2327,13 @@
   Location out = locations->Out();
   Location in = locations->InAt(0);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK(in.IsRegister());
       DCHECK(in.Equals(out));
       __ negl(out.AsRegister<Register>());
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK(in.IsRegisterPair());
       DCHECK(in.Equals(out));
       __ negl(out.AsRegisterPairLow<Register>());
@@ -2345,7 +2346,7 @@
       __ negl(out.AsRegisterPairHigh<Register>());
       break;
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       DCHECK(in.Equals(out));
       Register constant = locations->GetTemp(0).AsRegister<Register>();
       XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
@@ -2358,7 +2359,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       DCHECK(in.Equals(out));
       XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       // Implement double negation with an exclusive or with value
@@ -2377,7 +2378,7 @@
 void LocationsBuilderX86::VisitX86FPNeg(HX86FPNeg* neg) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
-  DCHECK(Primitive::IsFloatingPointType(neg->GetType()));
+  DCHECK(DataType::IsFloatingPointType(neg->GetType()));
   locations->SetInAt(0, Location::RequiresFpuRegister());
   locations->SetInAt(1, Location::RequiresRegister());
   locations->SetOut(Location::SameAsFirstInput());
@@ -2391,7 +2392,7 @@
 
   Register constant_area = locations->InAt(1).AsRegister<Register>();
   XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
-  if (neg->GetType() == Primitive::kPrimFloat) {
+  if (neg->GetType() == DataType::Type::kFloat32) {
     __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x80000000),
                                                  neg->GetBaseMethodAddress(),
                                                  constant_area));
@@ -2405,15 +2406,15 @@
 }
 
 void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
 
   // The float-to-long and double-to-long type conversions rely on a
   // call to the runtime.
   LocationSummary::CallKind call_kind =
-      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
-       && result_type == Primitive::kPrimLong)
+      ((input_type == DataType::Type::kFloat32 || input_type == DataType::Type::kFloat64)
+       && result_type == DataType::Type::kInt64)
       ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
   LocationSummary* locations =
@@ -2423,9 +2424,9 @@
   // our bit representation makes it safe.
 
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong: {
+        case DataType::Type::kInt64: {
           // Type conversion from long to byte is a result of code transformations.
           HInstruction* input = conversion->InputAt(0);
           Location input_location = input->IsConstant()
@@ -2437,11 +2438,11 @@
           locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
           break;
         }
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
           // Make the output overlap to please the register allocator. This greatly simplifies
@@ -2455,15 +2456,15 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2475,22 +2476,22 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
           locations->AddTemp(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
@@ -2503,21 +2504,21 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           locations->SetInAt(0, Location::RegisterLocation(EAX));
           locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
           break;
 
-        case Primitive::kPrimFloat:
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat32:
+        case DataType::Type::kFloat64: {
           // Processing a Dex `float-to-long' or 'double-to-long' instruction.
           InvokeRuntimeCallingConvention calling_convention;
           XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
@@ -2534,15 +2535,15 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to char is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `int-to-char' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2554,26 +2555,26 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-float' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-float' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::Any());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -2585,26 +2586,26 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-double' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-double' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::Any());
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -2626,13 +2627,13 @@
   LocationSummary* locations = conversion->GetLocations();
   Location out = locations->Out();
   Location in = locations->InAt(0);
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to byte is a result of code transformations.
           if (in.IsRegisterPair()) {
             __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
@@ -2642,11 +2643,11 @@
             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
           }
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           if (in.IsRegister()) {
             __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
@@ -2663,9 +2664,9 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
           if (in.IsRegisterPair()) {
             __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
@@ -2677,11 +2678,11 @@
             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
           }
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           if (in.IsRegister()) {
             __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
@@ -2700,9 +2701,9 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           if (in.IsRegisterPair()) {
             __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
@@ -2716,7 +2717,7 @@
           }
           break;
 
-        case Primitive::kPrimFloat: {
+        case DataType::Type::kFloat32: {
           // Processing a Dex `float-to-int' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           Register output = out.AsRegister<Register>();
@@ -2741,7 +2742,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat64: {
           // Processing a Dex `double-to-int' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           Register output = out.AsRegister<Register>();
@@ -2772,14 +2773,14 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
           DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
@@ -2787,13 +2788,13 @@
           __ cdq();
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-long' instruction.
           codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-long' instruction.
           codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
@@ -2805,9 +2806,9 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
           if (in.IsRegisterPair()) {
             __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
@@ -2819,11 +2820,11 @@
             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
           }
           break;
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `Process a Dex `int-to-char'' instruction.
           if (in.IsRegister()) {
             __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
@@ -2842,19 +2843,19 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-float' instruction.
           __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
           break;
 
-        case Primitive::kPrimLong: {
+        case DataType::Type::kInt64: {
           // Processing a Dex `long-to-float' instruction.
           size_t adjustment = 0;
 
@@ -2862,7 +2863,7 @@
           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
           // TODO: enhance register allocator to ask for stack temporaries.
           if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
-            adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
+            adjustment = DataType::Size(DataType::Type::kInt64);
             __ subl(ESP, Immediate(adjustment));
           }
 
@@ -2884,7 +2885,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
@@ -2895,19 +2896,19 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-double' instruction.
           __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
           break;
 
-        case Primitive::kPrimLong: {
+        case DataType::Type::kInt64: {
           // Processing a Dex `long-to-double' instruction.
           size_t adjustment = 0;
 
@@ -2915,7 +2916,7 @@
           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
           // TODO: enhance register allocator to ask for stack temporaries.
           if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
-            adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
+            adjustment = DataType::Size(DataType::Type::kInt64);
             __ subl(ESP, Immediate(adjustment));
           }
 
@@ -2937,7 +2938,7 @@
           break;
         }
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
@@ -2958,22 +2959,22 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(add->InputAt(1)->IsEmittedAtUseSite());
@@ -2999,7 +3000,7 @@
   Location out = locations->Out();
 
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
@@ -3023,7 +3024,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsRegisterPair()) {
         __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
         __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
@@ -3040,7 +3041,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3058,7 +3059,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3085,15 +3086,15 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(sub->InputAt(1)->IsEmittedAtUseSite());
@@ -3117,7 +3118,7 @@
   Location second = locations->InAt(1);
   DCHECK(first.Equals(locations->Out()));
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (second.IsRegister()) {
         __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
       } else if (second.IsConstant()) {
@@ -3129,7 +3130,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsRegisterPair()) {
         __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
         __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
@@ -3146,7 +3147,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3164,7 +3165,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3191,7 +3192,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       if (mul->InputAt(1)->IsIntConstant()) {
@@ -3201,7 +3202,7 @@
         locations->SetOut(Location::SameAsFirstInput());
       }
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
@@ -3210,8 +3211,8 @@
       locations->AddTemp(Location::RegisterLocation(EDX));
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(mul->InputAt(1)->IsEmittedAtUseSite());
@@ -3236,7 +3237,7 @@
   Location out = locations->Out();
 
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       // The constant may have ended up in a register, so test explicitly to avoid
       // problems where the output may not be the same as the first operand.
       if (mul->InputAt(1)->IsIntConstant()) {
@@ -3252,7 +3253,7 @@
       }
       break;
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register in1_hi = first.AsRegisterPairHigh<Register>();
       Register in1_lo = first.AsRegisterPairLow<Register>();
       Register eax = locations->GetTemp(0).AsRegister<Register>();
@@ -3334,7 +3335,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       DCHECK(first.Equals(locations->Out()));
       if (second.IsFpuRegister()) {
         __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
@@ -3353,7 +3354,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       DCHECK(first.Equals(locations->Out()));
       if (second.IsFpuRegister()) {
         __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
@@ -3419,9 +3420,9 @@
 }
 
 void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
-  Primitive::Type type = rem->GetResultType();
-  bool is_float = type == Primitive::kPrimFloat;
-  size_t elem_size = Primitive::ComponentSize(type);
+  DataType::Type type = rem->GetResultType();
+  bool is_float = type == DataType::Type::kFloat32;
+  size_t elem_size = DataType::Size(type);
   LocationSummary* locations = rem->GetLocations();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
@@ -3598,7 +3599,7 @@
   bool is_div = instruction->IsDiv();
 
   switch (instruction->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK_EQ(EAX, first.AsRegister<Register>());
       DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
 
@@ -3637,7 +3638,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConvention calling_convention;
       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
@@ -3662,13 +3663,13 @@
 }
 
 void LocationsBuilderX86::VisitDiv(HDiv* div) {
-  LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
+  LocationSummary::CallKind call_kind = (div->GetResultType() == DataType::Type::kInt64)
       ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
 
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RegisterLocation(EAX));
       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::SameAsFirstInput());
@@ -3682,7 +3683,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::RegisterPairLocation(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -3692,8 +3693,8 @@
       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(div->InputAt(1)->IsEmittedAtUseSite());
@@ -3717,13 +3718,13 @@
   Location second = locations->InAt(1);
 
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GenerateDivRemIntegral(div);
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3741,7 +3742,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
@@ -3765,15 +3766,15 @@
 }
 
 void LocationsBuilderX86::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
 
-  LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
+  LocationSummary::CallKind call_kind = (rem->GetResultType() == DataType::Type::kInt64)
       ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RegisterLocation(EAX));
       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RegisterLocation(EDX));
@@ -3785,7 +3786,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       InvokeRuntimeCallingConvention calling_convention;
       locations->SetInAt(0, Location::RegisterPairLocation(
           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
@@ -3795,8 +3796,8 @@
       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
       break;
     }
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat64:
+    case DataType::Type::kFloat32: {
       locations->SetInAt(0, Location::Any());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::RequiresFpuRegister());
@@ -3810,15 +3811,15 @@
 }
 
 void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GenerateDivRemIntegral(rem);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       GenerateRemFP(rem);
       break;
     }
@@ -3830,15 +3831,15 @@
 void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   switch (instruction->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::Any());
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
       if (!instruction->IsConstant()) {
         locations->AddTemp(Location::RequiresRegister());
@@ -3858,11 +3859,11 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32: {
       if (value.IsRegister()) {
         __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
         __ j(kEqual, slow_path->GetEntryLabel());
@@ -3877,7 +3878,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (value.IsRegisterPair()) {
         Register temp = locations->GetTemp(0).AsRegister<Register>();
         __ movl(temp, value.AsRegisterPairLow<Register>());
@@ -3903,8 +3904,8 @@
       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
 
   switch (op->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       // Can't have Location::Any() and output SameAsFirstInput()
       locations->SetInAt(0, Location::RequiresRegister());
       // The shift count needs to be in CL or a constant.
@@ -3926,7 +3927,7 @@
   DCHECK(first.Equals(locations->Out()));
 
   switch (op->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       DCHECK(first.IsRegister());
       Register first_reg = first.AsRegister<Register>();
       if (second.IsRegister()) {
@@ -3955,7 +3956,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsRegister()) {
         Register second_reg = second.AsRegister<Register>();
         DCHECK_EQ(ECX, second_reg);
@@ -3999,10 +4000,10 @@
     codegen_->EmitParallelMoves(
         loc.ToLow(),
         loc.ToHigh(),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
         loc.ToLow(),
-        Primitive::kPrimInt);
+        DataType::Type::kInt32);
   } else if (shift > 32) {
     // Low part becomes 0.  High part is low part << (shift-32).
     __ movl(high, low);
@@ -4066,10 +4067,10 @@
     codegen_->EmitParallelMoves(
         loc.ToHigh(),
         loc.ToLow(),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
         loc.ToHigh(),
-        Primitive::kPrimInt);
+        DataType::Type::kInt32);
   } else if (shift > 32) {
     // Low part is high >> (shift - 32). High part becomes 0.
     __ movl(low, high);
@@ -4098,11 +4099,11 @@
       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
 
   switch (ror->GetResultType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // Add the temporary needed.
       locations->AddTemp(Location::RequiresRegister());
       FALLTHROUGH_INTENDED;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetInAt(0, Location::RequiresRegister());
       // The shift count needs to be in CL (unless it is a constant).
       locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, ror->InputAt(1)));
@@ -4119,7 +4120,7 @@
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
 
-  if (ror->GetResultType() == Primitive::kPrimInt) {
+  if (ror->GetResultType() == DataType::Type::kInt32) {
     Register first_reg = first.AsRegister<Register>();
     if (second.IsRegister()) {
       Register second_reg = second.AsRegister<Register>();
@@ -4131,7 +4132,7 @@
     return;
   }
 
-  DCHECK_EQ(ror->GetResultType(), Primitive::kPrimLong);
+  DCHECK_EQ(ror->GetResultType(), DataType::Type::kInt64);
   Register first_reg_lo = first.AsRegisterPairLow<Register>();
   Register first_reg_hi = first.AsRegisterPairHigh<Register>();
   Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
@@ -4314,11 +4315,11 @@
   Location out = locations->Out();
   DCHECK(in.Equals(out));
   switch (not_->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ notl(out.AsRegister<Register>());
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ notl(out.AsRegisterPairLow<Register>());
       __ notl(out.AsRegisterPairHigh<Register>());
       break;
@@ -4347,19 +4348,19 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       if (compare->InputAt(1)->IsX86LoadFromConstantTable()) {
         DCHECK(compare->InputAt(1)->IsEmittedAtUseSite());
@@ -4386,15 +4387,15 @@
   Condition less_cond = kLess;
 
   switch (compare->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       codegen_->GenerateIntCompare(left, right);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register left_low = left.AsRegisterPairLow<Register>();
       Register left_high = left.AsRegisterPairHigh<Register>();
       int32_t val_low = 0;
@@ -4430,13 +4431,13 @@
       less_cond = kBelow;  // for CF (unsigned).
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       GenerateFPCompare(left, right, compare, false);
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
       less_cond = kBelow;  // for CF (floats).
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       GenerateFPCompare(left, right, compare, true);
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
       less_cond = kBelow;  // for CF (floats).
@@ -4675,10 +4676,10 @@
 // for method patch needs to point to the embedded constant which occupies the last 4 bytes.
 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches(
     const ArenaDeque<X86PcRelativePatchInfo>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const X86PcRelativePatchInfo& info : infos) {
     uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
     linker_patches->push_back(Factory(
@@ -4686,7 +4687,7 @@
   }
 }
 
-void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       boot_image_method_patches_.size() +
@@ -4697,24 +4698,25 @@
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(boot_image_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        boot_image_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        boot_image_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        string_patches_, linker_patches);
   } else {
     DCHECK(boot_image_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        boot_image_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   DCHECK_EQ(size, linker_patches->size());
 }
 
@@ -4742,7 +4744,7 @@
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    kEmitCompilerReadBarrier ?
@@ -4753,7 +4755,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
 
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister());
   } else {
     // The output overlaps in case of long: we don't want the low move
@@ -4763,12 +4765,12 @@
     // the read barrier.
     locations->SetOut(
         Location::RequiresRegister(),
-        (object_field_get_with_read_barrier || instruction->GetType() == Primitive::kPrimLong) ?
+        (object_field_get_with_read_barrier || instruction->GetType() == DataType::Type::kInt64) ?
             Location::kOutputOverlap :
             Location::kNoOutputOverlap);
   }
 
-  if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
+  if (field_info.IsVolatile() && (field_info.GetFieldType() == DataType::Type::kInt64)) {
     // Long values can be loaded atomically into an XMM using movsd.
     // So we use an XMM register as a temp to achieve atomicity (first
     // load the temp into the XMM and then copy the XMM into the
@@ -4786,35 +4788,35 @@
   Register base = base_loc.AsRegister<Register>();
   Location out = locations->Out();
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
   switch (field_type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       __ movzxb(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       __ movsxb(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       __ movsxw(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       __ movzxw(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ movl(out.AsRegister<Register>(), Address(base, offset));
       break;
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       // /* HeapReference<Object> */ out = *(base + offset)
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         // Note that a potential implicit null check is handled in this
@@ -4838,7 +4840,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (is_volatile) {
         XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
         __ movsd(temp, Address(base, offset));
@@ -4855,22 +4857,22 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
 
-  if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimLong) {
+  if (field_type == DataType::Type::kReference || field_type == DataType::Type::kInt64) {
     // Potential implicit null checks, in the case of reference or
     // long fields, are handled in the previous switch statement.
   } else {
@@ -4878,7 +4880,7 @@
   }
 
   if (is_volatile) {
-    if (field_type == Primitive::kPrimNot) {
+    if (field_type == DataType::Type::kReference) {
       // Memory barriers, in the case of references, are also handled
       // in the previous switch statement.
     } else {
@@ -4894,23 +4896,23 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
-  bool is_byte_type = (field_type == Primitive::kPrimBoolean)
-    || (field_type == Primitive::kPrimByte);
+  DataType::Type field_type = field_info.GetFieldType();
+  bool is_byte_type = (field_type == DataType::Type::kBool)
+    || (field_type == DataType::Type::kInt8);
 
   // The register allocator does not support multiple
   // inputs that die at entry with one in a specific register.
   if (is_byte_type) {
     // Ensure the value is in a byte register.
     locations->SetInAt(1, Location::RegisterLocation(EAX));
-  } else if (Primitive::IsFloatingPointType(field_type)) {
-    if (is_volatile && field_type == Primitive::kPrimDouble) {
+  } else if (DataType::IsFloatingPointType(field_type)) {
+    if (is_volatile && field_type == DataType::Type::kFloat64) {
       // In order to satisfy the semantics of volatile, this must be a single instruction store.
       locations->SetInAt(1, Location::RequiresFpuRegister());
     } else {
       locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
     }
-  } else if (is_volatile && field_type == Primitive::kPrimLong) {
+  } else if (is_volatile && field_type == DataType::Type::kInt64) {
     // In order to satisfy the semantics of volatile, this must be a single instruction store.
     locations->SetInAt(1, Location::RequiresRegister());
 
@@ -4942,7 +4944,7 @@
   Register base = locations->InAt(0).AsRegister<Register>();
   Location value = locations->InAt(1);
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
@@ -4954,14 +4956,14 @@
   bool maybe_record_implicit_null_check_done = false;
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       if (value.IsConstant()) {
         __ movw(Address(base, offset),
                 Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
@@ -4971,13 +4973,13 @@
       break;
     }
 
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       if (kPoisonHeapReferences && needs_write_barrier) {
         // Note that in the case where `value` is a null reference,
         // we do not enter this block, as the reference does not
         // need poisoning.
-        DCHECK_EQ(field_type, Primitive::kPrimNot);
+        DCHECK_EQ(field_type, DataType::Type::kReference);
         Register temp = locations->GetTemp(0).AsRegister<Register>();
         __ movl(temp, value.AsRegister<Register>());
         __ PoisonHeapReference(temp);
@@ -4992,7 +4994,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (is_volatile) {
         XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
         XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
@@ -5015,7 +5017,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (value.IsConstant()) {
         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
         __ movl(Address(base, offset), Immediate(v));
@@ -5025,7 +5027,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (value.IsConstant()) {
         int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant());
         __ movl(Address(base, offset), Immediate(Low32Bits(v)));
@@ -5038,7 +5040,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
@@ -5203,7 +5205,7 @@
 
 void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier ?
@@ -5214,7 +5216,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps in case of long: we don't want the low move
@@ -5224,9 +5226,9 @@
     // the read barrier.
     locations->SetOut(
         Location::RequiresRegister(),
-        (instruction->GetType() == Primitive::kPrimLong || object_array_get_with_read_barrier) ?
-            Location::kOutputOverlap :
-            Location::kNoOutputOverlap);
+        (instruction->GetType() == DataType::Type::kInt64 || object_array_get_with_read_barrier)
+            ? Location::kOutputOverlap
+            : Location::kNoOutputOverlap);
   }
 }
 
@@ -5238,27 +5240,27 @@
   Location out_loc = locations->Out();
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   switch (type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       Register out = out_loc.AsRegister<Register>();
       __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       Register out = out_loc.AsRegister<Register>();
       __ movsxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       Register out = out_loc.AsRegister<Register>();
       __ movsxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       Register out = out_loc.AsRegister<Register>();
       if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
         // Branch cases into compressed and uncompressed for each index's type.
@@ -5282,13 +5284,13 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register out = out_loc.AsRegister<Register>();
       __ movl(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset));
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       static_assert(
           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -5318,7 +5320,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       DCHECK_NE(obj, out_loc.AsRegisterPairLow<Register>());
       __ movl(out_loc.AsRegisterPairLow<Register>(),
               CodeGeneratorX86::ArrayAddress(obj, index, TIMES_8, data_offset));
@@ -5328,24 +5330,24 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
       __ movss(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset));
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
       __ movsd(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_8, data_offset));
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
 
-  if (type == Primitive::kPrimNot || type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kReference || type == DataType::Type::kInt64) {
     // Potential implicit null checks, in the case of reference or
     // long arrays, are handled in the previous switch statement.
   } else {
@@ -5354,7 +5356,7 @@
 }
 
 void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -5366,8 +5368,8 @@
           LocationSummary::kCallOnSlowPath :
           LocationSummary::kNoCall);
 
-  bool is_byte_type = (value_type == Primitive::kPrimBoolean)
-      || (value_type == Primitive::kPrimByte);
+  bool is_byte_type = (value_type == DataType::Type::kBool)
+      || (value_type == DataType::Type::kInt8);
   // We need the inputs to be different than the output in case of long operation.
   // In case of a byte operation, the register allocator does not support multiple
   // inputs that die at entry with one in a specific register.
@@ -5376,7 +5378,7 @@
   if (is_byte_type) {
     // Ensure the value is in a byte register.
     locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
-  } else if (Primitive::IsFloatingPointType(value_type)) {
+  } else if (DataType::IsFloatingPointType(value_type)) {
     locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
   } else {
     locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
@@ -5395,7 +5397,7 @@
   Register array = array_loc.AsRegister<Register>();
   Location index = locations->InAt(1);
   Location value = locations->InAt(2);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
@@ -5404,8 +5406,8 @@
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_1, offset);
       if (value.IsRegister()) {
@@ -5417,8 +5419,8 @@
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_2, offset);
       if (value.IsRegister()) {
@@ -5430,7 +5432,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
 
@@ -5526,7 +5528,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
       if (value.IsRegister()) {
@@ -5540,7 +5542,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
       if (value.IsRegisterPair()) {
         __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset),
@@ -5560,7 +5562,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
       if (value.IsFpuRegister()) {
@@ -5574,7 +5576,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, offset);
       if (value.IsFpuRegister()) {
@@ -5591,7 +5593,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -5801,7 +5803,7 @@
       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
     }
   } else if (source.IsRegisterPair()) {
-      size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt);
+      size_t elem_size = DataType::Size(DataType::Type::kInt32);
       // Create stack space for 2 elements.
       __ subl(ESP, Immediate(2 * elem_size));
       __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>());
@@ -6955,8 +6957,8 @@
 void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
-         || instruction->GetResultType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32
+         || instruction->GetResultType() == DataType::Type::kInt64);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
   locations->SetOut(Location::SameAsFirstInput());
@@ -6980,7 +6982,7 @@
   Location second = locations->InAt(1);
   DCHECK(first.Equals(locations->Out()));
 
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     if (second.IsRegister()) {
       if (instruction->IsAnd()) {
         __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
@@ -7013,7 +7015,7 @@
       }
     }
   } else {
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
     if (second.IsRegisterPair()) {
       if (instruction->IsAnd()) {
         __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
@@ -7555,12 +7557,12 @@
   }
 
   switch (insn->GetType()) {
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetOut(Location::RequiresFpuRegister());
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       locations->SetOut(Location::RequiresRegister());
       break;
 
@@ -7580,19 +7582,19 @@
   HConstant *value = insn->GetConstant();
 
   switch (insn->GetType()) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       __ movss(out.AsFpuRegister<XmmRegister>(),
                codegen_->LiteralFloatAddress(
                   value->AsFloatConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       __ movsd(out.AsFpuRegister<XmmRegister>(),
                codegen_->LiteralDoubleAddress(
                   value->AsDoubleConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ movl(out.AsRegister<Register>(),
               codegen_->LiteralInt32Address(
                   value->AsIntConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
@@ -7785,13 +7787,13 @@
 }
 
 // TODO: target as memory.
-void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
+void CodeGeneratorX86::MoveFromReturnRegister(Location target, DataType::Type type) {
   if (!target.IsValid()) {
-    DCHECK_EQ(type, Primitive::kPrimVoid);
+    DCHECK_EQ(type, DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
   Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
   if (target.Equals(return_loc)) {
@@ -7800,10 +7802,10 @@
 
   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
   //       with the else branch.
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     HParallelMove parallel_move(GetGraph()->GetArena());
-    parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
-    parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
+    parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), DataType::Type::kInt32, nullptr);
+    parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), DataType::Type::kInt32, nullptr);
     GetMoveResolver()->EmitNativeCode(&parallel_move);
   } else {
     // Let the parallel move resolver take care of all of this.
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index b32d57a..fb61e75 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -83,8 +83,8 @@
   InvokeDexCallingConventionVisitorX86() {}
   virtual ~InvokeDexCallingConventionVisitorX86() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE;
   Location GetMethodLocation() const OVERRIDE;
 
  private:
@@ -103,13 +103,13 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return Location::RegisterLocation(EAX);
   }
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? Location::RegisterPairLocation(EAX, EDX)
         : Location::RegisterLocation(EAX);
   }
-  Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
-    return Primitive::Is64BitType(type)
+  Location GetSetValueLocation(DataType::Type type, bool is_instance) const OVERRIDE {
+    return DataType::Is64BitType(type)
         ? (is_instance
             ? Location::RegisterPairLocation(EDX, EBX)
             : Location::RegisterPairLocation(ECX, EDX))
@@ -117,7 +117,7 @@
             ? Location::RegisterLocation(EDX)
             : Location::RegisterLocation(ECX));
   }
-  Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::FpuRegisterLocation(XMM0);
   }
 
@@ -321,7 +321,7 @@
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
@@ -428,10 +428,10 @@
                               dex::TypeIndex dex_index,
                               Handle<mirror::Class> handle);
 
-  void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
+  void MoveFromReturnRegister(Location trg, DataType::Type type) OVERRIDE;
 
   // Emit linker patches.
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
 
   void PatchJitRootUse(uint8_t* code,
                        const uint8_t* roots_data,
@@ -456,8 +456,8 @@
     block_labels_ = CommonInitializeLabels<Label>();
   }
 
-  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
-    return type == Primitive::kPrimLong;
+  bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE {
+    return type == DataType::Type::kInt64;
   }
 
   bool ShouldSplitLongMoves() const OVERRIDE { return true; }
@@ -617,9 +617,9 @@
     HX86ComputeBaseMethodAddress* method_address;
   };
 
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   void EmitPcRelativeLinkerPatches(const ArenaDeque<X86PcRelativePatchInfo>& infos,
-                                   ArenaVector<LinkerPatch>* linker_patches);
+                                   ArenaVector<linker::LinkerPatch>* linker_patches);
 
   Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
 
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 39a6580..42704e9 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -25,6 +25,7 @@
 #include "heap_poisoning.h"
 #include "intrinsics.h"
 #include "intrinsics_x86_64.h"
+#include "linker/linker_patch.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
@@ -105,12 +106,12 @@
 
 class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
  public:
-  DivRemMinusOneSlowPathX86_64(HInstruction* at, Register reg, Primitive::Type type, bool is_div)
+  DivRemMinusOneSlowPathX86_64(HInstruction* at, Register reg, DataType::Type type, bool is_div)
       : SlowPathCode(at), cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     __ Bind(GetEntryLabel());
-    if (type_ == Primitive::kPrimInt) {
+    if (type_ == DataType::Type::kInt32) {
       if (is_div_) {
         __ negl(cpu_reg_);
       } else {
@@ -118,7 +119,7 @@
       }
 
     } else {
-      DCHECK_EQ(Primitive::kPrimLong, type_);
+      DCHECK_EQ(DataType::Type::kInt64, type_);
       if (is_div_) {
         __ negq(cpu_reg_);
       } else {
@@ -132,7 +133,7 @@
 
  private:
   const CpuRegister cpu_reg_;
-  const Primitive::Type type_;
+  const DataType::Type type_;
   const bool is_div_;
   DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
 };
@@ -214,10 +215,10 @@
     codegen->EmitParallelMoves(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         length_loc,
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt);
+        DataType::Type::kInt32);
     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
         ? kQuickThrowStringBounds
         : kQuickThrowArrayBounds;
@@ -359,10 +360,10 @@
     InvokeRuntimeCallingConvention calling_convention;
     codegen->EmitParallelMoves(locations->InAt(0),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                               Primitive::kPrimNot,
+                               DataType::Type::kReference,
                                locations->InAt(1),
                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                               Primitive::kPrimNot);
+                               DataType::Type::kReference);
     if (instruction_->IsInstanceOf()) {
       x86_64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
@@ -430,17 +431,17 @@
     parallel_move.AddMove(
         locations->InAt(0),
         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(1),
         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     parallel_move.AddMove(
         locations->InAt(2),
         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-        Primitive::kPrimNot,
+        DataType::Type::kReference,
         nullptr);
     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
 
@@ -833,16 +834,16 @@
     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
     parallel_move.AddMove(ref_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     parallel_move.AddMove(obj_,
                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
-                          Primitive::kPrimNot,
+                          DataType::Type::kReference,
                           nullptr);
     if (index.IsValid()) {
       parallel_move.AddMove(index,
                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
-                            Primitive::kPrimInt,
+                            DataType::Type::kInt32,
                             nullptr);
       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
     } else {
@@ -1106,10 +1107,10 @@
 // for method patch needs to point to the embedded constant which occupies the last 4 bytes.
 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
 
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
 inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
     const ArenaDeque<PatchInfo<Label>>& infos,
-    ArenaVector<LinkerPatch>* linker_patches) {
+    ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PatchInfo<Label>& info : infos) {
     uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
     linker_patches->push_back(
@@ -1117,7 +1118,7 @@
   }
 }
 
-void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
+void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
       boot_image_method_patches_.size() +
@@ -1128,24 +1129,25 @@
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(boot_image_type_patches_,
-                                                                linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
+        boot_image_method_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
+        boot_image_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
+        string_patches_, linker_patches);
   } else {
     DCHECK(boot_image_method_patches_.empty());
-    EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_,
-                                                                  linker_patches);
-    EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_,
-                                                                     linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
+        boot_image_type_patches_, linker_patches);
+    EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
+        string_patches_, linker_patches);
   }
-  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
-                                                                linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
-                                                              linker_patches);
-  EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
-                                                                linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
+      method_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
+      type_bss_entry_patches_, linker_patches);
+  EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
+      string_bss_entry_patches_, linker_patches);
   DCHECK_EQ(size, linker_patches->size());
 }
 
@@ -1441,7 +1443,7 @@
 }
 
 void CodeGeneratorX86_64::MoveLocation(
-    Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
+    Location dst, Location src, DataType::Type dst_type ATTRIBUTE_UNUSED) {
   Move(dst, src);
 }
 
@@ -1516,22 +1518,22 @@
 
   Location left = locations->InAt(0);
   Location right = locations->InAt(1);
-  Primitive::Type type = condition->InputAt(0)->GetType();
+  DataType::Type type = condition->InputAt(0)->GetType();
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       codegen_->GenerateIntCompare(left, right);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       codegen_->GenerateLongCompare(left, right);
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (right.IsFpuRegister()) {
         __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
       } else if (right.IsConstant()) {
@@ -1545,7 +1547,7 @@
       }
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (right.IsFpuRegister()) {
         __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
       } else if (right.IsConstant()) {
@@ -1578,17 +1580,17 @@
   GenerateCompareTest(condition);
 
   // Now generate the correct jump(s).
-  Primitive::Type type = condition->InputAt(0)->GetType();
+  DataType::Type type = condition->InputAt(0)->GetType();
   switch (type) {
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       GenerateFPJumps(condition, true_target, false_target);
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       GenerateFPJumps(condition, true_target, false_target);
       break;
     }
@@ -1611,7 +1613,7 @@
   // conditions if they are materialized due to the complex branching.
   return cond->IsCondition() &&
          cond->GetNext() == branch &&
-         !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
+         !DataType::IsFloatingPointType(cond->InputAt(0)->GetType());
 }
 
 template<class LabelType>
@@ -1675,8 +1677,8 @@
 
     // If this is a long or FP comparison that has been folded into
     // the HCondition, generate the comparison directly.
-    Primitive::Type type = condition->InputAt(0)->GetType();
-    if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+    DataType::Type type = condition->InputAt(0)->GetType();
+    if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
       GenerateCompareTestAndBranch(condition, true_target, false_target);
       return;
     }
@@ -1748,14 +1750,14 @@
 
 static bool SelectCanUseCMOV(HSelect* select) {
   // There are no conditional move instructions for XMMs.
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     return false;
   }
 
   // A FP condition doesn't generate the single CC that we need.
   HInstruction* condition = select->GetCondition();
   if (condition->IsCondition() &&
-      Primitive::IsFloatingPointType(condition->InputAt(0)->GetType())) {
+      DataType::IsFloatingPointType(condition->InputAt(0)->GetType())) {
     return false;
   }
 
@@ -1765,7 +1767,7 @@
 
 void LocationsBuilderX86_64::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
-  if (Primitive::IsFloatingPointType(select->GetType())) {
+  if (DataType::IsFloatingPointType(select->GetType())) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
     locations->SetInAt(1, Location::Any());
   } else {
@@ -1824,7 +1826,7 @@
 
     // If the condition is true, overwrite the output, which already contains false.
     // Generate the correct sized CMOV.
-    bool is_64_bit = Primitive::Is64BitType(select->GetType());
+    bool is_64_bit = DataType::Is64BitType(select->GetType());
     if (value_true_loc.IsRegister()) {
       __ cmov(cond, value_false, value_true_loc.AsRegister<CpuRegister>(), is_64_bit);
     } else {
@@ -1860,12 +1862,12 @@
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   // Handle the long/FP comparisons made in instruction simplification.
   switch (cond->InputAt(0)->GetType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       break;
@@ -1900,14 +1902,14 @@
       codegen_->GenerateIntCompare(lhs, rhs);
       __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
       return;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // Clear output register: setcc only sets the low byte.
       __ xorl(reg, reg);
 
       codegen_->GenerateLongCompare(lhs, rhs);
       __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
       return;
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
       if (rhs.IsConstant()) {
         float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
@@ -1920,7 +1922,7 @@
       GenerateFPJumps(cond, &true_label, &false_label);
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
       if (rhs.IsConstant()) {
         double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
@@ -2033,19 +2035,19 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::RequiresRegister());
@@ -2063,23 +2065,23 @@
   Location right = locations->InAt(1);
 
   NearLabel less, greater, done;
-  Primitive::Type type = compare->InputAt(0)->GetType();
+  DataType::Type type = compare->InputAt(0)->GetType();
   Condition less_cond = kLess;
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       codegen_->GenerateIntCompare(left, right);
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       codegen_->GenerateLongCompare(left, right);
       break;
     }
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
       if (right.IsConstant()) {
         float value = right.GetConstant()->AsFloatConstant()->GetValue();
@@ -2093,7 +2095,7 @@
       less_cond = kBelow;  //  ucomis{s,d} sets CF
       break;
     }
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
       if (right.IsConstant()) {
         double value = right.GetConstant()->AsDoubleConstant()->GetValue();
@@ -2205,18 +2207,18 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
   switch (ret->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RegisterLocation(RAX));
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
       break;
 
@@ -2228,18 +2230,18 @@
 void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
   if (kIsDebugBuild) {
     switch (ret->InputAt(0)->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimLong:
+      case DataType::Type::kBool:
+      case DataType::Type::kInt8:
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+      case DataType::Type::kInt32:
+      case DataType::Type::kReference:
+      case DataType::Type::kInt64:
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
         break;
 
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat32:
+      case DataType::Type::kFloat64:
         DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
                   XMM0);
         break;
@@ -2251,22 +2253,22 @@
   codegen_->GenerateFrameExit();
 }
 
-Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
+Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(DataType::Type type) const {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt64:
       return Location::RegisterLocation(RAX);
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       return Location::NoLocation();
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat64:
+    case DataType::Type::kFloat32:
       return Location::FpuRegisterLocation(XMM0);
   }
 
@@ -2277,14 +2279,14 @@
   return Location::RegisterLocation(kMethodRegisterArgument);
 }
 
-Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       uint32_t index = gp_index_++;
       stack_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2294,7 +2296,7 @@
       }
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t index = gp_index_;
       stack_index_ += 2;
       if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2306,7 +2308,7 @@
       }
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t index = float_index_++;
       stack_index_++;
       if (index < calling_convention.GetNumberOfFpuRegisters()) {
@@ -2316,7 +2318,7 @@
       }
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t index = float_index_++;
       stack_index_ += 2;
       if (index < calling_convention.GetNumberOfFpuRegisters()) {
@@ -2326,7 +2328,7 @@
       }
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
       break;
   }
@@ -2467,14 +2469,14 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       locations->AddTemp(Location::RequiresFpuRegister());
@@ -2490,19 +2492,19 @@
   Location out = locations->Out();
   Location in = locations->InAt(0);
   switch (neg->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       DCHECK(in.IsRegister());
       DCHECK(in.Equals(out));
       __ negl(out.AsRegister<CpuRegister>());
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       DCHECK(in.IsRegister());
       DCHECK(in.Equals(out));
       __ negq(out.AsRegister<CpuRegister>());
       break;
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       DCHECK(in.Equals(out));
       XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       // Implement float negation with an exclusive or with value
@@ -2513,7 +2515,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       DCHECK(in.Equals(out));
       XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
       // Implement double negation with an exclusive or with value
@@ -2532,23 +2534,23 @@
 void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
 
   // The Java language does not allow treating boolean as an integral type but
   // our bit representation makes it safe.
 
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to byte is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2560,15 +2562,15 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2580,21 +2582,21 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-int' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
@@ -2606,14 +2608,14 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           // TODO: We would benefit from a (to-be-implemented)
           // Location::RegisterOrStackSlot requirement for this input.
@@ -2621,13 +2623,13 @@
           locations->SetOut(Location::RequiresRegister());
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-long' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-long' instruction.
           locations->SetInAt(0, Location::RequiresFpuRegister());
           locations->SetOut(Location::RequiresRegister());
@@ -2639,15 +2641,15 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to char is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `int-to-char' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2659,26 +2661,26 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-float' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-float' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -2690,26 +2692,26 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-double' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-double' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           locations->SetInAt(0, Location::Any());
           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -2731,19 +2733,19 @@
   LocationSummary* locations = conversion->GetLocations();
   Location out = locations->Out();
   Location in = locations->InAt(0);
-  Primitive::Type result_type = conversion->GetResultType();
-  Primitive::Type input_type = conversion->GetInputType();
+  DataType::Type result_type = conversion->GetResultType();
+  DataType::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
   switch (result_type) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to byte is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-byte' instruction.
           if (in.IsRegister()) {
             __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
@@ -2762,15 +2764,15 @@
       }
       break;
 
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to short is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-short' instruction.
           if (in.IsRegister()) {
             __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
@@ -2789,9 +2791,9 @@
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-int' instruction.
           if (in.IsRegister()) {
             __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
@@ -2806,7 +2808,7 @@
           }
           break;
 
-        case Primitive::kPrimFloat: {
+        case DataType::Type::kFloat32: {
           // Processing a Dex `float-to-int' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           CpuRegister output = out.AsRegister<CpuRegister>();
@@ -2828,7 +2830,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat64: {
           // Processing a Dex `double-to-int' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           CpuRegister output = out.AsRegister<CpuRegister>();
@@ -2856,21 +2858,21 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
         DCHECK(out.IsRegister());
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-long' instruction.
           DCHECK(in.IsRegister());
           __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
           break;
 
-        case Primitive::kPrimFloat: {
+        case DataType::Type::kFloat32: {
           // Processing a Dex `float-to-long' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           CpuRegister output = out.AsRegister<CpuRegister>();
@@ -2892,7 +2894,7 @@
           break;
         }
 
-        case Primitive::kPrimDouble: {
+        case DataType::Type::kFloat64: {
           // Processing a Dex `double-to-long' instruction.
           XmmRegister input = in.AsFpuRegister<XmmRegister>();
           CpuRegister output = out.AsRegister<CpuRegister>();
@@ -2920,15 +2922,15 @@
       }
       break;
 
-    case Primitive::kPrimChar:
+    case DataType::Type::kUint16:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Type conversion from long to char is a result of code transformations.
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // Processing a Dex `int-to-char' instruction.
           if (in.IsRegister()) {
             __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
@@ -2947,14 +2949,14 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-float' instruction.
           if (in.IsRegister()) {
             __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
@@ -2968,7 +2970,7 @@
           }
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-float' instruction.
           if (in.IsRegister()) {
             __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
@@ -2982,7 +2984,7 @@
           }
           break;
 
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           // Processing a Dex `double-to-float' instruction.
           if (in.IsFpuRegister()) {
             __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
@@ -3002,14 +3004,14 @@
       };
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           // Boolean input is a result of code transformations.
-        case Primitive::kPrimByte:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
+        case DataType::Type::kInt8:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
           // Processing a Dex `int-to-double' instruction.
           if (in.IsRegister()) {
             __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
@@ -3023,7 +3025,7 @@
           }
           break;
 
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // Processing a Dex `long-to-double' instruction.
           if (in.IsRegister()) {
             __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
@@ -3037,7 +3039,7 @@
           }
           break;
 
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           // Processing a Dex `float-to-double' instruction.
           if (in.IsFpuRegister()) {
             __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
@@ -3067,14 +3069,14 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       // We can use a leaq or addq if the constant can fit in an immediate.
       locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
@@ -3082,8 +3084,8 @@
       break;
     }
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat64:
+    case DataType::Type::kFloat32: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
@@ -3102,7 +3104,7 @@
   Location out = locations->Out();
 
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
@@ -3127,7 +3129,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
@@ -3152,7 +3154,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3167,7 +3169,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3191,20 +3193,20 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
@@ -3221,7 +3223,7 @@
   Location second = locations->InAt(1);
   DCHECK(first.Equals(locations->Out()));
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (second.IsRegister()) {
         __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
       } else if (second.IsConstant()) {
@@ -3232,7 +3234,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsConstant()) {
         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
         DCHECK(IsInt<32>(value));
@@ -3243,7 +3245,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3258,7 +3260,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3282,7 +3284,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       if (mul->InputAt(1)->IsIntConstant()) {
@@ -3293,7 +3295,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
       if (mul->InputAt(1)->IsLongConstant() &&
@@ -3305,8 +3307,8 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
@@ -3324,7 +3326,7 @@
   Location second = locations->InAt(1);
   Location out = locations->Out();
   switch (mul->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       // The constant may have ended up in a register, so test explicitly to avoid
       // problems where the output may not be the same as the first operand.
       if (mul->InputAt(1)->IsIntConstant()) {
@@ -3340,7 +3342,7 @@
                  Address(CpuRegister(RSP), second.GetStackIndex()));
       }
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       // The constant may have ended up in a register, so test explicitly to avoid
       // problems where the output may not be the same as the first operand.
       if (mul->InputAt(1)->IsLongConstant()) {
@@ -3365,7 +3367,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       DCHECK(first.Equals(out));
       if (second.IsFpuRegister()) {
         __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
@@ -3381,7 +3383,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       DCHECK(first.Equals(out));
       if (second.IsFpuRegister()) {
         __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
@@ -3425,9 +3427,9 @@
 }
 
 void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
-  Primitive::Type type = rem->GetResultType();
-  bool is_float = type == Primitive::kPrimFloat;
-  size_t elem_size = Primitive::ComponentSize(type);
+  DataType::Type type = rem->GetResultType();
+  bool is_float = type == DataType::Type::kFloat32;
+  size_t elem_size = DataType::Size(type);
   LocationSummary* locations = rem->GetLocations();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
@@ -3491,7 +3493,7 @@
   DCHECK(imm == 1 || imm == -1);
 
   switch (instruction->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (instruction->IsRem()) {
         __ xorl(output_register, output_register);
       } else {
@@ -3503,7 +3505,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (instruction->IsRem()) {
         __ xorl(output_register, output_register);
       } else {
@@ -3533,7 +3535,7 @@
 
   CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
 
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     __ leal(tmp, Address(numerator, abs_imm - 1));
     __ testl(numerator, numerator);
     __ cmov(kGreaterEqual, tmp, numerator);
@@ -3546,7 +3548,7 @@
 
     __ movl(output_register, tmp);
   } else {
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
     CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
 
     codegen_->Load64BitValue(rdx, abs_imm - 1);
@@ -3589,7 +3591,7 @@
   int shift;
 
   // TODO: can these branches be written as one?
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     int imm = second.GetConstant()->AsIntConstant()->GetValue();
 
     CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
@@ -3624,7 +3626,7 @@
   } else {
     int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
 
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
 
     CpuRegister rax = eax;
     CpuRegister rdx = edx;
@@ -3677,8 +3679,8 @@
 
 void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
   DCHECK(instruction->IsDiv() || instruction->IsRem());
-  Primitive::Type type = instruction->GetResultType();
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DataType::Type type = instruction->GetResultType();
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   bool is_div = instruction->IsDiv();
   LocationSummary* locations = instruction->GetLocations();
@@ -3712,7 +3714,7 @@
     // 0x80000000(00000000)/-1 triggers an arithmetic exception!
     // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
     // so it's safe to just use negl instead of more complex comparisons.
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       __ cmpl(second_reg, Immediate(-1));
       __ j(kEqual, slow_path->GetEntryLabel());
       // edx:eax <- sign-extended of eax
@@ -3735,8 +3737,8 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
   switch (div->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RegisterLocation(RAX));
       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::SameAsFirstInput());
@@ -3751,8 +3753,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
@@ -3770,15 +3772,15 @@
   Location second = locations->InAt(1);
   DCHECK(first.Equals(locations->Out()));
 
-  Primitive::Type type = div->GetResultType();
+  DataType::Type type = div->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GenerateDivRemIntegral(div);
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (second.IsFpuRegister()) {
         __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3793,7 +3795,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (second.IsFpuRegister()) {
         __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       } else if (second.IsConstant()) {
@@ -3814,13 +3816,13 @@
 }
 
 void LocationsBuilderX86_64::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   LocationSummary* locations =
     new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
 
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RegisterLocation(RAX));
       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       // Intel uses rdx:rax as the dividend and puts the remainder in rdx
@@ -3834,8 +3836,8 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       locations->SetInAt(0, Location::Any());
       locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::RequiresFpuRegister());
@@ -3849,15 +3851,15 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
-  Primitive::Type type = rem->GetResultType();
+  DataType::Type type = rem->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       GenerateDivRemIntegral(rem);
       break;
     }
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64: {
       GenerateRemFP(rem);
       break;
     }
@@ -3880,11 +3882,11 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32: {
       if (value.IsRegister()) {
         __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
         __ j(kEqual, slow_path->GetEntryLabel());
@@ -3899,7 +3901,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (value.IsRegister()) {
         __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
         __ j(kEqual, slow_path->GetEntryLabel());
@@ -3926,8 +3928,8 @@
       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
 
   switch (op->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       // The shift count needs to be in CL.
       locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
@@ -3947,7 +3949,7 @@
   Location second = locations->InAt(1);
 
   switch (op->GetResultType()) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       if (second.IsRegister()) {
         CpuRegister second_reg = second.AsRegister<CpuRegister>();
         if (op->IsShl()) {
@@ -3969,7 +3971,7 @@
       }
       break;
     }
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (second.IsRegister()) {
         CpuRegister second_reg = second.AsRegister<CpuRegister>();
         if (op->IsShl()) {
@@ -4002,8 +4004,8 @@
       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
 
   switch (ror->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64: {
       locations->SetInAt(0, Location::RequiresRegister());
       // The shift count needs to be in CL (unless it is a constant).
       locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, ror->InputAt(1)));
@@ -4022,7 +4024,7 @@
   Location second = locations->InAt(1);
 
   switch (ror->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       if (second.IsRegister()) {
         CpuRegister second_reg = second.AsRegister<CpuRegister>();
         __ rorl(first_reg, second_reg);
@@ -4031,7 +4033,7 @@
         __ rorl(first_reg, imm);
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (second.IsRegister()) {
         CpuRegister second_reg = second.AsRegister<CpuRegister>();
         __ rorq(first_reg, second_reg);
@@ -4184,11 +4186,11 @@
             locations->Out().AsRegister<CpuRegister>().AsRegister());
   Location out = locations->Out();
   switch (not_->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ notl(out.AsRegister<CpuRegister>());
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ notq(out.AsRegister<CpuRegister>());
       break;
 
@@ -4253,7 +4255,7 @@
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
   bool object_field_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_field_get_with_read_barrier ?
@@ -4263,7 +4265,7 @@
     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister());
   } else {
     // The output overlaps for an object field get when read barriers
@@ -4284,36 +4286,36 @@
   CpuRegister base = base_loc.AsRegister<CpuRegister>();
   Location out = locations->Out();
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
   switch (field_type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       // /* HeapReference<Object> */ out = *(base + offset)
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         // Note that a potential implicit null check is handled in this
@@ -4337,27 +4339,27 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
 
-  if (field_type == Primitive::kPrimNot) {
+  if (field_type == DataType::Type::kReference) {
     // Potential implicit null checks, in the case of reference
     // fields, are handled in the previous switch statement.
   } else {
@@ -4365,7 +4367,7 @@
   }
 
   if (is_volatile) {
-    if (field_type == Primitive::kPrimNot) {
+    if (field_type == DataType::Type::kReference) {
       // Memory barriers, in the case of references, are also handled
       // in the previous switch statement.
     } else {
@@ -4380,13 +4382,13 @@
 
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   bool is_volatile = field_info.IsVolatile();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
 
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
     if (is_volatile) {
       // In order to satisfy the semantics of volatile, this must be a single instruction store.
       locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
@@ -4405,7 +4407,7 @@
     // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     locations->AddTemp(Location::RequiresRegister());
-  } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+  } else if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
     // Temporary register for the reference poisoning.
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -4420,7 +4422,7 @@
   CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
   Location value = locations->InAt(1);
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
   if (is_volatile) {
@@ -4430,8 +4432,8 @@
   bool maybe_record_implicit_null_check_done = false;
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       if (value.IsConstant()) {
         __ movb(Address(base, offset),
                 Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
@@ -4441,8 +4443,8 @@
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       if (value.IsConstant()) {
         __ movw(Address(base, offset),
                 Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
@@ -4452,17 +4454,17 @@
       break;
     }
 
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference: {
       if (value.IsConstant()) {
         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
-        // `field_type == Primitive::kPrimNot` implies `v == 0`.
-        DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
+        // `field_type == DataType::Type::kReference` implies `v == 0`.
+        DCHECK((field_type != DataType::Type::kReference) || (v == 0));
         // Note: if heap poisoning is enabled, no need to poison
         // (negate) `v` if it is a reference, as it would be null.
         __ movl(Address(base, offset), Immediate(v));
       } else {
-        if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+        if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
           CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
           __ movl(temp, value.AsRegister<CpuRegister>());
           __ PoisonHeapReference(temp);
@@ -4474,7 +4476,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (value.IsConstant()) {
         int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
         codegen_->MoveInt64ToAddress(Address(base, offset),
@@ -4488,7 +4490,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (value.IsConstant()) {
         int32_t v =
             bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
@@ -4499,7 +4501,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (value.IsConstant()) {
         int64_t v =
             bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
@@ -4514,7 +4516,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
       UNREACHABLE();
   }
@@ -4679,7 +4681,7 @@
 
 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
   bool object_array_get_with_read_barrier =
-      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
+      kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction,
                                                    object_array_get_with_read_barrier ?
@@ -4690,7 +4692,7 @@
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(instruction->GetType())) {
+  if (DataType::IsFloatingPointType(instruction->GetType())) {
     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   } else {
     // The output overlaps for an object array get when read barriers
@@ -4710,27 +4712,27 @@
   Location out_loc = locations->Out();
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
 
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   switch (type) {
-    case Primitive::kPrimBoolean: {
+    case DataType::Type::kBool: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
       break;
     }
 
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt8: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       __ movsxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
       break;
     }
 
-    case Primitive::kPrimShort: {
+    case DataType::Type::kInt16: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
       break;
     }
 
-    case Primitive::kPrimChar: {
+    case DataType::Type::kUint16: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
         // Branch cases into compressed and uncompressed for each index's type.
@@ -4752,13 +4754,13 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       static_assert(
           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
@@ -4788,30 +4790,30 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
       __ movq(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
       __ movss(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
       __ movsd(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Potential implicit null checks, in the case of reference
     // arrays, are handled in the previous switch statement.
   } else {
@@ -4820,7 +4822,7 @@
 }
 
 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
 
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -4834,7 +4836,7 @@
 
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(value_type)) {
+  if (DataType::IsFloatingPointType(value_type)) {
     locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
   } else {
     locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
@@ -4853,7 +4855,7 @@
   CpuRegister array = array_loc.AsRegister<CpuRegister>();
   Location index = locations->InAt(1);
   Location value = locations->InAt(2);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
@@ -4862,8 +4864,8 @@
   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_1, offset);
       if (value.IsRegister()) {
@@ -4875,8 +4877,8 @@
       break;
     }
 
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_2, offset);
       if (value.IsRegister()) {
@@ -4889,7 +4891,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
 
@@ -4985,7 +4987,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
       if (value.IsRegister()) {
@@ -4999,7 +5001,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
       if (value.IsRegister()) {
@@ -5014,7 +5016,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
       if (value.IsFpuRegister()) {
@@ -5028,7 +5030,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
       Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
       if (value.IsFpuRegister()) {
@@ -5044,7 +5046,7 @@
       break;
     }
 
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
@@ -6359,8 +6361,8 @@
 void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
-         || instruction->GetResultType() == Primitive::kPrimLong);
+  DCHECK(instruction->GetResultType() == DataType::Type::kInt32
+         || instruction->GetResultType() == DataType::Type::kInt64);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
   locations->SetOut(Location::SameAsFirstInput());
@@ -6384,7 +6386,7 @@
   Location second = locations->InAt(1);
   DCHECK(first.Equals(locations->Out()));
 
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     if (second.IsRegister()) {
       if (instruction->IsAnd()) {
         __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
@@ -6416,7 +6418,7 @@
       }
     }
   } else {
-    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
     CpuRegister first_reg = first.AsRegister<CpuRegister>();
     bool second_is_constant = false;
     int64_t value = 0;
@@ -7094,13 +7096,13 @@
 }
 
 // TODO: trg as memory.
-void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
+void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, DataType::Type type) {
   if (!trg.IsValid()) {
-    DCHECK_EQ(type, Primitive::kPrimVoid);
+    DCHECK_EQ(type, DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
   Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
   if (trg.Equals(return_loc)) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index f5fa86b..6f67a45 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -89,16 +89,16 @@
   Location GetFieldIndexLocation() const OVERRIDE {
     return Location::RegisterLocation(RDI);
   }
-  Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::RegisterLocation(RAX);
   }
-  Location GetSetValueLocation(Primitive::Type type ATTRIBUTE_UNUSED, bool is_instance)
+  Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED, bool is_instance)
       const OVERRIDE {
     return is_instance
         ? Location::RegisterLocation(RDX)
         : Location::RegisterLocation(RSI);
   }
-  Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return Location::FpuRegisterLocation(XMM0);
   }
 
@@ -112,8 +112,8 @@
   InvokeDexCallingConventionVisitorX86_64() {}
   virtual ~InvokeDexCallingConventionVisitorX86_64() {}
 
-  Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetNextLocation(DataType::Type type) OVERRIDE;
+  Location GetReturnLocation(DataType::Type type) const OVERRIDE;
   Location GetMethodLocation() const OVERRIDE;
 
  private:
@@ -299,7 +299,7 @@
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
-  void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
+  void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
@@ -384,7 +384,7 @@
     block_labels_ = CommonInitializeLabels<Label>();
   }
 
-  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+  bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
     return false;
   }
 
@@ -422,9 +422,9 @@
                               dex::TypeIndex dex_index,
                               Handle<mirror::Class> handle);
 
-  void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
+  void MoveFromReturnRegister(Location trg, DataType::Type type) OVERRIDE;
 
-  void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+  void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
 
   void PatchJitRootUse(uint8_t* code,
                        const uint8_t* roots_data,
@@ -586,9 +586,9 @@
   static constexpr int32_t kDummy32BitOffset = 256;
 
  private:
-  template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
+  template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
   static void EmitPcRelativeLinkerPatches(const ArenaDeque<PatchInfo<Label>>& infos,
-                                          ArenaVector<LinkerPatch>* linker_patches);
+                                          ArenaVector<linker::LinkerPatch>* linker_patches);
 
   // Labels for each block that will be compiled.
   Label* block_labels_;  // Indexed by block id.
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 0a8e97c..896fcfa 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -91,7 +91,7 @@
   for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
     ArenaPool pool;
     ArenaAllocator arena(&pool);
-    HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
+    HGraph* graph = CreateCFG(&arena, data, DataType::Type::kInt64);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
     RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
@@ -602,7 +602,7 @@
 static void TestComparison(IfCondition condition,
                            int64_t i,
                            int64_t j,
-                           Primitive::Type type,
+                           DataType::Type type,
                            const CodegenTargetConfig target_config) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
@@ -626,11 +626,11 @@
 
   HInstruction* op1;
   HInstruction* op2;
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     op1 = graph->GetIntConstant(i);
     op2 = graph->GetIntConstant(j);
   } else {
-    DCHECK_EQ(type, Primitive::kPrimLong);
+    DCHECK_EQ(type, DataType::Type::kInt64);
     op1 = graph->GetLongConstant(i);
     op2 = graph->GetLongConstant(j);
   }
@@ -693,7 +693,8 @@
     for (int64_t i = -1; i <= 1; i++) {
       for (int64_t j = -1; j <= 1; j++) {
         for (int cond = kCondFirst; cond <= kCondLast; cond++) {
-          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
+          TestComparison(
+              static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
         }
       }
     }
@@ -705,7 +706,8 @@
     for (int64_t i = -1; i <= 1; i++) {
       for (int64_t j = -1; j <= 1; j++) {
         for (int cond = kCondFirst; cond <= kCondLast; cond++) {
-          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
+          TestComparison(
+              static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
         }
       }
     }
@@ -728,8 +730,8 @@
   // used as temps; however GPR scratch register is required for big stack offsets which don't fit
   // LDR encoding. So the following code is a regression test for that situation.
   HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
-  move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), Primitive::kPrimInt, nullptr);
-  move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), Primitive::kPrimInt, nullptr);
+  move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
+  move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
   codegen.GetMoveResolver()->EmitNativeCode(move);
 
   InternalCodeAllocator code_allocator;
@@ -778,11 +780,11 @@
   HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
   move->AddMove(Location::DoubleStackSlot(0),
                 Location::DoubleStackSlot(257),
-                Primitive::kPrimDouble,
+                DataType::Type::kFloat64,
                 nullptr);
   move->AddMove(Location::DoubleStackSlot(257),
                 Location::DoubleStackSlot(0),
-                Primitive::kPrimDouble,
+                DataType::Type::kFloat64,
                 nullptr);
   codegen.GetMoveResolver()->EmitNativeCode(move);
 
@@ -806,19 +808,19 @@
     HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
     move->AddMove(Location::SIMDStackSlot(0),
                   Location::SIMDStackSlot(257),
-                  Primitive::kPrimDouble,
+                  DataType::Type::kFloat64,
                   nullptr);
     move->AddMove(Location::SIMDStackSlot(257),
                   Location::SIMDStackSlot(0),
-                  Primitive::kPrimDouble,
+                  DataType::Type::kFloat64,
                   nullptr);
     move->AddMove(Location::FpuRegisterLocation(0),
                   Location::FpuRegisterLocation(1),
-                  Primitive::kPrimDouble,
+                  DataType::Type::kFloat64,
                   nullptr);
     move->AddMove(Location::FpuRegisterLocation(1),
                   Location::FpuRegisterLocation(0),
-                  Primitive::kPrimDouble,
+                  DataType::Type::kFloat64,
                   nullptr);
     codegen.GetMoveResolver()->EmitNativeCode(move);
     graph->SetHasSIMD(false);
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index e354654..356ff9f 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -76,8 +76,8 @@
   return vixl::aarch32::Register(location.reg());
 }
 
-inline vixl::aarch32::Register RegisterFrom(Location location, Primitive::Type type) {
-  DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type)) << type;
+inline vixl::aarch32::Register RegisterFrom(Location location, DataType::Type type) {
+  DCHECK(type != DataType::Type::kVoid && !DataType::IsFloatingPointType(type)) << type;
   return RegisterFrom(location);
 }
 
@@ -94,20 +94,20 @@
 }
 
 inline vixl::aarch32::SRegister OutputSRegister(HInstruction* instr) {
-  Primitive::Type type = instr->GetType();
-  DCHECK_EQ(type, Primitive::kPrimFloat) << type;
+  DataType::Type type = instr->GetType();
+  DCHECK_EQ(type, DataType::Type::kFloat32) << type;
   return SRegisterFrom(instr->GetLocations()->Out());
 }
 
 inline vixl::aarch32::DRegister OutputDRegister(HInstruction* instr) {
-  Primitive::Type type = instr->GetType();
-  DCHECK_EQ(type, Primitive::kPrimDouble) << type;
+  DataType::Type type = instr->GetType();
+  DCHECK_EQ(type, DataType::Type::kFloat64) << type;
   return DRegisterFrom(instr->GetLocations()->Out());
 }
 
 inline vixl::aarch32::VRegister OutputVRegister(HInstruction* instr) {
-  Primitive::Type type = instr->GetType();
-  if (type == Primitive::kPrimFloat) {
+  DataType::Type type = instr->GetType();
+  if (type == DataType::Type::kFloat32) {
     return OutputSRegister(instr);
   } else {
     return OutputDRegister(instr);
@@ -115,23 +115,23 @@
 }
 
 inline vixl::aarch32::SRegister InputSRegisterAt(HInstruction* instr, int input_index) {
-  Primitive::Type type = instr->InputAt(input_index)->GetType();
-  DCHECK_EQ(type, Primitive::kPrimFloat) << type;
+  DataType::Type type = instr->InputAt(input_index)->GetType();
+  DCHECK_EQ(type, DataType::Type::kFloat32) << type;
   return SRegisterFrom(instr->GetLocations()->InAt(input_index));
 }
 
 inline vixl::aarch32::DRegister InputDRegisterAt(HInstruction* instr, int input_index) {
-  Primitive::Type type = instr->InputAt(input_index)->GetType();
-  DCHECK_EQ(type, Primitive::kPrimDouble) << type;
+  DataType::Type type = instr->InputAt(input_index)->GetType();
+  DCHECK_EQ(type, DataType::Type::kFloat64) << type;
   return DRegisterFrom(instr->GetLocations()->InAt(input_index));
 }
 
 inline vixl::aarch32::VRegister InputVRegisterAt(HInstruction* instr, int input_index) {
-  Primitive::Type type = instr->InputAt(input_index)->GetType();
-  if (type == Primitive::kPrimFloat) {
+  DataType::Type type = instr->InputAt(input_index)->GetType();
+  if (type == DataType::Type::kFloat32) {
     return InputSRegisterAt(instr, input_index);
   } else {
-    DCHECK_EQ(type, Primitive::kPrimDouble);
+    DCHECK_EQ(type, DataType::Type::kFloat64);
     return InputDRegisterAt(instr, input_index);
   }
 }
@@ -196,7 +196,7 @@
   return instr->AsConstant()->GetValueAsUint64();
 }
 
-inline vixl::aarch32::Operand OperandFrom(Location location, Primitive::Type type) {
+inline vixl::aarch32::Operand OperandFrom(Location location, DataType::Type type) {
   if (location.IsRegister()) {
     return vixl::aarch32::Operand(RegisterFrom(location, type));
   } else {
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index e73fd7d..102acb3 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -73,9 +73,9 @@
   return vixl::aarch64::Register::GetWRegFromCode(VIXLRegCodeFromART(location.reg()));
 }
 
-inline vixl::aarch64::Register RegisterFrom(Location location, Primitive::Type type) {
-  DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type)) << type;
-  return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
+inline vixl::aarch64::Register RegisterFrom(Location location, DataType::Type type) {
+  DCHECK(type != DataType::Type::kVoid && !DataType::IsFloatingPointType(type)) << type;
+  return type == DataType::Type::kInt64 ? XRegisterFrom(location) : WRegisterFrom(location);
 }
 
 inline vixl::aarch64::Register OutputRegister(HInstruction* instr) {
@@ -107,9 +107,9 @@
   return vixl::aarch64::FPRegister::GetSRegFromCode(location.reg());
 }
 
-inline vixl::aarch64::FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
-  DCHECK(Primitive::IsFloatingPointType(type)) << type;
-  return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
+inline vixl::aarch64::FPRegister FPRegisterFrom(Location location, DataType::Type type) {
+  DCHECK(DataType::IsFloatingPointType(type)) << type;
+  return type == DataType::Type::kFloat64 ? DRegisterFrom(location) : SRegisterFrom(location);
 }
 
 inline vixl::aarch64::FPRegister OutputFPRegister(HInstruction* instr) {
@@ -121,20 +121,20 @@
                         instr->InputAt(input_index)->GetType());
 }
 
-inline vixl::aarch64::CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
-  return Primitive::IsFloatingPointType(type)
+inline vixl::aarch64::CPURegister CPURegisterFrom(Location location, DataType::Type type) {
+  return DataType::IsFloatingPointType(type)
       ? vixl::aarch64::CPURegister(FPRegisterFrom(location, type))
       : vixl::aarch64::CPURegister(RegisterFrom(location, type));
 }
 
 inline vixl::aarch64::CPURegister OutputCPURegister(HInstruction* instr) {
-  return Primitive::IsFloatingPointType(instr->GetType())
+  return DataType::IsFloatingPointType(instr->GetType())
       ? static_cast<vixl::aarch64::CPURegister>(OutputFPRegister(instr))
       : static_cast<vixl::aarch64::CPURegister>(OutputRegister(instr));
 }
 
 inline vixl::aarch64::CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
-  return Primitive::IsFloatingPointType(instr->InputAt(index)->GetType())
+  return DataType::IsFloatingPointType(instr->InputAt(index)->GetType())
       ? static_cast<vixl::aarch64::CPURegister>(InputFPRegisterAt(instr, index))
       : static_cast<vixl::aarch64::CPURegister>(InputRegisterAt(instr, index));
 }
@@ -142,9 +142,9 @@
 inline vixl::aarch64::CPURegister InputCPURegisterOrZeroRegAt(HInstruction* instr,
                                                                      int index) {
   HInstruction* input = instr->InputAt(index);
-  Primitive::Type input_type = input->GetType();
+  DataType::Type input_type = input->GetType();
   if (input->IsConstant() && input->AsConstant()->IsZeroBitPattern()) {
-    return (Primitive::ComponentSize(input_type) >= vixl::aarch64::kXRegSizeInBytes)
+    return (DataType::Size(input_type) >= vixl::aarch64::kXRegSizeInBytes)
         ? vixl::aarch64::Register(vixl::aarch64::xzr)
         : vixl::aarch64::Register(vixl::aarch64::wzr);
   }
@@ -163,7 +163,7 @@
   }
 }
 
-inline vixl::aarch64::Operand OperandFrom(Location location, Primitive::Type type) {
+inline vixl::aarch64::Operand OperandFrom(Location location, DataType::Type type) {
   if (location.IsRegister()) {
     return vixl::aarch64::Operand(RegisterFrom(location, type));
   } else {
@@ -202,7 +202,7 @@
 }
 
 inline vixl::aarch64::MemOperand HeapOperandFrom(Location location, Offset offset) {
-  return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
+  return HeapOperand(RegisterFrom(location, DataType::Type::kReference), offset);
 }
 
 inline Location LocationFrom(const vixl::aarch64::Register& reg) {
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 5f39a49..bb586bf 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -150,7 +150,7 @@
     //    EQUAL lhs, null
     // where lhs cannot be null with
     //    CONSTANT false
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -162,7 +162,7 @@
     //    NOT_EQUAL lhs, null
     // where lhs cannot be null with
     //    CONSTANT true
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -174,7 +174,7 @@
     //    ABOVE dst, 0, src  // unsigned 0 > src is always false
     // with
     //    CONSTANT false
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -186,7 +186,7 @@
     //    ABOVE_OR_EQUAL dst, src, 0  // unsigned src >= 0 is always true
     // with
     //    CONSTANT true
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -198,7 +198,7 @@
     //    BELOW dst, src, 0  // unsigned src < 0 is always false
     // with
     //    CONSTANT false
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -210,7 +210,7 @@
     //    BELOW_OR_EQUAL dst, 0, src  // unsigned 0 <= src is always true
     // with
     //    CONSTANT true
-    instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 }
@@ -231,7 +231,7 @@
   HConstant* input_cst = instruction->GetConstantRight();
   if (input_cst != nullptr) {
     HInstruction* input_value = instruction->GetLeastConstantLeft();
-    if (Primitive::IsFloatingPointType(input_value->GetType()) &&
+    if (DataType::IsFloatingPointType(input_value->GetType()) &&
         ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
          (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
       // Replace code looking like
@@ -240,7 +240,7 @@
       //    CONSTANT +1 (gt bias)
       // or
       //    CONSTANT -1 (lt bias)
-      instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
+      instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
                                                        (instruction->IsGtBias() ? 1 : -1)));
       instruction->GetBlock()->RemoveInstruction(instruction);
     }
@@ -249,8 +249,8 @@
 
 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
-  Primitive::Type type = instruction->GetType();
-  if (Primitive::IsIntOrLongType(type) &&
+  DataType::Type type = instruction->GetType();
+  if (DataType::IsIntOrLongType(type) &&
       (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
     // Replace code looking like
     //    MUL dst, src, 0
@@ -282,9 +282,9 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
-  if (!Primitive::IsIntegralType(type)) {
+  if (!DataType::IsIntegralType(type)) {
     return;
   }
 
@@ -326,9 +326,9 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
-  if (!Primitive::IsIntegralType(type)) {
+  if (!DataType::IsIntegralType(type)) {
     return;
   }
 
@@ -360,7 +360,7 @@
     //    XOR dst, src, src
     // with
     //    CONSTANT 0
-    Primitive::Type type = instruction->GetType();
+    DataType::Type type = instruction->GetType();
     HBasicBlock* block = instruction->GetBlock();
     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
     block->RemoveInstruction(instruction);
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 7ef28ed..c85a2e3 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -43,7 +43,7 @@
                 const std::string& expected_after_cf,
                 const std::string& expected_after_dce,
                 const std::function<void(HGraph*)>& check_after_cf,
-                Primitive::Type return_type = Primitive::kPrimInt) {
+                DataType::Type return_type = DataType::Type::kInt32) {
     graph_ = CreateCFG(&allocator_, data, return_type);
     TestCodeOnReadyGraph(expected_before,
                          expected_after_cf,
@@ -208,7 +208,7 @@
            expected_after_cf,
            expected_after_dce,
            check_after_cf,
-           Primitive::kPrimLong);
+           DataType::Type::kInt64);
 }
 
 /**
@@ -483,7 +483,7 @@
            expected_after_cf,
            expected_after_dce,
            check_after_cf,
-           Primitive::kPrimLong);
+           DataType::Type::kInt64);
 }
 
 /**
@@ -547,7 +547,7 @@
            expected_after_cf,
            expected_after_dce,
            check_after_cf,
-           Primitive::kPrimLong);
+           DataType::Type::kInt64);
 }
 
 /**
@@ -756,7 +756,7 @@
 
   // Make various unsigned comparisons with zero against a parameter.
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt, true);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32, true);
   entry_block->AddInstruction(parameter);
   entry_block->AddInstruction(new (&allocator_) HGoto());
 
diff --git a/compiler/optimizing/data_type-inl.h b/compiler/optimizing/data_type-inl.h
new file mode 100644
index 0000000..fbc0c12
--- /dev/null
+++ b/compiler/optimizing/data_type-inl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_DATA_TYPE_INL_H_
+#define ART_COMPILER_OPTIMIZING_DATA_TYPE_INL_H_
+
+#include "data_type.h"
+#include "primitive.h"
+
+namespace art {
+
+// Note: Not declared in data_type.h to avoid pulling in "primitive.h".
+constexpr DataType::Type DataTypeFromPrimitive(Primitive::Type type) {
+  switch (type) {
+    case Primitive::kPrimNot: return DataType::Type::kReference;
+    case Primitive::kPrimBoolean: return DataType::Type::kBool;
+    case Primitive::kPrimByte: return DataType::Type::kInt8;
+    case Primitive::kPrimChar: return DataType::Type::kUint16;
+    case Primitive::kPrimShort: return DataType::Type::kInt16;
+    case Primitive::kPrimInt: return DataType::Type::kInt32;
+    case Primitive::kPrimLong: return DataType::Type::kInt64;
+    case Primitive::kPrimFloat: return DataType::Type::kFloat32;
+    case Primitive::kPrimDouble: return DataType::Type::kFloat64;
+    case Primitive::kPrimVoid: return DataType::Type::kVoid;
+  }
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
+}
+
+constexpr DataType::Type DataType::FromShorty(char type) {
+  return DataTypeFromPrimitive(Primitive::GetType(type));
+}
+
+constexpr char DataType::TypeId(DataType::Type type) {
+  // Type id for visualizer.
+  switch (type) {
+    case DataType::Type::kBool: return 'z';
+    case DataType::Type::kInt8: return 'b';
+    case DataType::Type::kUint16: return 'c';
+    case DataType::Type::kInt16: return 's';
+    case DataType::Type::kInt32: return 'i';
+    case DataType::Type::kInt64: return 'j';
+    case DataType::Type::kFloat32: return 'f';
+    case DataType::Type::kFloat64: return 'd';
+    case DataType::Type::kReference: return 'l';
+    case DataType::Type::kVoid: return 'v';
+  }
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_DATA_TYPE_INL_H_
diff --git a/compiler/optimizing/data_type.cc b/compiler/optimizing/data_type.cc
new file mode 100644
index 0000000..6890617
--- /dev/null
+++ b/compiler/optimizing/data_type.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "data_type.h"
+
+namespace art {
+
+static const char* kTypeNames[] = {
+    "Reference",
+    "Bool",
+    "Int8",
+    "Uint16",
+    "Int16",
+    "Int32",
+    "Int64",
+    "Float32",
+    "Float64",
+    "Void",
+};
+
+const char* DataType::PrettyDescriptor(Type type) {
+  static_assert(arraysize(kTypeNames) == static_cast<size_t>(Type::kLast) + 1,
+                "Missing element");
+  uint32_t uint_type = static_cast<uint32_t>(type);
+  CHECK_LE(uint_type, static_cast<uint32_t>(Type::kLast));
+  return kTypeNames[uint_type];
+}
+
+std::ostream& operator<<(std::ostream& os, DataType::Type type) {
+  uint32_t uint_type = static_cast<uint32_t>(type);
+  if (uint_type <= static_cast<uint32_t>(DataType::Type::kLast)) {
+    os << kTypeNames[uint_type];
+  } else {
+    os << "Type[" << uint_type << "]";
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/data_type.h b/compiler/optimizing/data_type.h
new file mode 100644
index 0000000..08f9263
--- /dev/null
+++ b/compiler/optimizing/data_type.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
+#define ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
+
+#include <iosfwd>
+
+#include "base/logging.h"
+#include "base/bit_utils.h"
+
+namespace art {
+
+class DataType {
+ public:
+  enum class Type : uint8_t {
+    kReference = 0,
+    kBool,
+    kInt8,
+    kUint16,
+    kInt16,
+    kInt32,
+    kInt64,
+    kFloat32,
+    kFloat64,
+    kVoid,
+    kLast = kVoid
+  };
+
+  static constexpr Type FromShorty(char type);
+  static constexpr char TypeId(DataType::Type type);
+
+  static constexpr size_t SizeShift(Type type) {
+    switch (type) {
+      case Type::kVoid:
+      case Type::kBool:
+      case Type::kInt8:
+        return 0;
+      case Type::kUint16:
+      case Type::kInt16:
+        return 1;
+      case Type::kInt32:
+      case Type::kFloat32:
+        return 2;
+      case Type::kInt64:
+      case Type::kFloat64:
+        return 3;
+      case Type::kReference:
+        return WhichPowerOf2(kObjectReferenceSize);
+      default:
+        LOG(FATAL) << "Invalid type " << static_cast<int>(type);
+        return 0;
+    }
+  }
+
+  static constexpr size_t Size(Type type) {
+    switch (type) {
+      case Type::kVoid:
+        return 0;
+      case Type::kBool:
+      case Type::kInt8:
+        return 1;
+      case Type::kUint16:
+      case Type::kInt16:
+        return 2;
+      case Type::kInt32:
+      case Type::kFloat32:
+        return 4;
+      case Type::kInt64:
+      case Type::kFloat64:
+        return 8;
+      case Type::kReference:
+        return kObjectReferenceSize;
+      default:
+        LOG(FATAL) << "Invalid type " << static_cast<int>(type);
+        return 0;
+    }
+  }
+
+  static bool IsFloatingPointType(Type type) {
+    return type == Type::kFloat32 || type == Type::kFloat64;
+  }
+
+  static bool IsIntegralType(Type type) {
+    // The Java language does not allow treating boolean as an integral type but
+    // our bit representation makes it safe.
+    switch (type) {
+      case Type::kBool:
+      case Type::kInt8:
+      case Type::kUint16:
+      case Type::kInt16:
+      case Type::kInt32:
+      case Type::kInt64:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  static bool IsIntOrLongType(Type type) {
+    return type == Type::kInt32 || type == Type::kInt64;
+  }
+
+  static bool Is64BitType(Type type) {
+    return type == Type::kInt64 || type == Type::kFloat64;
+  }
+
+  // Return the general kind of `type`, fusing integer-like types as Type::kInt.
+  static Type Kind(Type type) {
+    switch (type) {
+      case Type::kBool:
+      case Type::kInt8:
+      case Type::kInt16:
+      case Type::kUint16:
+      case Type::kInt32:
+        return Type::kInt32;
+      default:
+        return type;
+    }
+  }
+
+  static int64_t MinValueOfIntegralType(Type type) {
+    switch (type) {
+      case Type::kBool:
+        return std::numeric_limits<bool>::min();
+      case Type::kInt8:
+        return std::numeric_limits<int8_t>::min();
+      case Type::kUint16:
+        return std::numeric_limits<uint16_t>::min();
+      case Type::kInt16:
+        return std::numeric_limits<int16_t>::min();
+      case Type::kInt32:
+        return std::numeric_limits<int32_t>::min();
+      case Type::kInt64:
+        return std::numeric_limits<int64_t>::min();
+      default:
+        LOG(FATAL) << "non integral type";
+    }
+    return 0;
+  }
+
+  static int64_t MaxValueOfIntegralType(Type type) {
+    switch (type) {
+      case Type::kBool:
+        return std::numeric_limits<bool>::max();
+      case Type::kInt8:
+        return std::numeric_limits<int8_t>::max();
+      case Type::kUint16:
+        return std::numeric_limits<uint16_t>::max();
+      case Type::kInt16:
+        return std::numeric_limits<int16_t>::max();
+      case Type::kInt32:
+        return std::numeric_limits<int32_t>::max();
+      case Type::kInt64:
+        return std::numeric_limits<int64_t>::max();
+      default:
+        LOG(FATAL) << "non integral type";
+    }
+    return 0;
+  }
+
+  static const char* PrettyDescriptor(Type type);
+
+ private:
+  static constexpr size_t kObjectReferenceSize = 4u;
+};
+std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
diff --git a/compiler/optimizing/data_type_test.cc b/compiler/optimizing/data_type_test.cc
new file mode 100644
index 0000000..927291a
--- /dev/null
+++ b/compiler/optimizing/data_type_test.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "data_type-inl.h"
+
+#include "primitive.h"
+
+namespace art {
+
+template <DataType::Type data_type, Primitive::Type primitive_type>
+static void CheckConversion() {
+  static_assert(data_type == DataTypeFromPrimitive(primitive_type), "Conversion check.");
+  static_assert(DataType::Size(data_type) == Primitive::ComponentSize(primitive_type),
+                "Size check.");
+}
+
+TEST(DataType, SizeAgainstPrimitive) {
+  CheckConversion<DataType::Type::kVoid, Primitive::kPrimVoid>();
+  CheckConversion<DataType::Type::kBool, Primitive::kPrimBoolean>();
+  CheckConversion<DataType::Type::kInt8, Primitive::kPrimByte>();
+  CheckConversion<DataType::Type::kUint16, Primitive::kPrimChar>();
+  CheckConversion<DataType::Type::kInt16, Primitive::kPrimShort>();
+  CheckConversion<DataType::Type::kInt32, Primitive::kPrimInt>();
+  CheckConversion<DataType::Type::kInt64, Primitive::kPrimLong>();
+  CheckConversion<DataType::Type::kFloat32, Primitive::kPrimFloat>();
+  CheckConversion<DataType::Type::kFloat64, Primitive::kPrimDouble>();
+  CheckConversion<DataType::Type::kReference, Primitive::kPrimNot>();
+}
+
+TEST(DataType, Names) {
+#define CHECK_NAME(type) EXPECT_STREQ(#type, DataType::PrettyDescriptor(DataType::Type::k##type))
+  CHECK_NAME(Void);
+  CHECK_NAME(Bool);
+  CHECK_NAME(Int8);
+  CHECK_NAME(Uint16);
+  CHECK_NAME(Int16);
+  CHECK_NAME(Int32);
+  CHECK_NAME(Int64);
+  CHECK_NAME(Float32);
+  CHECK_NAME(Float64);
+  CHECK_NAME(Reference);
+#undef CHECK_NAME
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 787296d..9b094e9 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -118,7 +118,7 @@
 }
 
 static HConstant* Evaluate(HCondition* condition, HInstruction* left, HInstruction* right) {
-  if (left == right && !Primitive::IsFloatingPointType(left->GetType())) {
+  if (left == right && !DataType::IsFloatingPointType(left->GetType())) {
     return condition->GetBlock()->GetGraph()->GetIntConstant(
         HasEquality(condition->GetCondition()) ? 1 : 0);
   }
diff --git a/compiler/optimizing/emit_swap_mips_test.cc b/compiler/optimizing/emit_swap_mips_test.cc
index fa3c4df..0e9c81d 100644
--- a/compiler/optimizing/emit_swap_mips_test.cc
+++ b/compiler/optimizing/emit_swap_mips_test.cc
@@ -118,12 +118,12 @@
   moves_->AddMove(
       Location::RegisterLocation(4),
       Location::RegisterLocation(5),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   moves_->AddMove(
       Location::RegisterLocation(5),
       Location::RegisterLocation(4),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   const char* expected =
       "or $t8, $a1, $zero\n"
@@ -136,12 +136,12 @@
   moves_->AddMove(
       Location::RegisterPairLocation(4, 5),
       Location::RegisterPairLocation(6, 7),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   moves_->AddMove(
       Location::RegisterPairLocation(6, 7),
       Location::RegisterPairLocation(4, 5),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   const char* expected =
       "or $t8, $a2, $zero\n"
@@ -157,12 +157,12 @@
   moves_->AddMove(
       Location::FpuRegisterLocation(4),
       Location::FpuRegisterLocation(2),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   moves_->AddMove(
       Location::FpuRegisterLocation(2),
       Location::FpuRegisterLocation(4),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   const char* expected =
       "mov.s $f6, $f2\n"
@@ -175,12 +175,12 @@
   moves_->AddMove(
       Location::FpuRegisterLocation(4),
       Location::FpuRegisterLocation(2),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   moves_->AddMove(
       Location::FpuRegisterLocation(2),
       Location::FpuRegisterLocation(4),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   const char* expected =
       "mov.d $f6, $f2\n"
@@ -193,12 +193,12 @@
   moves_->AddMove(
       Location::RegisterLocation(4),
       Location::FpuRegisterLocation(2),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   moves_->AddMove(
       Location::FpuRegisterLocation(2),
       Location::RegisterLocation(4),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   const char* expected =
       "or $t8, $a0, $zero\n"
@@ -211,12 +211,12 @@
   moves_->AddMove(
       Location::RegisterPairLocation(4, 5),
       Location::FpuRegisterLocation(4),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   moves_->AddMove(
       Location::FpuRegisterLocation(4),
       Location::RegisterPairLocation(4, 5),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   const char* expected =
       "mfc1 $t8, $f4\n"
@@ -232,12 +232,12 @@
   moves_->AddMove(
       Location::StackSlot(52),
       Location::StackSlot(48),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   moves_->AddMove(
       Location::StackSlot(48),
       Location::StackSlot(52),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   const char* expected =
       "addiu $sp, $sp, -4\n"
@@ -255,12 +255,12 @@
   moves_->AddMove(
       Location::DoubleStackSlot(56),
       Location::DoubleStackSlot(48),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   moves_->AddMove(
       Location::DoubleStackSlot(48),
       Location::DoubleStackSlot(56),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   const char* expected =
       "addiu $sp, $sp, -4\n"
@@ -282,12 +282,12 @@
   moves_->AddMove(
       Location::RegisterLocation(4),
       Location::StackSlot(48),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   moves_->AddMove(
       Location::StackSlot(48),
       Location::RegisterLocation(4),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   const char* expected =
       "or $t8, $a0, $zero\n"
@@ -300,12 +300,12 @@
   moves_->AddMove(
       Location::RegisterPairLocation(4, 5),
       Location::DoubleStackSlot(32),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   moves_->AddMove(
       Location::DoubleStackSlot(32),
       Location::RegisterPairLocation(4, 5),
-      Primitive::kPrimLong,
+      DataType::Type::kInt64,
       nullptr);
   const char* expected =
       "or $t8, $a0, $zero\n"
@@ -321,12 +321,12 @@
   moves_->AddMove(
       Location::FpuRegisterLocation(4),
       Location::StackSlot(48),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   moves_->AddMove(
       Location::StackSlot(48),
       Location::FpuRegisterLocation(4),
-      Primitive::kPrimFloat,
+      DataType::Type::kFloat32,
       nullptr);
   const char* expected =
       "mov.s $f6, $f4\n"
@@ -339,12 +339,12 @@
   moves_->AddMove(
       Location::FpuRegisterLocation(4),
       Location::DoubleStackSlot(48),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   moves_->AddMove(
       Location::DoubleStackSlot(48),
       Location::FpuRegisterLocation(4),
-      Primitive::kPrimDouble,
+      DataType::Type::kFloat64,
       nullptr);
   const char* expected =
       "mov.d $f6, $f4\n"
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 327e11f..1c7d1a0 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -456,7 +456,7 @@
   }
 
   // Ensure that reference type instructions have reference type info.
-  if (instruction->GetType() == Primitive::kPrimNot) {
+  if (instruction->GetType() == DataType::Type::kReference) {
     if (!instruction->GetReferenceTypeInfo().IsValid()) {
       AddError(StringPrintf("Reference type instruction %s:%d does not have "
                             "valid reference type information.",
@@ -674,7 +674,7 @@
 static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
   return insn1->IsConstant()
       && insn2->IsConstant()
-      && Primitive::Is64BitType(insn1->GetType()) == Primitive::Is64BitType(insn2->GetType());
+      && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
 }
 
 static bool IsConstantEquivalent(const HInstruction* insn1,
@@ -721,20 +721,20 @@
   // Ensure that the inputs have the same primitive kind as the phi.
   for (size_t i = 0; i < input_records.size(); ++i) {
     HInstruction* input = input_records[i].GetInstruction();
-    if (Primitive::PrimitiveKind(input->GetType()) != Primitive::PrimitiveKind(phi->GetType())) {
+    if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
         AddError(StringPrintf(
             "Input %d at index %zu of phi %d from block %d does not have the "
             "same kind as the phi: %s versus %s",
             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
-            Primitive::PrettyDescriptor(input->GetType()),
-            Primitive::PrettyDescriptor(phi->GetType())));
+            DataType::PrettyDescriptor(input->GetType()),
+            DataType::PrettyDescriptor(phi->GetType())));
     }
   }
   if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
     AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
                           phi->GetId(),
                           phi->GetBlock()->GetBlockId(),
-                          Primitive::PrettyDescriptor(phi->GetType())));
+                          DataType::PrettyDescriptor(phi->GetType())));
   }
 
   if (phi->IsCatchPhi()) {
@@ -820,7 +820,7 @@
                                 phi->GetId(),
                                 phi->GetRegNumber(),
                                 type_str.str().c_str()));
-        } else if (phi->GetType() == Primitive::kPrimNot) {
+        } else if (phi->GetType() == DataType::Type::kReference) {
           std::stringstream type_str;
           type_str << other_phi->GetType();
           AddError(StringPrintf(
@@ -859,7 +859,7 @@
           static_cast<int>(input_index),
           value));
     }
-  } else if (Primitive::PrimitiveKind(input->GetType()) != Primitive::kPrimInt) {
+  } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
     // TODO: We need a data-flow analysis to determine if an input like Phi,
     //       Select or a binary operation is actually Boolean. Allow for now.
     AddError(StringPrintf(
@@ -867,7 +867,7 @@
         instruction->DebugName(),
         instruction->GetId(),
         static_cast<int>(input_index),
-        Primitive::PrettyDescriptor(input->GetType())));
+        DataType::PrettyDescriptor(input->GetType())));
   }
 }
 
@@ -904,27 +904,27 @@
 
 void GraphChecker::VisitCondition(HCondition* op) {
   VisitInstruction(op);
-  if (op->GetType() != Primitive::kPrimBoolean) {
+  if (op->GetType() != DataType::Type::kBool) {
     AddError(StringPrintf(
         "Condition %s %d has a non-Boolean result type: %s.",
         op->DebugName(), op->GetId(),
-        Primitive::PrettyDescriptor(op->GetType())));
+        DataType::PrettyDescriptor(op->GetType())));
   }
   HInstruction* lhs = op->InputAt(0);
   HInstruction* rhs = op->InputAt(1);
-  if (Primitive::PrimitiveKind(lhs->GetType()) != Primitive::PrimitiveKind(rhs->GetType())) {
+  if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
     AddError(StringPrintf(
         "Condition %s %d has inputs of different kinds: %s, and %s.",
         op->DebugName(), op->GetId(),
-        Primitive::PrettyDescriptor(lhs->GetType()),
-        Primitive::PrettyDescriptor(rhs->GetType())));
+        DataType::PrettyDescriptor(lhs->GetType()),
+        DataType::PrettyDescriptor(rhs->GetType())));
   }
   if (!op->IsEqual() && !op->IsNotEqual()) {
-    if ((lhs->GetType() == Primitive::kPrimNot)) {
+    if ((lhs->GetType() == DataType::Type::kReference)) {
       AddError(StringPrintf(
           "Condition %s %d uses an object as left-hand side input.",
           op->DebugName(), op->GetId()));
-    } else if (rhs->GetType() == Primitive::kPrimNot) {
+    } else if (rhs->GetType() == DataType::Type::kReference) {
       AddError(StringPrintf(
           "Condition %s %d uses an object as right-hand side input.",
           op->DebugName(), op->GetId()));
@@ -934,72 +934,72 @@
 
 void GraphChecker::VisitNeg(HNeg* instruction) {
   VisitInstruction(instruction);
-  Primitive::Type input_type = instruction->InputAt(0)->GetType();
-  Primitive::Type result_type = instruction->GetType();
-  if (result_type != Primitive::PrimitiveKind(input_type)) {
+  DataType::Type input_type = instruction->InputAt(0)->GetType();
+  DataType::Type result_type = instruction->GetType();
+  if (result_type != DataType::Kind(input_type)) {
     AddError(StringPrintf("Binary operation %s %d has a result type different "
                           "from its input kind: %s vs %s.",
                           instruction->DebugName(), instruction->GetId(),
-                          Primitive::PrettyDescriptor(result_type),
-                          Primitive::PrettyDescriptor(input_type)));
+                          DataType::PrettyDescriptor(result_type),
+                          DataType::PrettyDescriptor(input_type)));
   }
 }
 
 void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
   VisitInstruction(op);
-  Primitive::Type lhs_type = op->InputAt(0)->GetType();
-  Primitive::Type rhs_type = op->InputAt(1)->GetType();
-  Primitive::Type result_type = op->GetType();
+  DataType::Type lhs_type = op->InputAt(0)->GetType();
+  DataType::Type rhs_type = op->InputAt(1)->GetType();
+  DataType::Type result_type = op->GetType();
 
   // Type consistency between inputs.
   if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
-    if (Primitive::PrimitiveKind(rhs_type) != Primitive::kPrimInt) {
+    if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
       AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
                             "%s of type %s.",
                             op->DebugName(), op->GetId(),
                             op->InputAt(1)->DebugName(),
-                            Primitive::PrettyDescriptor(rhs_type)));
+                            DataType::PrettyDescriptor(rhs_type)));
     }
   } else {
-    if (Primitive::PrimitiveKind(lhs_type) != Primitive::PrimitiveKind(rhs_type)) {
+    if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
       AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
                             op->DebugName(), op->GetId(),
-                            Primitive::PrettyDescriptor(lhs_type),
-                            Primitive::PrettyDescriptor(rhs_type)));
+                            DataType::PrettyDescriptor(lhs_type),
+                            DataType::PrettyDescriptor(rhs_type)));
     }
   }
 
   // Type consistency between result and input(s).
   if (op->IsCompare()) {
-    if (result_type != Primitive::kPrimInt) {
+    if (result_type != DataType::Type::kInt32) {
       AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
                             op->GetId(),
-                            Primitive::PrettyDescriptor(result_type)));
+                            DataType::PrettyDescriptor(result_type)));
     }
   } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
     // Only check the first input (value), as the second one (distance)
     // must invariably be of kind `int`.
-    if (result_type != Primitive::PrimitiveKind(lhs_type)) {
+    if (result_type != DataType::Kind(lhs_type)) {
       AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
                             "from its left-hand side (value) input kind: %s vs %s.",
                             op->DebugName(), op->GetId(),
-                            Primitive::PrettyDescriptor(result_type),
-                            Primitive::PrettyDescriptor(lhs_type)));
+                            DataType::PrettyDescriptor(result_type),
+                            DataType::PrettyDescriptor(lhs_type)));
     }
   } else {
-    if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(lhs_type)) {
+    if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
       AddError(StringPrintf("Binary operation %s %d has a result kind different "
                             "from its left-hand side input kind: %s vs %s.",
                             op->DebugName(), op->GetId(),
-                            Primitive::PrettyDescriptor(result_type),
-                            Primitive::PrettyDescriptor(lhs_type)));
+                            DataType::PrettyDescriptor(result_type),
+                            DataType::PrettyDescriptor(lhs_type)));
     }
-    if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(rhs_type)) {
+    if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
       AddError(StringPrintf("Binary operation %s %d has a result kind different "
                             "from its right-hand side input kind: %s vs %s.",
                             op->DebugName(), op->GetId(),
-                            Primitive::PrettyDescriptor(result_type),
-                            Primitive::PrettyDescriptor(rhs_type)));
+                            DataType::PrettyDescriptor(result_type),
+                            DataType::PrettyDescriptor(rhs_type)));
     }
   }
 }
@@ -1028,16 +1028,16 @@
 
 void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
   VisitInstruction(instruction);
-  Primitive::Type result_type = instruction->GetResultType();
-  Primitive::Type input_type = instruction->GetInputType();
+  DataType::Type result_type = instruction->GetResultType();
+  DataType::Type input_type = instruction->GetInputType();
   // Invariant: We should never generate a conversion to a Boolean value.
-  if (result_type == Primitive::kPrimBoolean) {
+  if (result_type == DataType::Type::kBool) {
     AddError(StringPrintf(
         "%s %d converts to a %s (from a %s).",
         instruction->DebugName(),
         instruction->GetId(),
-        Primitive::PrettyDescriptor(result_type),
-        Primitive::PrettyDescriptor(input_type)));
+        DataType::PrettyDescriptor(result_type),
+        DataType::PrettyDescriptor(input_type)));
   }
 }
 
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 3035e46..194f063 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -24,6 +24,7 @@
 #include "bounds_check_elimination.h"
 #include "builder.h"
 #include "code_generator.h"
+#include "data_type-inl.h"
 #include "dead_code_elimination.h"
 #include "disassembler.h"
 #include "inliner.h"
@@ -243,25 +244,6 @@
     }
   }
 
-  char GetTypeId(Primitive::Type type) {
-    // Note that Primitive::Descriptor would not work for us
-    // because it does not handle reference types (that is kPrimNot).
-    switch (type) {
-      case Primitive::kPrimBoolean: return 'z';
-      case Primitive::kPrimByte: return 'b';
-      case Primitive::kPrimChar: return 'c';
-      case Primitive::kPrimShort: return 's';
-      case Primitive::kPrimInt: return 'i';
-      case Primitive::kPrimLong: return 'j';
-      case Primitive::kPrimFloat: return 'f';
-      case Primitive::kPrimDouble: return 'd';
-      case Primitive::kPrimNot: return 'l';
-      case Primitive::kPrimVoid: return 'v';
-    }
-    LOG(FATAL) << "Unreachable";
-    return 'v';
-  }
-
   void PrintPredecessors(HBasicBlock* block) {
     AddIndent();
     output_ << "predecessors";
@@ -583,7 +565,7 @@
     if (!inputs.empty()) {
       StringList input_list;
       for (const HInstruction* input : inputs) {
-        input_list.NewEntryStream() << GetTypeId(input->GetType()) << input->GetId();
+        input_list.NewEntryStream() << DataType::TypeId(input->GetType()) << input->GetId();
       }
       StartAttributeStream() << input_list;
     }
@@ -597,7 +579,7 @@
         for (size_t i = 0, e = environment->Size(); i < e; ++i) {
           HInstruction* insn = environment->GetInstructionAt(i);
           if (insn != nullptr) {
-            vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
+            vregs.NewEntryStream() << DataType::TypeId(insn->GetType()) << insn->GetId();
           } else {
             vregs.NewEntryStream() << "_";
           }
@@ -654,7 +636,7 @@
 
     if ((IsPass(HGraphBuilder::kBuilderPassName)
         || IsPass(HInliner::kInlinerPassName))
-        && (instruction->GetType() == Primitive::kPrimNot)) {
+        && (instruction->GetType() == DataType::Type::kReference)) {
       ReferenceTypeInfo info = instruction->IsLoadClass()
         ? instruction->AsLoadClass()->GetLoadedClassRTI()
         : instruction->GetReferenceTypeInfo();
@@ -698,7 +680,7 @@
       size_t num_uses = instruction->GetUses().SizeSlow();
       AddIndent();
       output_ << bci << " " << num_uses << " "
-              << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
+              << DataType::TypeId(instruction->GetType()) << instruction->GetId() << " ";
       PrintInstruction(instruction);
       output_ << " " << kEndInstructionMarker << "\n";
     }
@@ -821,7 +803,7 @@
     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       AddIndent();
       HInstruction* instruction = it.Current();
-      output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
+      output_ << instruction->GetId() << " " << DataType::TypeId(instruction->GetType())
               << instruction->GetId() << "[ ";
       for (const HInstruction* input : instruction->GetInputs()) {
         output_ << input->GetId() << " ";
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index e1ed7f6..ac0dbee 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -37,7 +37,7 @@
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
                                                              dex::TypeIndex(0),
                                                              0,
-                                                             Primitive::kPrimNot);
+                                                             DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -46,7 +46,7 @@
 
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimNot,
+                                                           DataType::Type::kReference,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -55,7 +55,7 @@
                                                            0));
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimNot,
+                                                           DataType::Type::kReference,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -65,7 +65,7 @@
   HInstruction* to_remove = block->GetLastInstruction();
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimNot,
+                                                           DataType::Type::kReference,
                                                            MemberOffset(43),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -77,7 +77,7 @@
   block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
                                                            parameter,
                                                            nullptr,
-                                                           Primitive::kPrimNot,
+                                                           DataType::Type::kReference,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -86,7 +86,7 @@
                                                            0));
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimNot,
+                                                           DataType::Type::kReference,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -121,7 +121,7 @@
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
                                                              dex::TypeIndex(0),
                                                              0,
-                                                             Primitive::kPrimNot);
+                                                             DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -129,7 +129,7 @@
   entry->AddSuccessor(block);
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimBoolean,
+                                                           DataType::Type::kBool,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -152,7 +152,7 @@
 
   then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                           nullptr,
-                                                          Primitive::kPrimBoolean,
+                                                          DataType::Type::kBool,
                                                           MemberOffset(42),
                                                           false,
                                                           kUnknownFieldIndex,
@@ -162,7 +162,7 @@
   then->AddInstruction(new (&allocator) HGoto());
   else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimBoolean,
+                                                           DataType::Type::kBool,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -172,7 +172,7 @@
   else_->AddInstruction(new (&allocator) HGoto());
   join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                           nullptr,
-                                                          Primitive::kPrimBoolean,
+                                                          DataType::Type::kBool,
                                                           MemberOffset(42),
                                                           false,
                                                           kUnknownFieldIndex,
@@ -204,7 +204,7 @@
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
                                                              dex::TypeIndex(0),
                                                              0,
-                                                             Primitive::kPrimNot);
+                                                             DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -212,7 +212,7 @@
   entry->AddSuccessor(block);
   block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                            nullptr,
-                                                           Primitive::kPrimBoolean,
+                                                           DataType::Type::kBool,
                                                            MemberOffset(42),
                                                            false,
                                                            kUnknownFieldIndex,
@@ -235,7 +235,7 @@
 
   loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                                  nullptr,
-                                                                 Primitive::kPrimBoolean,
+                                                                 DataType::Type::kBool,
                                                                  MemberOffset(42),
                                                                  false,
                                                                  kUnknownFieldIndex,
@@ -250,7 +250,7 @@
   loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
                                                                parameter,
                                                                nullptr,
-                                                               Primitive::kPrimBoolean,
+                                                               DataType::Type::kBool,
                                                                MemberOffset(42),
                                                                false,
                                                                kUnknownFieldIndex,
@@ -260,7 +260,7 @@
   HInstruction* field_set = loop_body->GetLastInstruction();
   loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                                nullptr,
-                                                               Primitive::kPrimBoolean,
+                                                               DataType::Type::kBool,
                                                                MemberOffset(42),
                                                                false,
                                                                kUnknownFieldIndex,
@@ -272,7 +272,7 @@
 
   exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
                                                           nullptr,
-                                                          Primitive::kPrimBoolean,
+                                                          DataType::Type::kBool,
                                                           MemberOffset(42),
                                                           false,
                                                           kUnknownFieldIndex,
@@ -351,7 +351,7 @@
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
                                                              dex::TypeIndex(0),
                                                              0,
-                                                             Primitive::kPrimBoolean);
+                                                             DataType::Type::kBool);
   entry->AddInstruction(parameter);
   entry->AddInstruction(new (&allocator) HGoto());
   outer_loop_header->AddInstruction(new (&allocator) HSuspendCheck());
@@ -374,7 +374,7 @@
     entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
                                                              parameter,
                                                              nullptr,
-                                                             Primitive::kPrimNot,
+                                                             DataType::Type::kReference,
                                                              MemberOffset(42),
                                                              false,
                                                              kUnknownFieldIndex,
@@ -399,7 +399,7 @@
         new (&allocator) HInstanceFieldSet(parameter,
                                            parameter,
                                            nullptr,
-                                           Primitive::kPrimNot,
+                                           DataType::Type::kReference,
                                            MemberOffset(42),
                                            false,
                                            kUnknownFieldIndex,
@@ -425,7 +425,7 @@
         new (&allocator) HInstanceFieldSet(parameter,
                                            parameter,
                                            nullptr,
-                                           Primitive::kPrimNot,
+                                           DataType::Type::kReference,
                                            MemberOffset(42),
                                            false,
                                            kUnknownFieldIndex,
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index 84b20f6..fe286ab 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -56,17 +56,17 @@
 /**
  * Returns true if the from/to types denote a narrowing, integral conversion (precision loss).
  */
-static bool IsNarrowingIntegralConversion(Primitive::Type from, Primitive::Type to) {
+static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to) {
   switch (from) {
-    case Primitive::kPrimLong:
-      return to == Primitive::kPrimByte || to == Primitive::kPrimShort
-          || to == Primitive::kPrimChar || to == Primitive::kPrimInt;
-    case Primitive::kPrimInt:
-      return to == Primitive::kPrimByte || to == Primitive::kPrimShort
-          || to == Primitive::kPrimChar;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      return to == Primitive::kPrimByte;
+    case DataType::Type::kInt64:
+      return to == DataType::Type::kInt8 || to == DataType::Type::kInt16
+          || to == DataType::Type::kUint16 || to == DataType::Type::kInt32;
+    case DataType::Type::kInt32:
+      return to == DataType::Type::kInt8 || to == DataType::Type::kInt16
+          || to == DataType::Type::kUint16;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      return to == DataType::Type::kInt8;
     default:
       return false;
   }
@@ -75,13 +75,13 @@
 /**
  * Returns result of implicit widening type conversion done in HIR.
  */
-static Primitive::Type ImplicitConversion(Primitive::Type type) {
+static DataType::Type ImplicitConversion(DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimBoolean:
-      return Primitive::kPrimInt;
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt8:
+    case DataType::Type::kBool:
+      return DataType::Type::kInt32;
     default:
       return type;
   }
@@ -100,7 +100,7 @@
       scc_(graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
       cycle_(std::less<HInstruction*>(),
              graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
-      type_(Primitive::kPrimVoid),
+      type_(DataType::Type::kVoid),
       induction_(std::less<HLoopInformation*>(),
                  graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
       cycles_(std::less<HPhi*>(),
@@ -520,8 +520,8 @@
 
 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferConversion(
     InductionInfo* a,
-    Primitive::Type from,
-    Primitive::Type to) {
+    DataType::Type from,
+    DataType::Type to) {
   if (a != nullptr) {
     // Allow narrowing conversion on linear induction in certain cases:
     // induction is already at narrow type, or can be made narrower.
@@ -723,15 +723,15 @@
     HLoopInformation* loop,
     HInstruction* entry_phi,
     HTypeConversion* conversion) {
-  Primitive::Type from = conversion->GetInputType();
-  Primitive::Type to = conversion->GetResultType();
+  DataType::Type from = conversion->GetInputType();
+  DataType::Type to = conversion->GetResultType();
   // A narrowing conversion is allowed as *last* operation of the cycle of a linear induction
   // with an initial value that fits the type, provided that the narrowest encountered type is
   // recorded with the induction to account for the precision loss. The narrower induction does
   // *not* transfer to any wider operations, however, since these may yield out-of-type values
   if (entry_phi->InputCount() == 2 && conversion == entry_phi->InputAt(1)) {
-    int64_t min = Primitive::MinValueOfIntegralType(to);
-    int64_t max = Primitive::MaxValueOfIntegralType(to);
+    int64_t min = DataType::MinValueOfIntegralType(to);
+    int64_t max = DataType::MaxValueOfIntegralType(to);
     int64_t value = 0;
     InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
     if (IsNarrowingIntegralConversion(from, to) &&
@@ -761,7 +761,7 @@
       HCondition* condition = if_expr->AsCondition();
       InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
       InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
-      Primitive::Type type = ImplicitConversion(condition->InputAt(0)->GetType());
+      DataType::Type type = ImplicitConversion(condition->InputAt(0)->GetType());
       // Determine if the loop control uses a known sequence on an if-exit (X outside) or on
       // an if-iterate (X inside), expressed as if-iterate when passed into VisitCondition().
       if (a == nullptr || b == nullptr) {
@@ -778,7 +778,7 @@
 void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
                                            InductionInfo* a,
                                            InductionInfo* b,
-                                           Primitive::Type type,
+                                           DataType::Type type,
                                            IfCondition cmp) {
   if (a->induction_class == kInvariant && b->induction_class == kLinear) {
     // Swap condition if induction is at right-hand-side (e.g. U > i is same as i < U).
@@ -809,7 +809,7 @@
     }
     // Only accept integral condition. A mismatch between the type of condition and the induction
     // is only allowed if the, necessarily narrower, induction range fits the narrower control.
-    if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
+    if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
       return;  // not integral
     } else if (type != a->type &&
                !FitsNarrowerControl(lower_expr, upper_expr, stride_value, a->type, cmp)) {
@@ -830,7 +830,7 @@
                                            InductionInfo* upper_expr,
                                            InductionInfo* stride_expr,
                                            int64_t stride_value,
-                                           Primitive::Type type,
+                                           DataType::Type type,
                                            IfCondition cmp) {
   // Any loop of the general form:
   //
@@ -931,10 +931,10 @@
 
 bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr,
                                      int64_t stride_value,
-                                     Primitive::Type type,
+                                     DataType::Type type,
                                      IfCondition cmp) {
-  int64_t min = Primitive::MinValueOfIntegralType(type);
-  int64_t max = Primitive::MaxValueOfIntegralType(type);
+  int64_t min = DataType::MinValueOfIntegralType(type);
+  int64_t max = DataType::MaxValueOfIntegralType(type);
   // Some rules under which it is certain at compile-time that the loop is finite.
   int64_t value;
   switch (cmp) {
@@ -957,10 +957,10 @@
 bool HInductionVarAnalysis::FitsNarrowerControl(InductionInfo* lower_expr,
                                                 InductionInfo* upper_expr,
                                                 int64_t stride_value,
-                                                Primitive::Type type,
+                                                DataType::Type type,
                                                 IfCondition cmp) {
-  int64_t min = Primitive::MinValueOfIntegralType(type);
-  int64_t max = Primitive::MaxValueOfIntegralType(type);
+  int64_t min = DataType::MinValueOfIntegralType(type);
+  int64_t max = DataType::MaxValueOfIntegralType(type);
   // Inclusive test need one extra.
   if (stride_value != 1 && stride_value != -1) {
     return false;  // non-unit stride
@@ -1008,13 +1008,13 @@
 }
 
 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
-                                                                            Primitive::Type type) {
+                                                                            DataType::Type type) {
   HInstruction* constant;
   switch (type) {
-    case Primitive::kPrimDouble: constant = graph_->GetDoubleConstant(value); break;
-    case Primitive::kPrimFloat:  constant = graph_->GetFloatConstant(value);  break;
-    case Primitive::kPrimLong:   constant = graph_->GetLongConstant(value);   break;
-    default:                     constant = graph_->GetIntConstant(value);    break;
+    case DataType::Type::kFloat64: constant = graph_->GetDoubleConstant(value); break;
+    case DataType::Type::kFloat32: constant = graph_->GetFloatConstant(value);  break;
+    case DataType::Type::kInt64:   constant = graph_->GetLongConstant(value);   break;
+    default:                       constant = graph_->GetIntConstant(value);    break;
   }
   return CreateInvariantFetch(constant);
 }
@@ -1100,11 +1100,11 @@
   InductionInfo* b = LookupInfo(loop, instruction->InputAt(1));
   int64_t value = -1;
   if (IsExact(b, &value)) {
-    Primitive::Type type = instruction->InputAt(0)->GetType();
-    if (type == Primitive::kPrimInt && 0 <= value && value < 31) {
+    DataType::Type type = instruction->InputAt(0)->GetType();
+    if (type == DataType::Type::kInt32 && 0 <= value && value < 31) {
       return graph_->GetIntConstant(1 << value);
     }
-    if (type == Primitive::kPrimLong && 0 <= value && value < 63) {
+    if (type == DataType::Type::kInt64 && 0 <= value && value < 63) {
       return graph_->GetLongConstant(1L << value);
     }
   }
@@ -1142,11 +1142,11 @@
 bool HInductionVarAnalysis::IsNarrowingLinear(InductionInfo* info) {
   return info != nullptr &&
       info->induction_class == kLinear &&
-      (info->type == Primitive::kPrimByte ||
-       info->type == Primitive::kPrimShort ||
-       info->type == Primitive::kPrimChar ||
-       (info->type == Primitive::kPrimInt && (info->op_a->type == Primitive::kPrimLong ||
-                                              info->op_b->type == Primitive::kPrimLong)));
+      (info->type == DataType::Type::kInt8 ||
+       info->type == DataType::Type::kInt16 ||
+       info->type == DataType::Type::kUint16 ||
+       (info->type == DataType::Type::kInt32 && (info->op_a->type == DataType::Type::kInt64 ||
+                                                 info->op_b->type == DataType::Type::kInt64)));
 }
 
 bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
@@ -1207,12 +1207,12 @@
         DCHECK(info->operation == kNop);
         return "(" + InductionToString(info->op_a) + " * i + " +
                      InductionToString(info->op_b) + "):" +
-                     Primitive::PrettyDescriptor(info->type);
+                     DataType::PrettyDescriptor(info->type);
       } else if (info->induction_class == kPolynomial) {
         DCHECK(info->operation == kNop);
         return "poly(sum_lt(" + InductionToString(info->op_a) + ") + " +
                                 InductionToString(info->op_b) + "):" +
-                                Primitive::PrettyDescriptor(info->type);
+                                DataType::PrettyDescriptor(info->type);
       } else if (info->induction_class == kGeometric) {
         DCHECK(info->operation == kMul || info->operation == kDiv);
         DCHECK(info->fetch != nullptr);
@@ -1220,17 +1220,17 @@
                         FetchToString(info->fetch) +
                         (info->operation == kMul ? " ^ i + " : " ^ -i + ") +
                         InductionToString(info->op_b) + "):" +
-                        Primitive::PrettyDescriptor(info->type);
+                        DataType::PrettyDescriptor(info->type);
       } else if (info->induction_class == kWrapAround) {
         DCHECK(info->operation == kNop);
         return "wrap(" + InductionToString(info->op_a) + ", " +
                          InductionToString(info->op_b) + "):" +
-                         Primitive::PrettyDescriptor(info->type);
+                         DataType::PrettyDescriptor(info->type);
       } else if (info->induction_class == kPeriodic) {
         DCHECK(info->operation == kNop);
         return "periodic(" + InductionToString(info->op_a) + ", " +
                              InductionToString(info->op_b) + "):" +
-                             Primitive::PrettyDescriptor(info->type);
+                             DataType::PrettyDescriptor(info->type);
       }
     }
   }
diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h
index 39b39cd..421b3ab 100644
--- a/compiler/optimizing/induction_var_analysis.h
+++ b/compiler/optimizing/induction_var_analysis.h
@@ -103,7 +103,7 @@
                   InductionInfo* a,
                   InductionInfo* b,
                   HInstruction* f,
-                  Primitive::Type t)
+                  DataType::Type t)
         : induction_class(ic),
           operation(op),
           op_a(a),
@@ -115,7 +115,7 @@
     InductionInfo* op_a;
     InductionInfo* op_b;
     HInstruction* fetch;
-    Primitive::Type type;  // precision of operation
+    DataType::Type type;  // precision of operation
   };
 
   bool IsVisitedNode(HInstruction* instruction) const {
@@ -136,7 +136,7 @@
   InductionInfo* CreateTripCount(InductionOp op,
                                  InductionInfo* a,
                                  InductionInfo* b,
-                                 Primitive::Type type) {
+                                 DataType::Type type) {
     DCHECK(a != nullptr && b != nullptr);
     return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr, type);
   }
@@ -146,7 +146,7 @@
                                  InductionInfo* a,
                                  InductionInfo* b,
                                  HInstruction* f,
-                                 Primitive::Type type) {
+                                 DataType::Type type) {
     DCHECK(a != nullptr && b != nullptr);
     return new (graph_->GetArena()) InductionInfo(ic, op, a, b, f, type);
   }
@@ -167,7 +167,7 @@
   InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
   InductionInfo* TransferNeg(InductionInfo* a);
   InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
-  InductionInfo* TransferConversion(InductionInfo* a, Primitive::Type from, Primitive::Type to);
+  InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
 
   // Solvers.
   InductionInfo* SolvePhi(HInstruction* phi, size_t input_index, size_t adjust_input_size);
@@ -200,30 +200,30 @@
   void VisitCondition(HLoopInformation* loop,
                       InductionInfo* a,
                       InductionInfo* b,
-                      Primitive::Type type,
+                      DataType::Type type,
                       IfCondition cmp);
   void VisitTripCount(HLoopInformation* loop,
                       InductionInfo* lower_expr,
                       InductionInfo* upper_expr,
                       InductionInfo* stride,
                       int64_t stride_value,
-                      Primitive::Type type,
+                      DataType::Type type,
                       IfCondition cmp);
   bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
   bool IsFinite(InductionInfo* upper_expr,
                 int64_t stride_value,
-                Primitive::Type type,
+                DataType::Type type,
                 IfCondition cmp);
   bool FitsNarrowerControl(InductionInfo* lower_expr,
                            InductionInfo* upper_expr,
                            int64_t stride_value,
-                           Primitive::Type type,
+                           DataType::Type type,
                            IfCondition cmp);
 
   // Assign and lookup.
   void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
   InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
-  InductionInfo* CreateConstant(int64_t value, Primitive::Type type);
+  InductionInfo* CreateConstant(int64_t value, DataType::Type type);
   InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
   HInstruction* GetShiftConstant(HLoopInformation* loop,
                                  HInstruction* instruction,
@@ -250,7 +250,7 @@
   ArenaSafeMap<HInstruction*, NodeInfo> map_;
   ArenaVector<HInstruction*> scc_;
   ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
-  Primitive::Type type_;
+  DataType::Type type_;
 
   /**
    * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 9516ccb..53c8044 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -94,7 +94,7 @@
 
     // Provide entry and exit instructions.
     parameter_ = new (&allocator_) HParameterValue(
-        graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
+        graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true);
     entry_->AddInstruction(parameter_);
     constant0_ = graph_->GetIntConstant(0);
     constant1_ = graph_->GetIntConstant(1);
@@ -108,13 +108,13 @@
 
     // Provide loop instructions.
     for (int d = 0; d < n; d++) {
-      basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, Primitive::kPrimInt);
+      basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, DataType::Type::kInt32);
       loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
       loop_header_[d]->AddPhi(basic_[d]);
       HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
       loop_header_[d]->AddInstruction(compare);
       loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
-      increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[d], constant1_);
+      increment_[d] = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[d], constant1_);
       loop_body_[d]->AddInstruction(increment_[d]);
       loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
 
@@ -141,7 +141,7 @@
     *ifT = ifTrue;
     *ifF = ifFalse;
 
-    HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, Primitive::kPrimInt);
+    HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, DataType::Type::kInt32);
     loop_body_[d]->AddPhi(select_phi);
     return select_phi;
   }
@@ -154,7 +154,7 @@
 
   // Inserts a phi to loop header at depth d and returns it.
   HPhi* InsertLoopPhi(int vreg, int d) {
-    HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, Primitive::kPrimInt);
+    HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, DataType::Type::kInt32);
     loop_header_[d]->AddPhi(phi);
     return phi;
   }
@@ -165,7 +165,7 @@
     // ArraySet is given a float value in order to avoid SsaBuilder typing
     // it from the array's non-existent reference type info.
     return InsertInstruction(new (&allocator_) HArraySet(
-        parameter_, subscript, float_constant0_, Primitive::kPrimFloat, 0), d);
+        parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d);
   }
 
   // Returns induction information of instruction in loop at depth d.
@@ -265,8 +265,8 @@
   HInstruction* store = InsertArrayStore(basic_[0], 0);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
-  EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
 
   // Offset matters!
   EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
@@ -286,22 +286,22 @@
   // }
   BuildLoopNest(1);
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0);
   HInstruction* shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
   HInstruction* neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, basic_[0]), 0);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("((1) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("((100) * i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
-  EXPECT_STREQ("(( - (1)) * i + (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
+  EXPECT_STREQ("((1) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
+  EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("((100) * i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
+  EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl, 0).c_str());
+  EXPECT_STREQ("(( - (1)) * i + (0)):Int32", GetInductionInfo(neg, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindChainInduction) {
@@ -318,19 +318,19 @@
   k_header->AddInput(constant0_);
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* store1 = InsertArrayStore(add, 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, add, constant1_), 0);
   HInstruction* store2 = InsertArrayStore(sub, 0);
   k_header->AddInput(sub);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("(((100) - (1)) * i + (0)):PrimInt",
+  EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32",
                GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("(((100) - (1)) * i + (100)):PrimInt",
+  EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32",
                GetInductionInfo(store1->InputAt(1), 0).c_str());
-  EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):PrimInt",
+  EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32",
                GetInductionInfo(store2->InputAt(1), 0).c_str());
 }
 
@@ -351,11 +351,11 @@
   HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
 
   // True-branch.
-  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
+  HInstruction* inc1 = new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_);
   ifTrue->AddInstruction(inc1);
   k_body->AddInput(inc1);
   // False-branch.
-  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
+  HInstruction* inc2 = new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_);
   ifFalse->AddInstruction(inc2);
   k_body->AddInput(inc2);
   // Merge over a phi.
@@ -363,8 +363,8 @@
   k_header->AddInput(k_body);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
 
   // Both increments get same induction.
   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
@@ -384,18 +384,18 @@
   HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
 
   // True-branch.
-  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
+  HInstruction* inc1 = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
   ifTrue->AddInstruction(inc1);
   k->AddInput(inc1);
   // False-branch.
-  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
+  HInstruction* inc2 = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
   ifFalse->AddInstruction(inc2);
   k->AddInput(inc2);
   // Merge over a phi.
   HInstruction* store = InsertArrayStore(k, 0);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
 
   // Both increments get same induction.
   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
@@ -412,17 +412,17 @@
   BuildLoopNest(1);
 
   HInstruction* add1 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], basic_[0]), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0);
   HInstruction* add2 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant7_, basic_[0]), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0);
   HInstruction* add3 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, add1, add2), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, add1, add2), 0);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(basic_[0], 0).c_str());
-  EXPECT_STREQ("(((1) + (1)) * i + (0)):PrimInt", GetInductionInfo(add1, 0).c_str());
-  EXPECT_STREQ("((1) * i + (7)):PrimInt", GetInductionInfo(add2, 0).c_str());
-  EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):PrimInt", GetInductionInfo(add3, 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("(((1) + (1)) * i + (0)):Int32", GetInductionInfo(add1, 0).c_str());
+  EXPECT_STREQ("((1) * i + (7)):Int32", GetInductionInfo(add2, 0).c_str());
+  EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):Int32", GetInductionInfo(add3, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
@@ -438,18 +438,18 @@
   k_header->AddInput(constant1_);
 
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, basic_[0], constant2_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0);
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, mul), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, constant100_, mul), 0);
   HInstruction* pol = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, add, k_header), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, add, k_header), 0);
   k_header->AddInput(pol);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle and the base linear induction are classified.
-  EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):PrimInt) + (1)):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32",
                GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("((2) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
+  EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
 }
 
@@ -469,32 +469,32 @@
   k_header->AddInput(constant1_);
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* pol = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
   k_header->AddInput(pol);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle and derived are classified.
-  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (1)):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32",
                GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) + (100))):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32",
                GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32",
                GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
+  EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32",
                GetInductionInfo(neg, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):PrimInt) + (2)):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32",
                GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):PrimInt) + (4)):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32",
                GetInductionInfo(shl, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
 }
@@ -512,21 +512,21 @@
   k_header->AddInput(constant7_);
 
   HInstruction* add1 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, k_header), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, k_header), 0);
   HInstruction* add2 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, add1, k_header), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, add1, k_header), 0);
   HInstruction* add3 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
   k_header->AddInput(add3);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle and added-derived are classified.
-  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (7)):PrimInt",
+  EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32",
                GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):PrimInt) + ((7) + (7))):PrimInt",
+  EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32",
                GetInductionInfo(add1, 0).c_str());
   EXPECT_STREQ(
-      "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):PrimInt) + (((7) + (7)) + (7))):PrimInt",
+      "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32",
       GetInductionInfo(add2, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
 }
@@ -542,12 +542,12 @@
   k_header->AddInput(constant1_);
 
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
   k_header->AddInput(mul);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("geo((1) * 100 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("geo((100) * 100 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
+  EXPECT_STREQ("geo((1) * 100 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("geo((100) * 100 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
@@ -567,31 +567,31 @@
   k_header->AddInput(constant1_);
 
   HInstruction* add1 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* shl1 = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* add2 = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, shl1, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, shl1, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, shl1, constant1_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, shl1, constant1_), 0);
   HInstruction* neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, shl1, constant2_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, shl1, constant2_), 0);
   HInstruction* shl2 = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, shl1, constant2_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, shl1, constant2_), 0);
   k_header->AddInput(shl1);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("geo((1) * 2 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("geo((1) * 2 ^ i + (1)):PrimInt", GetInductionInfo(add1, 0).c_str());
-  EXPECT_STREQ("geo((2) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl1, 0).c_str());
-  EXPECT_STREQ("geo((2) * 2 ^ i + (100)):PrimInt", GetInductionInfo(add2, 0).c_str());
-  EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):PrimInt",
+  EXPECT_STREQ("geo((1) * 2 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("geo((1) * 2 ^ i + (1)):Int32", GetInductionInfo(add1, 0).c_str());
+  EXPECT_STREQ("geo((2) * 2 ^ i + (0)):Int32", GetInductionInfo(shl1, 0).c_str());
+  EXPECT_STREQ("geo((2) * 2 ^ i + (100)):Int32", GetInductionInfo(add2, 0).c_str());
+  EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):Int32",
                GetInductionInfo(neg, 0).c_str());
-  EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
+  EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
+  EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
@@ -610,24 +610,24 @@
   k_header->AddInput(constant1_);
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* div = InsertInstruction(
-      new (&allocator_) HDiv(Primitive::kPrimInt, k_header, constant100_, kNoDexPc), 0);
+      new (&allocator_) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0);
   k_header->AddInput(div);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle and direct additive derived are classified.
-  EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):Int32", GetInductionInfo(add, 0).c_str());
+  EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
@@ -645,12 +645,12 @@
   k_header->AddInput(constant100_);
 
   HInstruction* shr = InsertInstruction(
-      new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
   k_header->AddInput(shr);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle is classified.
-  EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
 }
 
@@ -665,7 +665,7 @@
   k_header->AddInput(constantm1_);
 
   HInstruction* shr = InsertInstruction(
-      new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
   k_header->AddInput(shr);
   PerformInductionVarAnalysis();
 
@@ -689,27 +689,32 @@
   k_header->AddInput(constant100_);
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
   HInstruction* rem = InsertInstruction(
-      new (&allocator_) HRem(Primitive::kPrimInt, k_header, constant7_, kNoDexPc), 0);
+      new (&allocator_) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0);
   k_header->AddInput(rem);
   PerformInductionVarAnalysis();
 
   // Note, only the phi in the cycle and derived are classified.
-  EXPECT_STREQ("wrap((100), ((100) % (7))):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):PrimInt", GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):PrimInt", GetInductionInfo(neg, 0).c_str());
-  EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):PrimInt", GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):PrimInt", GetInductionInfo(shl, 0).c_str());
+  EXPECT_STREQ("wrap((100), ((100) % (7))):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):Int32",
+               GetInductionInfo(add, 0).c_str());
+  EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):Int32",
+               GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):Int32",
+               GetInductionInfo(neg, 0).c_str());
+  EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):Int32",
+               GetInductionInfo(mul, 0).c_str());
+  EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):Int32",
+               GetInductionInfo(shl, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
 }
 
@@ -726,15 +731,15 @@
 
   HInstruction* store = InsertArrayStore(k_header, 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
   k_header->AddInput(sub);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
                GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
                GetInductionInfo(store->InputAt(1), 0).c_str());
-  EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
@@ -755,11 +760,11 @@
   HInstruction* store = InsertArrayStore(k_header, 0);
   k_header->AddInput(t);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0);
   t->AddInput(sub);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):PrimInt):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32",
                GetInductionInfo(store->InputAt(1), 0).c_str());
 }
 
@@ -780,34 +785,34 @@
   k_header->AddInput(constant0_);
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
   HInstruction* shl1 = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* neg1 = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, k_header), 0);
   HInstruction* shl2 = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
   HInstruction* neg2 = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, shl2), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, shl2), 0);
   k_header->AddInput(shl2);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("wrap((100), ((2) * i + (100)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32",
                GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32",
                GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32",
                GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32",
                GetInductionInfo(shl1, 0).c_str());
-  EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):PrimInt):PrimInt",
+  EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32",
                GetInductionInfo(neg1, 0).c_str());
-  EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
-  EXPECT_STREQ("(( - (2)) * i + (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
+  EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
+  EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
@@ -834,8 +839,8 @@
   t->AddInput(k_header);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (100)):PrimInt", GetInductionInfo(store1->InputAt(1), 0).c_str());
-  EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
+  EXPECT_STREQ("periodic((0), (100)):Int32", GetInductionInfo(store1->InputAt(1), 0).c_str());
+  EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
@@ -851,12 +856,12 @@
 
   HInstruction* store = InsertArrayStore(k_header, 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
   k_header->AddInput(sub);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(sub, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
@@ -872,12 +877,12 @@
 
   HInstruction* store = InsertArrayStore(k_header, 0);
   HInstruction* x = InsertInstruction(
-      new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HXor(DataType::Type::kInt32, k_header, constant1_), 0);
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
@@ -891,12 +896,12 @@
   k_header->AddInput(constant1_);
 
   HInstruction* x = InsertInstruction(
-      new (&allocator_) HXor(Primitive::kPrimInt, constant1_, k_header), 0);
+      new (&allocator_) HXor(DataType::Type::kInt32, constant1_, k_header), 0);
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((1), ((1) ^ (1))):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic(((1) ^ (1)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((1), ((1) ^ (1))):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic(((1) ^ (1)), (1)):Int32", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
@@ -910,12 +915,12 @@
   k_header->AddInput(constant1_);
 
   HInstruction* x = InsertInstruction(
-      new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant100_), 0);
+      new (&allocator_) HXor(DataType::Type::kInt32, k_header, constant100_), 0);
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((1), ((1) ^ (100))):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic(((1) ^ (100)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((1), ((1) ^ (100))):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic(((1) ^ (100)), (1)):Int32", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
@@ -932,8 +937,8 @@
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
@@ -950,8 +955,8 @@
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
@@ -968,8 +973,8 @@
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
@@ -986,8 +991,8 @@
   k_header->AddInput(x);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
@@ -1007,30 +1012,30 @@
   k_header->AddInput(constant0_);
 
   HInstruction* neg1 = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, k_header), 0);
   HInstruction* idiom = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, idiom, constant100_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, idiom, constant100_), 0);
   HInstruction* sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, idiom, constant100_), 0);
+      new (&allocator_) HSub(DataType::Type::kInt32, idiom, constant100_), 0);
   HInstruction* mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, idiom, constant100_), 0);
+      new (&allocator_) HMul(DataType::Type::kInt32, idiom, constant100_), 0);
   HInstruction* shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, idiom, constant1_), 0);
+      new (&allocator_) HShl(DataType::Type::kInt32, idiom, constant1_), 0);
   HInstruction* neg2 = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, idiom), 0);
+      new (&allocator_) HNeg(DataType::Type::kInt32, idiom), 0);
   k_header->AddInput(idiom);
   PerformInductionVarAnalysis();
 
-  EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(k_header, 0).c_str());
-  EXPECT_STREQ("periodic((0), ( - (1))):PrimInt", GetInductionInfo(neg1, 0).c_str());
-  EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(idiom, 0).c_str());
-  EXPECT_STREQ("periodic(((1) + (100)), (100)):PrimInt", GetInductionInfo(add, 0).c_str());
-  EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):PrimInt", GetInductionInfo(sub, 0).c_str());
-  EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
-  EXPECT_STREQ("periodic((2), (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
-  EXPECT_STREQ("periodic(( - (1)), (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
+  EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("periodic((0), ( - (1))):Int32", GetInductionInfo(neg1, 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(idiom, 0).c_str());
+  EXPECT_STREQ("periodic(((1) + (100)), (100)):Int32", GetInductionInfo(add, 0).c_str());
+  EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):Int32", GetInductionInfo(sub, 0).c_str());
+  EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(mul, 0).c_str());
+  EXPECT_STREQ("periodic((2), (0)):Int32", GetInductionInfo(shl, 0).c_str());
+  EXPECT_STREQ("periodic(( - (1)), (0)):Int32", GetInductionInfo(neg2, 0).c_str());
 }
 
 TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
@@ -1052,7 +1057,7 @@
   }
 
   HInstruction* inc = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k_header[9]), 9);
+      new (&allocator_) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9);
   HInstruction* store = InsertArrayStore(inc, 9);
 
   for (int d = 0; d < 10; d++) {
@@ -1063,7 +1068,7 @@
 
   // Avoid exact phi number, since that depends on the SSA building phase.
   std::regex r("\\(\\(1\\) \\* i \\+ "
-               "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):PrimInt");
+               "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32");
 
   for (int d = 0; d < 10; d++) {
     if (d == 9) {
@@ -1071,7 +1076,7 @@
     } else {
       EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
     }
-    EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[d], d).c_str());
+    EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str());
     // Trip-count.
     EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
   }
@@ -1086,15 +1091,15 @@
   // }
   BuildLoopNest(1);
   HInstruction* conv = InsertInstruction(
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], kNoDexPc), 0);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
   HInstruction* store1 = InsertArrayStore(conv, 0);
   HInstruction* store2 = InsertArrayStore(basic_[0], 0);
   PerformInductionVarAnalysis();
 
   // Regular int induction (i) is transferred over conversion into byte induction (k).
-  EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
-  EXPECT_STREQ("((1) * i + (0)):PrimInt",  GetInductionInfo(store2->InputAt(1), 0).c_str());
-  EXPECT_STREQ("((1) * i + (1)):PrimInt",  GetInductionInfo(increment_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int32",  GetInductionInfo(store2->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (1)):Int32",  GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
   EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
@@ -1117,17 +1122,17 @@
   // }
   BuildLoopNest(1);
   HInstruction* conv = InsertInstruction(
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], kNoDexPc), 0);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
   HInstruction* store1 = InsertArrayStore(conv, 0);
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
   HInstruction* store2 = InsertArrayStore(add, 0);
 
   PerformInductionVarAnalysis();
 
   // Byte induction (k) is detected, but it does not transfer over the addition,
   // since this may yield out-of-type values.
-  EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
 
   // Narrowing detected.
@@ -1147,15 +1152,15 @@
   k_header->AddInput(graph_->GetIntConstant(-128));
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* conv = InsertInstruction(
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, add, kNoDexPc), 0);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
   k_header->AddInput(conv);
   PerformInductionVarAnalysis();
 
   // Byte induction (k) is detected, but it does not transfer over the addition,
   // since this may yield out-of-type values.
-  EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
 
   // Narrowing detected.
@@ -1175,9 +1180,9 @@
   k_header->AddInput(graph_->GetIntConstant(-129));
 
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
   HInstruction* conv = InsertInstruction(
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, add, kNoDexPc), 0);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
   k_header->AddInput(conv);
   PerformInductionVarAnalysis();
 
@@ -1197,9 +1202,9 @@
   k_header->AddInput(constant0_);
 
   HInstruction* conv = InsertInstruction(
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, k_header, kNoDexPc), 0);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0);
   HInstruction* add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
+      new (&allocator_) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
   k_header->AddInput(add);
   PerformInductionVarAnalysis();
 
@@ -1216,13 +1221,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
@@ -1242,13 +1247,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
@@ -1268,13 +1273,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (-32768)):PrimShort", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
@@ -1294,13 +1299,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (-32768)):PrimShort", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
@@ -1319,13 +1324,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (0)):PrimChar", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
@@ -1344,13 +1349,13 @@
   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
   HInstruction* conv =
-      new (&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], kNoDexPc);
+      new (&allocator_) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   basic_[0]->ReplaceInput(conv, 1);
   PerformInductionVarAnalysis();
 
   // Recorded at the phi, but not transferred to increment.
-  EXPECT_STREQ("((1) * i + (0)):PrimChar", GetInductionInfo(basic_[0], 0).c_str());
+  EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
 
   // Narrowing detected.
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 191d3d1..92b584c 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -157,15 +157,15 @@
 }
 
 /** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
-static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, Primitive::Type type) {
+static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, DataType::Type type) {
   switch (type) {
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimByte: {
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt8: {
       // Constants within range only.
       // TODO: maybe some room for improvement, like allowing widening conversions
-      int32_t min = Primitive::MinValueOfIntegralType(type);
-      int32_t max = Primitive::MaxValueOfIntegralType(type);
+      int32_t min = DataType::MinValueOfIntegralType(type);
+      int32_t max = DataType::MaxValueOfIntegralType(type);
       return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
           ? v
           : InductionVarRange::Value();
@@ -216,10 +216,10 @@
   // bounds check elimination, will have truncated higher precision induction
   // at their use point already).
   switch (info->type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt8:
       break;
     default:
       return false;
@@ -689,8 +689,8 @@
   } else if (instruction->IsTypeConversion()) {
     // Since analysis is 32-bit (or narrower), chase beyond widening along the path.
     // For example, this discovers the length in: for (long i = 0; i < a.length; i++);
-    if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
-        instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
+    if (instruction->AsTypeConversion()->GetInputType() == DataType::Type::kInt32 &&
+        instruction->AsTypeConversion()->GetResultType() == DataType::Type::kInt64) {
       return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
     }
   }
@@ -1051,9 +1051,9 @@
     HInstruction* c = nullptr;
     if (GenerateCode(info->op_b, nullptr, graph, block, graph ? &c : nullptr, false, false)) {
       if (graph != nullptr) {
-        Primitive::Type type = info->type;
+        DataType::Type type = info->type;
         int64_t sum = a * ((m * (m - 1)) / 2) + b * m;
-        if (type != Primitive::kPrimLong) {
+        if (type != DataType::Type::kInt64) {
           sum = static_cast<int32_t>(sum);  // okay to truncate
         }
         *result =
@@ -1081,16 +1081,16 @@
     if (GenerateCode(info->op_a, nullptr, graph, block, &opa, false, false) &&
         GenerateCode(info->op_b, nullptr, graph, block, &opb, false, false)) {
       if (graph != nullptr) {
-        Primitive::Type type = info->type;
+        DataType::Type type = info->type;
         // Compute f ^ m for known maximum index value m.
         bool overflow = false;
         int64_t fpow = IntPow(f, m, &overflow);
         if (info->operation == HInductionVarAnalysis::kDiv) {
           // For division, any overflow truncates to zero.
-          if (overflow || (type != Primitive::kPrimLong && !CanLongValueFitIntoInt(fpow))) {
+          if (overflow || (type != DataType::Type::kInt64 && !CanLongValueFitIntoInt(fpow))) {
             fpow = 0;
           }
-        } else if (type != Primitive::kPrimLong) {
+        } else if (type != DataType::Type::kInt64) {
           // For multiplication, okay to truncate to required precision.
           DCHECK(info->operation == HInductionVarAnalysis::kMul);
           fpow = static_cast<int32_t>(fpow);
@@ -1161,7 +1161,7 @@
   }
   // Don't rely on FP arithmetic to be precise, unless the full period
   // consist of pre-computed expressions only.
-  if (info->type == Primitive::kPrimFloat || info->type == Primitive::kPrimDouble) {
+  if (info->type == DataType::Type::kFloat32 || info->type == DataType::Type::kFloat64) {
     if (!all_invariants) {
       return false;
     }
@@ -1187,7 +1187,7 @@
       GenerateCode(trip->op_a, nullptr, graph, block, graph ? &t : nullptr, false, false)) {
     // During actual code generation (graph != nullptr), generate is_even ? x : y.
     if (graph != nullptr) {
-      Primitive::Type type = trip->type;
+      DataType::Type type = trip->type;
       HInstruction* msk =
           Insert(block, new (graph->GetArena()) HAnd(type, t, graph->GetConstant(type, 1)));
       HInstruction* is_even =
@@ -1224,7 +1224,7 @@
       return true;
     }
     // Handle current operation.
-    Primitive::Type type = info->type;
+    DataType::Type type = info->type;
     HInstruction* opa = nullptr;
     HInstruction* opb = nullptr;
     switch (info->induction_class) {
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 9437014..1c84269 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -71,12 +71,12 @@
     x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                            dex::TypeIndex(0),
                                            0,
-                                           Primitive::kPrimInt);
+                                           DataType::Type::kInt32);
     entry_block_->AddInstruction(x_);
     y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                            dex::TypeIndex(0),
                                            0,
-                                           Primitive::kPrimInt);
+                                           DataType::Type::kInt32);
     entry_block_->AddInstruction(y_);
     // Set arbitrary range analysis hint while testing private methods.
     SetHint(x_);
@@ -101,7 +101,7 @@
     return_block->AddSuccessor(exit_block_);
     // Instructions.
     loop_preheader_->AddInstruction(new (&allocator_) HGoto());
-    HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+    HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
     loop_header_->AddPhi(phi);
     phi->AddInput(graph_->GetIntConstant(lower));  // i = l
     if (stride > 0) {
@@ -111,7 +111,8 @@
     }
     loop_header_->AddInstruction(condition_);
     loop_header_->AddInstruction(new (&allocator_) HIf(condition_));
-    increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, phi, graph_->GetIntConstant(stride));
+    increment_ =
+        new (&allocator_) HAdd(DataType::Type::kInt32, phi, graph_->GetIntConstant(stride));
     loop_body_->AddInstruction(increment_);  // i += s
     phi->AddInput(increment_);
     loop_body_->AddInstruction(new (&allocator_) HGoto());
@@ -173,7 +174,7 @@
     return iva_->CreateTripCount(op,
                                  CreateConst(tc),
                                  CreateInvariant('<', CreateConst(0), CreateConst(tc)),
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a linear a * i + b induction. */
@@ -183,7 +184,7 @@
                                  CreateConst(a),
                                  CreateConst(b),
                                  nullptr,
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a polynomial sum(a * i + b) + c induction. */
@@ -193,7 +194,7 @@
                                  CreateLinear(a, b),
                                  CreateConst(c),
                                  nullptr,
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a geometric a * f^i + b induction. */
@@ -204,7 +205,7 @@
                                  CreateConst(a),
                                  CreateConst(b),
                                  graph_->GetIntConstant(f),
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a range [lo, hi] using a periodic induction. */
@@ -214,7 +215,7 @@
                                  CreateConst(lo),
                                  CreateConst(hi),
                                  nullptr,
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a wrap-around induction consisting of a constant, followed by info. */
@@ -226,7 +227,7 @@
                                  CreateConst(initial),
                                  info,
                                  nullptr,
-                                 Primitive::kPrimInt);
+                                 DataType::Type::kInt32);
   }
 
   /** Constructs a wrap-around induction consisting of a constant, followed by a range. */
@@ -725,13 +726,13 @@
 
 TEST_F(InductionVarRangeTest, AddOrSubAndConstant) {
   HInstruction* add = new (&allocator_)
-      HAdd(Primitive::kPrimInt, x_, graph_->GetIntConstant(-1));
+      HAdd(DataType::Type::kInt32, x_, graph_->GetIntConstant(-1));
   HInstruction* alt = new (&allocator_)
-      HAdd(Primitive::kPrimInt, graph_->GetIntConstant(-1), x_);
+      HAdd(DataType::Type::kInt32, graph_->GetIntConstant(-1), x_);
   HInstruction* sub = new (&allocator_)
-      HSub(Primitive::kPrimInt, x_, graph_->GetIntConstant(1));
+      HSub(DataType::Type::kInt32, x_, graph_->GetIntConstant(1));
   HInstruction* rev = new (&allocator_)
-      HSub(Primitive::kPrimInt, graph_->GetIntConstant(1), x_);
+      HSub(DataType::Type::kInt32, graph_->GetIntConstant(1), x_);
   entry_block_->AddInstruction(add);
   entry_block_->AddInstruction(alt);
   entry_block_->AddInstruction(sub);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 793e781..90e3d2a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -21,6 +21,7 @@
 #include "builder.h"
 #include "class_linker.h"
 #include "constant_folding.h"
+#include "data_type-inl.h"
 #include "dead_code_elimination.h"
 #include "dex/inline_method_analyser.h"
 #include "dex/verification_results.h"
@@ -707,7 +708,7 @@
   HInstanceFieldGet* result = new (graph_->GetArena()) HInstanceFieldGet(
       receiver,
       field,
-      Primitive::kPrimNot,
+      DataType::Type::kReference,
       field->GetOffset(),
       field->IsVolatile(),
       field->GetDexFieldIndex(),
@@ -1143,9 +1144,9 @@
   HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
       class_linker, receiver, invoke_instruction->GetDexPc());
 
-  Primitive::Type type = Is64BitInstructionSet(graph_->GetInstructionSet())
-      ? Primitive::kPrimLong
-      : Primitive::kPrimInt;
+  DataType::Type type = Is64BitInstructionSet(graph_->GetInstructionSet())
+      ? DataType::Type::kInt64
+      : DataType::Type::kInt32;
   HClassTableGet* class_table_get = new (graph_->GetArena()) HClassTableGet(
       receiver_class,
       type,
@@ -1155,7 +1156,7 @@
       invoke_instruction->GetDexPc());
 
   HConstant* constant;
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     constant = graph_->GetLongConstant(
         reinterpret_cast<intptr_t>(actual_method), invoke_instruction->GetDexPc());
   } else {
@@ -1253,7 +1254,7 @@
       }
       invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
       new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
-      if (invoke_instruction->GetType() == Primitive::kPrimNot) {
+      if (invoke_instruction->GetType() == DataType::Type::kReference) {
         new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
       }
       return_replacement = new_invoke;
@@ -1403,7 +1404,7 @@
   size_t input_index = 0;
   for (size_t i = 0; i < arg_vreg_index; ++i, ++input_index) {
     DCHECK_LT(input_index, invoke_instruction->GetNumberOfArguments());
-    if (Primitive::Is64BitType(invoke_instruction->InputAt(input_index)->GetType())) {
+    if (DataType::Is64BitType(invoke_instruction->InputAt(input_index)->GetType())) {
       ++i;
       DCHECK_NE(i, arg_vreg_index);
     }
@@ -1423,7 +1424,7 @@
 
   switch (inline_method.opcode) {
     case kInlineOpNop:
-      DCHECK_EQ(invoke_instruction->GetType(), Primitive::kPrimVoid);
+      DCHECK_EQ(invoke_instruction->GetType(), DataType::Type::kVoid);
       *return_replacement = nullptr;
       break;
     case kInlineOpReturnArg:
@@ -1541,7 +1542,7 @@
   HInstanceFieldGet* iget = new (graph_->GetArena()) HInstanceFieldGet(
       obj,
       resolved_field,
-      resolved_field->GetTypeAsPrimitiveType(),
+      DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
       resolved_field->GetOffset(),
       resolved_field->IsVolatile(),
       field_index,
@@ -1550,7 +1551,7 @@
       // Read barrier generates a runtime call in slow path and we need a valid
       // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
       /* dex_pc */ 0);
-  if (iget->GetType() == Primitive::kPrimNot) {
+  if (iget->GetType() == DataType::Type::kReference) {
     // Use the same dex_cache that we used for field lookup as the hint_dex_cache.
     Handle<mirror::DexCache> dex_cache = handles_->NewHandle(referrer->GetDexCache());
     ReferenceTypePropagation rtp(graph_,
@@ -1582,7 +1583,7 @@
       obj,
       value,
       resolved_field,
-      resolved_field->GetTypeAsPrimitiveType(),
+      DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
       resolved_field->GetOffset(),
       resolved_field->IsVolatile(),
       field_index,
@@ -1667,8 +1668,6 @@
   HGraphBuilder builder(callee_graph,
                         &dex_compilation_unit,
                         &outer_compilation_unit_,
-                        resolved_method->GetDexFile(),
-                        *code_item,
                         compiler_driver_,
                         codegen_,
                         inline_stats_,
@@ -1711,7 +1710,7 @@
       } else if (argument->IsDoubleConstant()) {
         current->ReplaceWith(
             callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue()));
-      } else if (argument->GetType() == Primitive::kPrimNot) {
+      } else if (argument->GetType() == DataType::Type::kReference) {
         if (!resolved_method->IsStatic() && parameter_index == 0 && receiver_type.IsValid()) {
           run_rtp = true;
           current->SetReferenceTypeInfo(receiver_type);
@@ -1975,7 +1974,7 @@
        param_idx < e;
        ++param_idx, ++input_idx) {
     HInstruction* input = invoke_instruction->InputAt(input_idx);
-    if (input->GetType() == Primitive::kPrimNot) {
+    if (input->GetType() == DataType::Type::kReference) {
       ObjPtr<mirror::Class> param_cls = resolved_method->LookupResolvedClassFromTypeIndex(
           param_list->GetTypeItem(param_idx).type_idx_);
       if (IsReferenceTypeRefinement(GetClassRTI(param_cls),
@@ -1993,7 +1992,7 @@
                                       HInstruction* return_replacement) {
   // Check the integrity of reference types and run another type propagation if needed.
   if (return_replacement != nullptr) {
-    if (return_replacement->GetType() == Primitive::kPrimNot) {
+    if (return_replacement->GetType() == DataType::Type::kReference) {
       // Test if the return type is a refinement of the declared return type.
       if (IsReferenceTypeRefinement(invoke_instruction->GetReferenceTypeInfo(),
                                     /* declared_can_be_null */ true,
@@ -2019,7 +2018,7 @@
 void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
                                         HInstruction* return_replacement) {
   if (return_replacement != nullptr) {
-    if (return_replacement->GetType() == Primitive::kPrimNot) {
+    if (return_replacement->GetType() == DataType::Type::kReference) {
       if (!return_replacement->GetReferenceTypeInfo().IsValid()) {
         // Make sure that we have a valid type for the return. We may get an invalid one when
         // we inline invokes with multiple branches and create a Phi for the result.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 6532ec1..e832b10 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -19,6 +19,7 @@
 #include "art_method-inl.h"
 #include "bytecode_utils.h"
 #include "class_linker.h"
+#include "data_type-inl.h"
 #include "dex_instruction-inl.h"
 #include "driver/compiler_options.h"
 #include "imtable-inl.h"
@@ -221,7 +222,7 @@
 }
 
 HInstruction* HInstructionBuilder::LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc) {
-  HInstruction* ref = LoadLocal(register_index, Primitive::kPrimNot);
+  HInstruction* ref = LoadLocal(register_index, DataType::Type::kReference);
   if (!ref->CanBeNull()) {
     return ref;
   }
@@ -388,15 +389,15 @@
   }
 }
 
-HInstruction* HInstructionBuilder::LoadLocal(uint32_t reg_number, Primitive::Type type) const {
+HInstruction* HInstructionBuilder::LoadLocal(uint32_t reg_number, DataType::Type type) const {
   HInstruction* value = (*current_locals_)[reg_number];
   DCHECK(value != nullptr);
 
   // If the operation requests a specific type, we make sure its input is of that type.
   if (type != value->GetType()) {
-    if (Primitive::IsFloatingPointType(type)) {
+    if (DataType::IsFloatingPointType(type)) {
       value = ssa_builder_->GetFloatOrDoubleEquivalent(value, type);
-    } else if (type == Primitive::kPrimNot) {
+    } else if (type == DataType::Type::kReference) {
       value = ssa_builder_->GetReferenceTypeEquivalent(value);
     }
     DCHECK(value != nullptr);
@@ -406,8 +407,8 @@
 }
 
 void HInstructionBuilder::UpdateLocal(uint32_t reg_number, HInstruction* stored_value) {
-  Primitive::Type stored_type = stored_value->GetType();
-  DCHECK_NE(stored_type, Primitive::kPrimVoid);
+  DataType::Type stored_type = stored_value->GetType();
+  DCHECK_NE(stored_type, DataType::Type::kVoid);
 
   // Storing into vreg `reg_number` may implicitly invalidate the surrounding
   // registers. Consider the following cases:
@@ -420,7 +421,7 @@
 
   if (reg_number != 0) {
     HInstruction* local_low = (*current_locals_)[reg_number - 1];
-    if (local_low != nullptr && Primitive::Is64BitType(local_low->GetType())) {
+    if (local_low != nullptr && DataType::Is64BitType(local_low->GetType())) {
       // The vreg we are storing into was previously the high vreg of a pair.
       // We need to invalidate its low vreg.
       DCHECK((*current_locals_)[reg_number] == nullptr);
@@ -429,7 +430,7 @@
   }
 
   (*current_locals_)[reg_number] = stored_value;
-  if (Primitive::Is64BitType(stored_type)) {
+  if (DataType::Is64BitType(stored_type)) {
     // We are storing a pair. Invalidate the instruction in the high vreg.
     (*current_locals_)[reg_number + 1] = nullptr;
   }
@@ -455,7 +456,7 @@
     HParameterValue* parameter = new (arena_) HParameterValue(*dex_file_,
                                                               referrer_method_id.class_idx_,
                                                               parameter_index++,
-                                                              Primitive::kPrimNot,
+                                                              DataType::Type::kReference,
                                                               /* is_this */ true);
     AppendInstruction(parameter);
     UpdateLocal(locals_index++, parameter);
@@ -472,14 +473,14 @@
         *dex_file_,
         arg_types->GetTypeItem(shorty_pos - 1).type_idx_,
         parameter_index++,
-        Primitive::GetType(shorty[shorty_pos]),
+        DataType::FromShorty(shorty[shorty_pos]),
         /* is_this */ false);
     ++shorty_pos;
     AppendInstruction(parameter);
     // Store the parameter value in the local that the dex code will use
     // to reference that parameter.
     UpdateLocal(locals_index++, parameter);
-    if (Primitive::Is64BitType(parameter->GetType())) {
+    if (DataType::Is64BitType(parameter->GetType())) {
       i++;
       locals_index++;
       parameter_index++;
@@ -489,8 +490,8 @@
 
 template<typename T>
 void HInstructionBuilder::If_22t(const Instruction& instruction, uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
-  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* first = LoadLocal(instruction.VRegA(), DataType::Type::kInt32);
+  HInstruction* second = LoadLocal(instruction.VRegB(), DataType::Type::kInt32);
   T* comparison = new (arena_) T(first, second, dex_pc);
   AppendInstruction(comparison);
   AppendInstruction(new (arena_) HIf(comparison, dex_pc));
@@ -499,7 +500,7 @@
 
 template<typename T>
 void HInstructionBuilder::If_21t(const Instruction& instruction, uint32_t dex_pc) {
-  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+  HInstruction* value = LoadLocal(instruction.VRegA(), DataType::Type::kInt32);
   T* comparison = new (arena_) T(value, graph_->GetIntConstant(0, dex_pc), dex_pc);
   AppendInstruction(comparison);
   AppendInstruction(new (arena_) HIf(comparison, dex_pc));
@@ -508,7 +509,7 @@
 
 template<typename T>
 void HInstructionBuilder::Unop_12x(const Instruction& instruction,
-                                   Primitive::Type type,
+                                   DataType::Type type,
                                    uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
   AppendInstruction(new (arena_) T(type, first, dex_pc));
@@ -516,8 +517,8 @@
 }
 
 void HInstructionBuilder::Conversion_12x(const Instruction& instruction,
-                                         Primitive::Type input_type,
-                                         Primitive::Type result_type,
+                                         DataType::Type input_type,
+                                         DataType::Type result_type,
                                          uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
   AppendInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc));
@@ -526,7 +527,7 @@
 
 template<typename T>
 void HInstructionBuilder::Binop_23x(const Instruction& instruction,
-                                    Primitive::Type type,
+                                    DataType::Type type,
                                     uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
   HInstruction* second = LoadLocal(instruction.VRegC(), type);
@@ -536,16 +537,16 @@
 
 template<typename T>
 void HInstructionBuilder::Binop_23x_shift(const Instruction& instruction,
-                                          Primitive::Type type,
+                                          DataType::Type type,
                                           uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt);
+  HInstruction* second = LoadLocal(instruction.VRegC(), DataType::Type::kInt32);
   AppendInstruction(new (arena_) T(type, first, second, dex_pc));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
 void HInstructionBuilder::Binop_23x_cmp(const Instruction& instruction,
-                                        Primitive::Type type,
+                                        DataType::Type type,
                                         ComparisonBias bias,
                                         uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
@@ -556,17 +557,17 @@
 
 template<typename T>
 void HInstructionBuilder::Binop_12x_shift(const Instruction& instruction,
-                                          Primitive::Type type,
+                                          DataType::Type type,
                                           uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegA(), type);
-  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* second = LoadLocal(instruction.VRegB(), DataType::Type::kInt32);
   AppendInstruction(new (arena_) T(type, first, second, dex_pc));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
 template<typename T>
 void HInstructionBuilder::Binop_12x(const Instruction& instruction,
-                                    Primitive::Type type,
+                                    DataType::Type type,
                                     uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegA(), type);
   HInstruction* second = LoadLocal(instruction.VRegB(), type);
@@ -576,23 +577,23 @@
 
 template<typename T>
 void HInstructionBuilder::Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* first = LoadLocal(instruction.VRegB(), DataType::Type::kInt32);
   HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s(), dex_pc);
   if (reverse) {
     std::swap(first, second);
   }
-  AppendInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+  AppendInstruction(new (arena_) T(DataType::Type::kInt32, first, second, dex_pc));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
 template<typename T>
 void HInstructionBuilder::Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* first = LoadLocal(instruction.VRegB(), DataType::Type::kInt32);
   HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b(), dex_pc);
   if (reverse) {
     std::swap(first, second);
   }
-  AppendInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+  AppendInstruction(new (arena_) T(DataType::Type::kInt32, first, second, dex_pc));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
@@ -624,7 +625,7 @@
 }
 
 void HInstructionBuilder::BuildSwitch(const Instruction& instruction, uint32_t dex_pc) {
-  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+  HInstruction* value = LoadLocal(instruction.VRegA(), DataType::Type::kInt32);
   DexSwitchTable table(instruction, dex_pc);
 
   if (table.GetNumEntries() == 0) {
@@ -651,9 +652,9 @@
 }
 
 void HInstructionBuilder::BuildReturn(const Instruction& instruction,
-                                      Primitive::Type type,
+                                      DataType::Type type,
                                       uint32_t dex_pc) {
-  if (type == Primitive::kPrimVoid) {
+  if (type == DataType::Type::kVoid) {
     // Only <init> (which is a return-void) could possibly have a constructor fence.
     // This may insert additional redundant constructor fences from the super constructors.
     // TODO: remove redundant constructor fences (b/36656456).
@@ -802,7 +803,7 @@
                                       uint32_t register_index) {
   InvokeType invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode());
   const char* descriptor = dex_file_->GetMethodShorty(method_idx);
-  Primitive::Type return_type = Primitive::GetType(descriptor[0]);
+  DataType::Type return_type = DataType::FromShorty(descriptor[0]);
 
   // Remove the return type from the 'proto'.
   size_t number_of_arguments = strlen(descriptor) - 1;
@@ -844,7 +845,7 @@
     HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
         arena_,
         number_of_arguments - 1,
-        Primitive::kPrimNot /*return_type */,
+        DataType::Type::kReference /*return_type */,
         dex_pc,
         method_idx,
         nullptr,
@@ -938,7 +939,7 @@
                                                  uint32_t register_index) {
   const char* descriptor = dex_file_->GetShorty(proto_idx);
   DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), number_of_vreg_arguments);
-  Primitive::Type return_type = Primitive::GetType(descriptor[0]);
+  DataType::Type return_type = DataType::FromShorty(descriptor[0]);
   size_t number_of_arguments = strlen(descriptor);
   HInvoke* invoke = new (arena_) HInvokePolymorphic(arena_,
                                                     number_of_arguments,
@@ -1113,8 +1114,8 @@
        // it hasn't been properly checked.
        (i < number_of_vreg_arguments) && (*argument_index < invoke->GetNumberOfArguments());
        i++, (*argument_index)++) {
-    Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
-    bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble);
+    DataType::Type type = DataType::FromShorty(descriptor[descriptor_index++]);
+    bool is_wide = (type == DataType::Type::kInt64) || (type == DataType::Type::kFloat64);
     if (!is_range
         && is_wide
         && ((i + 1 == number_of_vreg_arguments) || (args[i] + 1 != args[i + 1]))) {
@@ -1169,7 +1170,7 @@
   if (invoke->GetInvokeType() != InvokeType::kStatic) {  // Instance call.
     uint32_t obj_reg = is_range ? register_index : args[0];
     HInstruction* arg = is_unresolved
-        ? LoadLocal(obj_reg, Primitive::kPrimNot)
+        ? LoadLocal(obj_reg, DataType::Type::kReference)
         : LoadNullCheckedLocal(obj_reg, invoke->GetDexPc());
     invoke->SetArgumentAt(0, arg);
     start_index = 1;
@@ -1229,7 +1230,7 @@
   // This is a StringFactory call, not an actual String constructor. Its result
   // replaces the empty String pre-allocated by NewInstance.
   uint32_t orig_this_reg = is_range ? register_index : args[0];
-  HInstruction* arg_this = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+  HInstruction* arg_this = LoadLocal(orig_this_reg, DataType::Type::kReference);
 
   // Replacing the NewInstance might render it redundant. Keep a list of these
   // to be visited once it is clear whether it is has remaining uses.
@@ -1251,10 +1252,10 @@
   return true;
 }
 
-static Primitive::Type GetFieldAccessType(const DexFile& dex_file, uint16_t field_index) {
+static DataType::Type GetFieldAccessType(const DexFile& dex_file, uint16_t field_index) {
   const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index);
   const char* type = dex_file.GetFieldTypeDescriptor(field_id);
-  return Primitive::GetType(type[0]);
+  return DataType::FromShorty(type[0]);
 }
 
 bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
@@ -1280,12 +1281,10 @@
   // is unresolved. In that case, we rely on the runtime to perform various
   // checks first, followed by a null check.
   HInstruction* object = (resolved_field == nullptr)
-      ? LoadLocal(obj_reg, Primitive::kPrimNot)
+      ? LoadLocal(obj_reg, DataType::Type::kReference)
       : LoadNullCheckedLocal(obj_reg, dex_pc);
 
-  Primitive::Type field_type = (resolved_field == nullptr)
-      ? GetFieldAccessType(*dex_file_, field_index)
-      : resolved_field->GetTypeAsPrimitiveType();
+  DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
   if (is_put) {
     HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
     HInstruction* field_set = nullptr;
@@ -1377,7 +1376,7 @@
 void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
                                                            uint32_t dex_pc,
                                                            bool is_put,
-                                                           Primitive::Type field_type) {
+                                                           DataType::Type field_type) {
   uint32_t source_or_dest_reg = instruction.VRegA_21c();
   uint16_t field_index = instruction.VRegB_21c();
 
@@ -1452,12 +1451,12 @@
   if (resolved_field == nullptr) {
     MaybeRecordStat(compilation_stats_,
                     MethodCompilationStat::kUnresolvedField);
-    Primitive::Type field_type = GetFieldAccessType(*dex_file_, field_index);
+    DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
     BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type);
     return true;
   }
 
-  Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
+  DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
 
   Handle<mirror::Class> klass = handles_->NewHandle(resolved_field->GetDeclaringClass());
   HLoadClass* constant = BuildLoadClass(klass->GetDexTypeIndex(),
@@ -1515,15 +1514,15 @@
                                        uint16_t first_vreg,
                                        int64_t second_vreg_or_constant,
                                        uint32_t dex_pc,
-                                       Primitive::Type type,
+                                       DataType::Type type,
                                        bool second_is_constant,
                                        bool isDiv) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   HInstruction* first = LoadLocal(first_vreg, type);
   HInstruction* second = nullptr;
   if (second_is_constant) {
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       second = graph_->GetIntConstant(second_vreg_or_constant, dex_pc);
     } else {
       second = graph_->GetLongConstant(second_vreg_or_constant, dex_pc);
@@ -1533,8 +1532,8 @@
   }
 
   if (!second_is_constant
-      || (type == Primitive::kPrimInt && second->AsIntConstant()->GetValue() == 0)
-      || (type == Primitive::kPrimLong && second->AsLongConstant()->GetValue() == 0)) {
+      || (type == DataType::Type::kInt32 && second->AsIntConstant()->GetValue() == 0)
+      || (type == DataType::Type::kInt64 && second->AsLongConstant()->GetValue() == 0)) {
     second = new (arena_) HDivZeroCheck(second, dex_pc);
     AppendInstruction(second);
   }
@@ -1550,7 +1549,7 @@
 void HInstructionBuilder::BuildArrayAccess(const Instruction& instruction,
                                            uint32_t dex_pc,
                                            bool is_put,
-                                           Primitive::Type anticipated_type) {
+                                           DataType::Type anticipated_type) {
   uint8_t source_or_dest_reg = instruction.VRegA_23x();
   uint8_t array_reg = instruction.VRegB_23x();
   uint8_t index_reg = instruction.VRegC_23x();
@@ -1558,7 +1557,7 @@
   HInstruction* object = LoadNullCheckedLocal(array_reg, dex_pc);
   HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
   AppendInstruction(length);
-  HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
+  HInstruction* index = LoadLocal(index_reg, DataType::Type::kInt32);
   index = new (arena_) HBoundsCheck(index, length, dex_pc);
   AppendInstruction(index);
   if (is_put) {
@@ -1594,7 +1593,7 @@
       || primitive == 'L'
       || primitive == '[') << descriptor;
   bool is_reference_array = (primitive == 'L') || (primitive == '[');
-  Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
+  DataType::Type type = is_reference_array ? DataType::Type::kReference : DataType::Type::kInt32;
 
   for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
     HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
@@ -1612,7 +1611,7 @@
 void HInstructionBuilder::BuildFillArrayData(HInstruction* object,
                                              const T* data,
                                              uint32_t element_count,
-                                             Primitive::Type anticipated_type,
+                                             DataType::Type anticipated_type,
                                              uint32_t dex_pc) {
   for (uint32_t i = 0; i < element_count; ++i) {
     HInstruction* index = graph_->GetIntConstant(i, dex_pc);
@@ -1650,21 +1649,21 @@
       BuildFillArrayData(array,
                          reinterpret_cast<const int8_t*>(data),
                          element_count,
-                         Primitive::kPrimByte,
+                         DataType::Type::kInt8,
                          dex_pc);
       break;
     case 2:
       BuildFillArrayData(array,
                          reinterpret_cast<const int16_t*>(data),
                          element_count,
-                         Primitive::kPrimShort,
+                         DataType::Type::kInt16,
                          dex_pc);
       break;
     case 4:
       BuildFillArrayData(array,
                          reinterpret_cast<const int32_t*>(data),
                          element_count,
-                         Primitive::kPrimInt,
+                         DataType::Type::kInt32,
                          dex_pc);
       break;
     case 8:
@@ -1686,7 +1685,7 @@
   for (uint32_t i = 0; i < element_count; ++i) {
     HInstruction* index = graph_->GetIntConstant(i, dex_pc);
     HInstruction* value = graph_->GetLongConstant(data[i], dex_pc);
-    HArraySet* aset = new (arena_) HArraySet(object, index, value, Primitive::kPrimLong, dex_pc);
+    HArraySet* aset = new (arena_) HArraySet(object, index, value, DataType::Type::kInt64, dex_pc);
     ssa_builder_->MaybeAddAmbiguousArraySet(aset);
     AppendInstruction(aset);
   }
@@ -1783,7 +1782,7 @@
                                          uint8_t reference,
                                          dex::TypeIndex type_index,
                                          uint32_t dex_pc) {
-  HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
+  HInstruction* object = LoadLocal(reference, DataType::Type::kReference);
   HLoadClass* cls = BuildLoadClass(type_index, dex_pc);
 
   ScopedObjectAccess soa(Thread::Current());
@@ -1889,7 +1888,7 @@
     case Instruction::MOVE:
     case Instruction::MOVE_FROM16:
     case Instruction::MOVE_16: {
-      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+      HInstruction* value = LoadLocal(instruction.VRegB(), DataType::Type::kInt32);
       UpdateLocal(instruction.VRegA(), value);
       break;
     }
@@ -1898,7 +1897,7 @@
     case Instruction::MOVE_WIDE:
     case Instruction::MOVE_WIDE_FROM16:
     case Instruction::MOVE_WIDE_16: {
-      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
+      HInstruction* value = LoadLocal(instruction.VRegB(), DataType::Type::kInt64);
       UpdateLocal(instruction.VRegA(), value);
       break;
     }
@@ -1916,9 +1915,10 @@
       if (value->IsIntConstant()) {
         DCHECK_EQ(value->AsIntConstant()->GetValue(), 0);
       } else if (value->IsPhi()) {
-        DCHECK(value->GetType() == Primitive::kPrimInt || value->GetType() == Primitive::kPrimNot);
+        DCHECK(value->GetType() == DataType::Type::kInt32 ||
+               value->GetType() == DataType::Type::kReference);
       } else {
-        value = LoadLocal(reg_number, Primitive::kPrimNot);
+        value = LoadLocal(reg_number, DataType::Type::kReference);
       }
       UpdateLocal(instruction.VRegA(), value);
       break;
@@ -1926,7 +1926,7 @@
 
     case Instruction::RETURN_VOID_NO_BARRIER:
     case Instruction::RETURN_VOID: {
-      BuildReturn(instruction, Primitive::kPrimVoid, dex_pc);
+      BuildReturn(instruction, DataType::Type::kVoid, dex_pc);
       break;
     }
 
@@ -2045,435 +2045,435 @@
     }
 
     case Instruction::NEG_INT: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimInt, dex_pc);
+      Unop_12x<HNeg>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::NEG_LONG: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimLong, dex_pc);
+      Unop_12x<HNeg>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::NEG_FLOAT: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimFloat, dex_pc);
+      Unop_12x<HNeg>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::NEG_DOUBLE: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimDouble, dex_pc);
+      Unop_12x<HNeg>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::NOT_INT: {
-      Unop_12x<HNot>(instruction, Primitive::kPrimInt, dex_pc);
+      Unop_12x<HNot>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::NOT_LONG: {
-      Unop_12x<HNot>(instruction, Primitive::kPrimLong, dex_pc);
+      Unop_12x<HNot>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_LONG: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_FLOAT: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_DOUBLE: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::LONG_TO_INT: {
-      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt64, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::LONG_TO_FLOAT: {
-      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimFloat, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt64, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::LONG_TO_DOUBLE: {
-      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimDouble, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt64, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::FLOAT_TO_INT: {
-      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat32, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::FLOAT_TO_LONG: {
-      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimLong, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat32, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::FLOAT_TO_DOUBLE: {
-      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimDouble, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat32, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::DOUBLE_TO_INT: {
-      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimInt, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat64, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::DOUBLE_TO_LONG: {
-      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimLong, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat64, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::DOUBLE_TO_FLOAT: {
-      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimFloat, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kFloat64, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_BYTE: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kInt8, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_SHORT: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimShort, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kInt16, dex_pc);
       break;
     }
 
     case Instruction::INT_TO_CHAR: {
-      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar, dex_pc);
+      Conversion_12x(instruction, DataType::Type::kInt32, DataType::Type::kUint16, dex_pc);
       break;
     }
 
     case Instruction::ADD_INT: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HAdd>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::ADD_LONG: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HAdd>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::ADD_DOUBLE: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_23x<HAdd>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::ADD_FLOAT: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_23x<HAdd>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::SUB_INT: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HSub>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SUB_LONG: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HSub>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::SUB_FLOAT: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_23x<HSub>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::SUB_DOUBLE: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_23x<HSub>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::ADD_INT_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HAdd>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HMul>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::MUL_LONG: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HMul>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::MUL_FLOAT: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_23x<HMul>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::MUL_DOUBLE: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_23x<HMul>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::DIV_INT: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimInt, false, true);
+                         dex_pc, DataType::Type::kInt32, false, true);
       break;
     }
 
     case Instruction::DIV_LONG: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimLong, false, true);
+                         dex_pc, DataType::Type::kInt64, false, true);
       break;
     }
 
     case Instruction::DIV_FLOAT: {
-      Binop_23x<HDiv>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_23x<HDiv>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::DIV_DOUBLE: {
-      Binop_23x<HDiv>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_23x<HDiv>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::REM_INT: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimInt, false, false);
+                         dex_pc, DataType::Type::kInt32, false, false);
       break;
     }
 
     case Instruction::REM_LONG: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimLong, false, false);
+                         dex_pc, DataType::Type::kInt64, false, false);
       break;
     }
 
     case Instruction::REM_FLOAT: {
-      Binop_23x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_23x<HRem>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::REM_DOUBLE: {
-      Binop_23x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_23x<HRem>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::AND_INT: {
-      Binop_23x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HAnd>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::AND_LONG: {
-      Binop_23x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HAnd>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::SHL_INT: {
-      Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x_shift<HShl>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SHL_LONG: {
-      Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x_shift<HShl>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::SHR_INT: {
-      Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x_shift<HShr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SHR_LONG: {
-      Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x_shift<HShr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::USHR_INT: {
-      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x_shift<HUShr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::USHR_LONG: {
-      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x_shift<HUShr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::OR_INT: {
-      Binop_23x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HOr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::OR_LONG: {
-      Binop_23x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HOr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT: {
-      Binop_23x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_23x<HXor>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::XOR_LONG: {
-      Binop_23x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_23x<HXor>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::ADD_LONG_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HAdd>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::ADD_DOUBLE_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_12x<HAdd>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::ADD_FLOAT_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_12x<HAdd>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::SUB_INT_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HSub>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SUB_LONG_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HSub>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::SUB_FLOAT_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_12x<HSub>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::SUB_DOUBLE_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_12x<HSub>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HMul>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::MUL_LONG_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HMul>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::MUL_FLOAT_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_12x<HMul>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::MUL_DOUBLE_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_12x<HMul>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::DIV_INT_2ADDR: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
-                         dex_pc, Primitive::kPrimInt, false, true);
+                         dex_pc, DataType::Type::kInt32, false, true);
       break;
     }
 
     case Instruction::DIV_LONG_2ADDR: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
-                         dex_pc, Primitive::kPrimLong, false, true);
+                         dex_pc, DataType::Type::kInt64, false, true);
       break;
     }
 
     case Instruction::REM_INT_2ADDR: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
-                         dex_pc, Primitive::kPrimInt, false, false);
+                         dex_pc, DataType::Type::kInt32, false, false);
       break;
     }
 
     case Instruction::REM_LONG_2ADDR: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
-                         dex_pc, Primitive::kPrimLong, false, false);
+                         dex_pc, DataType::Type::kInt64, false, false);
       break;
     }
 
     case Instruction::REM_FLOAT_2ADDR: {
-      Binop_12x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_12x<HRem>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::REM_DOUBLE_2ADDR: {
-      Binop_12x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_12x<HRem>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::SHL_INT_2ADDR: {
-      Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x_shift<HShl>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SHL_LONG_2ADDR: {
-      Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x_shift<HShl>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::SHR_INT_2ADDR: {
-      Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x_shift<HShr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::SHR_LONG_2ADDR: {
-      Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x_shift<HShr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::USHR_INT_2ADDR: {
-      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x_shift<HUShr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::USHR_LONG_2ADDR: {
-      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x_shift<HUShr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::DIV_FLOAT_2ADDR: {
-      Binop_12x<HDiv>(instruction, Primitive::kPrimFloat, dex_pc);
+      Binop_12x<HDiv>(instruction, DataType::Type::kFloat32, dex_pc);
       break;
     }
 
     case Instruction::DIV_DOUBLE_2ADDR: {
-      Binop_12x<HDiv>(instruction, Primitive::kPrimDouble, dex_pc);
+      Binop_12x<HDiv>(instruction, DataType::Type::kFloat64, dex_pc);
       break;
     }
 
     case Instruction::AND_INT_2ADDR: {
-      Binop_12x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HAnd>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::AND_LONG_2ADDR: {
-      Binop_12x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HAnd>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::OR_INT_2ADDR: {
-      Binop_12x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HOr>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::OR_LONG_2ADDR: {
-      Binop_12x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HOr>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT_2ADDR: {
-      Binop_12x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
+      Binop_12x<HXor>(instruction, DataType::Type::kInt32, dex_pc);
       break;
     }
 
     case Instruction::XOR_LONG_2ADDR: {
-      Binop_12x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
+      Binop_12x<HXor>(instruction, DataType::Type::kInt64, dex_pc);
       break;
     }
 
@@ -2540,14 +2540,14 @@
     case Instruction::DIV_INT_LIT16:
     case Instruction::DIV_INT_LIT8: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimInt, true, true);
+                         dex_pc, DataType::Type::kInt32, true, true);
       break;
     }
 
     case Instruction::REM_INT_LIT16:
     case Instruction::REM_INT_LIT8: {
       BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
-                         dex_pc, Primitive::kPrimInt, true, false);
+                         dex_pc, DataType::Type::kInt32, true, false);
       break;
     }
 
@@ -2578,7 +2578,7 @@
 
     case Instruction::NEW_ARRAY: {
       dex::TypeIndex type_index(instruction.VRegC_22c());
-      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+      HInstruction* length = LoadLocal(instruction.VRegB_22c(), DataType::Type::kInt32);
       HLoadClass* cls = BuildLoadClass(type_index, dex_pc);
 
       HNewArray* new_array = new (arena_) HNewArray(cls, length, dex_pc);
@@ -2632,27 +2632,27 @@
     }
 
     case Instruction::CMP_LONG: {
-      Binop_23x_cmp(instruction, Primitive::kPrimLong, ComparisonBias::kNoBias, dex_pc);
+      Binop_23x_cmp(instruction, DataType::Type::kInt64, ComparisonBias::kNoBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, DataType::Type::kFloat32, ComparisonBias::kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, DataType::Type::kFloat64, ComparisonBias::kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, DataType::Type::kFloat32, ComparisonBias::kLtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, DataType::Type::kFloat64, ComparisonBias::kLtBias, dex_pc);
       break;
     }
 
@@ -2735,13 +2735,13 @@
       break;                                                                      \
     }
 
-    ARRAY_XX(, Primitive::kPrimInt);
-    ARRAY_XX(_WIDE, Primitive::kPrimLong);
-    ARRAY_XX(_OBJECT, Primitive::kPrimNot);
-    ARRAY_XX(_BOOLEAN, Primitive::kPrimBoolean);
-    ARRAY_XX(_BYTE, Primitive::kPrimByte);
-    ARRAY_XX(_CHAR, Primitive::kPrimChar);
-    ARRAY_XX(_SHORT, Primitive::kPrimShort);
+    ARRAY_XX(, DataType::Type::kInt32);
+    ARRAY_XX(_WIDE, DataType::Type::kInt64);
+    ARRAY_XX(_OBJECT, DataType::Type::kReference);
+    ARRAY_XX(_BOOLEAN, DataType::Type::kBool);
+    ARRAY_XX(_BYTE, DataType::Type::kInt8);
+    ARRAY_XX(_CHAR, DataType::Type::kUint16);
+    ARRAY_XX(_SHORT, DataType::Type::kInt16);
 
     case Instruction::ARRAY_LENGTH: {
       HInstruction* object = LoadNullCheckedLocal(instruction.VRegB_12x(), dex_pc);
@@ -2781,7 +2781,7 @@
     }
 
     case Instruction::THROW: {
-      HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+      HInstruction* exception = LoadLocal(instruction.VRegA_11x(), DataType::Type::kReference);
       AppendInstruction(new (arena_) HThrow(exception, dex_pc));
       // We finished building this block. Set the current block to null to avoid
       // adding dead instructions to it.
@@ -2806,7 +2806,7 @@
 
     case Instruction::MONITOR_ENTER: {
       AppendInstruction(new (arena_) HMonitorOperation(
-          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          LoadLocal(instruction.VRegA_11x(), DataType::Type::kReference),
           HMonitorOperation::OperationKind::kEnter,
           dex_pc));
       break;
@@ -2814,7 +2814,7 @@
 
     case Instruction::MONITOR_EXIT: {
       AppendInstruction(new (arena_) HMonitorOperation(
-          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          LoadLocal(instruction.VRegA_11x(), DataType::Type::kReference),
           HMonitorOperation::OperationKind::kExit,
           dex_pc));
       break;
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index b7fa394..a684bf4 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -42,7 +42,7 @@
                       SsaBuilder* ssa_builder,
                       const DexFile* dex_file,
                       const DexFile::CodeItem& code_item,
-                      Primitive::Type return_type,
+                      DataType::Type return_type,
                       DexCompilationUnit* dex_compilation_unit,
                       const DexCompilationUnit* const outer_compilation_unit,
                       CompilerDriver* driver,
@@ -96,7 +96,7 @@
   ArenaVector<HInstruction*>* GetLocalsForWithAllocation(
       HBasicBlock* block, ArenaVector<HInstruction*>* locals, const size_t vregs);
   HInstruction* ValueOfLocalAt(HBasicBlock* block, size_t local);
-  HInstruction* LoadLocal(uint32_t register_index, Primitive::Type type) const;
+  HInstruction* LoadLocal(uint32_t register_index, DataType::Type type) const;
   HInstruction* LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc);
   void UpdateLocal(uint32_t register_index, HInstruction* instruction);
 
@@ -112,24 +112,24 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<typename T>
-  void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void Unop_12x(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void Binop_23x(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_23x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void Binop_23x_shift(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   void Binop_23x_cmp(const Instruction& instruction,
-                     Primitive::Type type,
+                     DataType::Type type,
                      ComparisonBias bias,
                      uint32_t dex_pc);
 
   template<typename T>
-  void Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void Binop_12x(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_12x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void Binop_12x_shift(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   template<typename T>
   void Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc);
@@ -141,19 +141,19 @@
   template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_pc);
 
   void Conversion_12x(const Instruction& instruction,
-                      Primitive::Type input_type,
-                      Primitive::Type result_type,
+                      DataType::Type input_type,
+                      DataType::Type result_type,
                       uint32_t dex_pc);
 
   void BuildCheckedDivRem(uint16_t out_reg,
                           uint16_t first_reg,
                           int64_t second_reg_or_constant,
                           uint32_t dex_pc,
-                          Primitive::Type type,
+                          DataType::Type type,
                           bool second_is_lit,
                           bool is_div);
 
-  void BuildReturn(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+  void BuildReturn(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
 
   // Builds an instance field access node and returns whether the instruction is supported.
   bool BuildInstanceFieldAccess(const Instruction& instruction,
@@ -164,14 +164,14 @@
   void BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
                                         uint32_t dex_pc,
                                         bool is_put,
-                                        Primitive::Type field_type);
+                                        DataType::Type field_type);
   // Builds a static field access node and returns whether the instruction is supported.
   bool BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
 
   void BuildArrayAccess(const Instruction& instruction,
                         uint32_t dex_pc,
                         bool is_get,
-                        Primitive::Type anticipated_type);
+                        DataType::Type anticipated_type);
 
   // Builds an invocation node and returns whether the instruction is supported.
   bool BuildInvoke(const Instruction& instruction,
@@ -210,7 +210,7 @@
   void BuildFillArrayData(HInstruction* object,
                           const T* data,
                           uint32_t element_count,
-                          Primitive::Type anticipated_type,
+                          DataType::Type anticipated_type,
                           uint32_t dex_pc);
 
   // Fills the given object with data as specified in the fill-array-data
@@ -321,7 +321,7 @@
   const DexFile::CodeItem& code_item_;
 
   // The return type of the method being compiled.
-  const Primitive::Type return_type_;
+  const DataType::Type return_type_;
 
   HBasicBlockBuilder* block_builder_;
   SsaBuilder* ssa_builder_;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 337177f..1a2494a 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,6 +18,7 @@
 
 #include "art_method-inl.h"
 #include "class_linker-inl.h"
+#include "data_type-inl.h"
 #include "escape.h"
 #include "intrinsics.h"
 #include "mirror/class-inl.h"
@@ -103,10 +104,10 @@
 
   bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
 
-  void SimplifyRotate(HInvoke* invoke, bool is_left, Primitive::Type type);
+  void SimplifyRotate(HInvoke* invoke, bool is_left, DataType::Type type);
   void SimplifySystemArrayCopy(HInvoke* invoke);
   void SimplifyStringEquals(HInvoke* invoke);
-  void SimplifyCompare(HInvoke* invoke, bool is_signum, Primitive::Type type);
+  void SimplifyCompare(HInvoke* invoke, bool is_signum, DataType::Type type);
   void SimplifyIsNaN(HInvoke* invoke);
   void SimplifyFP2Int(HInvoke* invoke);
   void SimplifyStringCharAt(HInvoke* invoke);
@@ -178,7 +179,7 @@
   // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point.
   // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`,
   // while the later yields `-0.0`.
-  if (!Primitive::IsIntegralType(binop->GetType())) {
+  if (!DataType::IsIntegralType(binop->GetType())) {
     return false;
   }
   binop->ReplaceInput(left_neg->GetInput(), 0);
@@ -194,7 +195,7 @@
 
 bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation* op) {
   DCHECK(op->IsAnd() || op->IsOr()) << op->DebugName();
-  Primitive::Type type = op->GetType();
+  DataType::Type type = op->GetType();
   HInstruction* left = op->GetLeft();
   HInstruction* right = op->GetRight();
 
@@ -246,24 +247,24 @@
 }
 
 bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul) {
-  Primitive::Type type = mul->GetPackedType();
+  DataType::Type type = mul->GetPackedType();
   InstructionSet isa = codegen_->GetInstructionSet();
   switch (isa) {
     case kArm64:
-      if (!(type == Primitive::kPrimByte ||
-            type == Primitive::kPrimChar ||
-            type == Primitive::kPrimShort ||
-            type == Primitive::kPrimInt)) {
+      if (!(type == DataType::Type::kInt8 ||
+            type == DataType::Type::kUint16 ||
+            type == DataType::Type::kInt16 ||
+            type == DataType::Type::kInt32)) {
         return false;
       }
       break;
     case kMips:
     case kMips64:
-      if (!(type == Primitive::kPrimByte ||
-            type == Primitive::kPrimChar ||
-            type == Primitive::kPrimShort ||
-            type == Primitive::kPrimInt ||
-            type == Primitive::kPrimLong)) {
+      if (!(type == DataType::Type::kInt8 ||
+            type == DataType::Type::kUint16 ||
+            type == DataType::Type::kInt16 ||
+            type == DataType::Type::kInt32 ||
+            type == DataType::Type::kInt64)) {
         return false;
       }
       break;
@@ -328,7 +329,7 @@
   HInstruction* shift_amount = instruction->GetRight();
   HInstruction* value = instruction->GetLeft();
 
-  int64_t implicit_mask = (value->GetType() == Primitive::kPrimLong)
+  int64_t implicit_mask = (value->GetType() == DataType::Type::kInt64)
       ? kMaxLongShiftDistance
       : kMaxIntShiftDistance;
 
@@ -351,7 +352,7 @@
       //    SHL dst, value, cst & implicit_mask
       // (as defined by shift semantics). This ensures other
       // optimizations do not need to special case for such situations.
-      DCHECK_EQ(shift_amount->GetType(), Primitive::kPrimInt);
+      DCHECK_EQ(shift_amount->GetType(), DataType::Type::kInt32);
       instruction->ReplaceInput(GetGraph()->GetIntConstant(masked_cst), /* index */ 1);
       RecordSimplification();
       return;
@@ -412,7 +413,7 @@
   if ((left->IsUShr() && right->IsShl()) || (left->IsShl() && right->IsUShr())) {
     HUShr* ushr = left->IsUShr() ? left->AsUShr() : right->AsUShr();
     HShl* shl = left->IsShl() ? left->AsShl() : right->AsShl();
-    DCHECK(Primitive::IsIntOrLongType(ushr->GetType()));
+    DCHECK(DataType::IsIntOrLongType(ushr->GetType()));
     if (ushr->GetType() == shl->GetType() &&
         ushr->GetLeft() == shl->GetLeft()) {
       if (ushr->GetRight()->IsConstant() && shl->GetRight()->IsConstant()) {
@@ -445,7 +446,7 @@
                                                                        HUShr* ushr,
                                                                        HShl* shl) {
   DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
-  size_t reg_bits = Primitive::ComponentSize(ushr->GetType()) * kBitsPerByte;
+  size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
   size_t rdist = Int64FromConstant(ushr->GetRight()->AsConstant());
   size_t ldist = Int64FromConstant(shl->GetRight()->AsConstant());
   if (((ldist + rdist) & (reg_bits - 1)) == 0) {
@@ -506,7 +507,7 @@
                                                                           HShl* shl) {
   DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
   DCHECK(ushr->GetRight()->IsSub() || shl->GetRight()->IsSub());
-  size_t reg_bits = Primitive::ComponentSize(ushr->GetType()) * kBitsPerByte;
+  size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
   HInstruction* shl_shift = shl->GetRight();
   HInstruction* ushr_shift = ushr->GetRight();
   if ((shl_shift->IsSub() && IsSubRegBitsMinusOther(shl_shift->AsSub(), reg_bits, ushr_shift)) ||
@@ -664,14 +665,14 @@
 }
 
 void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+  if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
       && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
     instruction->ClearValueCanBeNull();
   }
 }
 
 void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+  if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
       && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
     instruction->ClearValueCanBeNull();
   }
@@ -708,7 +709,7 @@
 }
 
 static bool CmpHasBoolType(HInstruction* input, HInstruction* cmp) {
-  if (input->GetType() == Primitive::kPrimBoolean) {
+  if (input->GetType() == DataType::Type::kBool) {
     return true;  // input has direct boolean type
   } else if (cmp->GetUses().HasExactlyOneElement()) {
     // Comparison also has boolean type if both its input and the instruction
@@ -801,7 +802,7 @@
   } else if (input->IsCondition() &&
              // Don't change FP compares. The definition of compares involving
              // NaNs forces the compares to be done as written by the user.
-             !Primitive::IsFloatingPointType(input->InputAt(0)->GetType())) {
+             !DataType::IsFloatingPointType(input->InputAt(0)->GetType())) {
     // Replace condition with its opposite.
     replace_with = GetGraph()->InsertOppositeCondition(input->AsCondition(), bool_not);
   }
@@ -815,8 +816,8 @@
 
 // Constructs a new ABS(x) node in the HIR.
 static HInstruction* NewIntegralAbs(ArenaAllocator* arena, HInstruction* x, HInstruction* cursor) {
-  Primitive::Type type = x->GetType();
-  DCHECK(type == Primitive::kPrimInt || type ==  Primitive::kPrimLong);
+  DataType::Type type = x->GetType();
+  DCHECK(type == DataType::Type::kInt32 || type ==  DataType::Type::kInt64);
   // Construct a fake intrinsic with as much context as is needed to allocate one.
   // The intrinsic will always be lowered into code later anyway.
   // TODO: b/65164101 : moving towards a real HAbs node makes more sense.
@@ -837,8 +838,8 @@
       MethodReference(nullptr, dex::kDexNoIndex),
       HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
   invoke->SetArgumentAt(0, x);
-  invoke->SetIntrinsic(type == Primitive::kPrimInt ? Intrinsics::kMathAbsInt
-                                                   : Intrinsics::kMathAbsLong,
+  invoke->SetIntrinsic(type == DataType::Type::kInt32 ? Intrinsics::kMathAbsInt
+                                                      : Intrinsics::kMathAbsLong,
                        kNoEnvironmentOrCache,
                        kNoSideEffects,
                        kNoThrow);
@@ -848,20 +849,20 @@
 
 // Returns true if operands a and b consists of widening type conversions
 // (either explicit or implicit) to the given to_type.
-static bool AreLowerPrecisionArgs(Primitive::Type to_type, HInstruction* a, HInstruction* b) {
+static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInstruction* b) {
   if (a->IsTypeConversion() && a->GetType() == to_type) {
     a = a->InputAt(0);
   }
   if (b->IsTypeConversion() && b->GetType() == to_type) {
     b = b->InputAt(0);
   }
-  Primitive::Type type1 = a->GetType();
-  Primitive::Type type2 = b->GetType();
-  return (type1 == Primitive::kPrimByte  && type2 == Primitive::kPrimByte) ||
-         (type1 == Primitive::kPrimShort && type2 == Primitive::kPrimShort) ||
-         (type1 == Primitive::kPrimChar  && type2 == Primitive::kPrimChar) ||
-         (type1 == Primitive::kPrimInt   && type2 == Primitive::kPrimInt &&
-          to_type == Primitive::kPrimLong);
+  DataType::Type type1 = a->GetType();
+  DataType::Type type2 = b->GetType();
+  return (type1 == DataType::Type::kInt8  && type2 == DataType::Type::kInt8) ||
+         (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) ||
+         (type1 == DataType::Type::kUint16  && type2 == DataType::Type::kUint16) ||
+         (type1 == DataType::Type::kInt32   && type2 == DataType::Type::kInt32 &&
+          to_type == DataType::Type::kInt64);
 }
 
 void InstructionSimplifierVisitor::VisitSelect(HSelect* select) {
@@ -904,11 +905,12 @@
     IfCondition cmp = condition->AsCondition()->GetCondition();
     HInstruction* a = condition->InputAt(0);
     HInstruction* b = condition->InputAt(1);
-    Primitive::Type t_type = true_value->GetType();
-    Primitive::Type f_type = false_value->GetType();
+    DataType::Type t_type = true_value->GetType();
+    DataType::Type f_type = false_value->GetType();
     // Here we have a <cmp> b ? true_value : false_value.
     // Test if both values are same-typed int or long.
-    if (t_type == f_type && (t_type == Primitive::kPrimInt || t_type == Primitive::kPrimLong)) {
+    if (t_type == f_type &&
+        (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) {
       // Try to replace typical integral ABS constructs.
       if (true_value->IsNeg()) {
         HInstruction* negated = true_value->InputAt(0);
@@ -974,7 +976,9 @@
 
 void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
   HInstruction* value = instruction->GetValue();
-  if (value->GetType() != Primitive::kPrimNot) return;
+  if (value->GetType() != DataType::Type::kReference) {
+    return;
+  }
 
   if (CanEnsureNotNullAt(value, instruction)) {
     instruction->ClearValueCanBeNull();
@@ -1014,39 +1018,39 @@
   }
 }
 
-static bool IsTypeConversionImplicit(Primitive::Type input_type, Primitive::Type result_type) {
+static bool IsTypeConversionImplicit(DataType::Type input_type, DataType::Type result_type) {
   // Invariant: We should never generate a conversion to a Boolean value.
-  DCHECK_NE(Primitive::kPrimBoolean, result_type);
+  DCHECK_NE(DataType::Type::kBool, result_type);
 
   // Besides conversion to the same type, widening integral conversions are implicit,
   // excluding conversions to long and the byte->char conversion where we need to
   // clear the high 16 bits of the 32-bit sign-extended representation of byte.
   return result_type == input_type ||
-      (result_type == Primitive::kPrimInt && (input_type == Primitive::kPrimBoolean ||
-                                              input_type == Primitive::kPrimByte ||
-                                              input_type == Primitive::kPrimShort ||
-                                              input_type == Primitive::kPrimChar)) ||
-      (result_type == Primitive::kPrimChar && input_type == Primitive::kPrimBoolean) ||
-      (result_type == Primitive::kPrimShort && (input_type == Primitive::kPrimBoolean ||
-                                                input_type == Primitive::kPrimByte)) ||
-      (result_type == Primitive::kPrimByte && input_type == Primitive::kPrimBoolean);
+      (result_type == DataType::Type::kInt32 && (input_type == DataType::Type::kBool ||
+                                                 input_type == DataType::Type::kInt8 ||
+                                                 input_type == DataType::Type::kInt16 ||
+                                                 input_type == DataType::Type::kUint16)) ||
+      (result_type == DataType::Type::kUint16 && input_type == DataType::Type::kBool) ||
+      (result_type == DataType::Type::kInt16 && (input_type == DataType::Type::kBool ||
+                                                 input_type == DataType::Type::kInt8)) ||
+      (result_type == DataType::Type::kInt8 && input_type == DataType::Type::kBool);
 }
 
-static bool IsTypeConversionLossless(Primitive::Type input_type, Primitive::Type result_type) {
+static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type result_type) {
   // The conversion to a larger type is loss-less with the exception of two cases,
-  //   - conversion to char, the only unsigned type, where we may lose some bits, and
+  //   - conversion to Uint16, the only unsigned type, where we may lose some bits, and
   //   - conversion from float to long, the only FP to integral conversion with smaller FP type.
   // For integral to FP conversions this holds because the FP mantissa is large enough.
   DCHECK_NE(input_type, result_type);
-  return Primitive::ComponentSize(result_type) > Primitive::ComponentSize(input_type) &&
-      result_type != Primitive::kPrimChar &&
-      !(result_type == Primitive::kPrimLong && input_type == Primitive::kPrimFloat);
+  return DataType::Size(result_type) > DataType::Size(input_type) &&
+      result_type != DataType::Type::kUint16 &&
+      !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);
 }
 
 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
   HInstruction* input = instruction->GetInput();
-  Primitive::Type input_type = input->GetType();
-  Primitive::Type result_type = instruction->GetResultType();
+  DataType::Type input_type = input->GetType();
+  DataType::Type result_type = instruction->GetResultType();
   if (IsTypeConversionImplicit(input_type, result_type)) {
     // Remove the implicit conversion; this includes conversion to the same type.
     instruction->ReplaceWith(input);
@@ -1058,7 +1062,7 @@
   if (input->IsTypeConversion()) {
     HTypeConversion* input_conversion = input->AsTypeConversion();
     HInstruction* original_input = input_conversion->GetInput();
-    Primitive::Type original_type = original_input->GetType();
+    DataType::Type original_type = original_input->GetType();
 
     // When the first conversion is lossless, a direct conversion from the original type
     // to the final type yields the same result, even for a lossy second conversion, for
@@ -1069,10 +1073,10 @@
     // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct
     // conversion yields the same result, for example long->int->short or int->char->short.
     bool integral_conversions_with_non_widening_second =
-        Primitive::IsIntegralType(input_type) &&
-        Primitive::IsIntegralType(original_type) &&
-        Primitive::IsIntegralType(result_type) &&
-        Primitive::ComponentSize(result_type) <= Primitive::ComponentSize(input_type);
+        DataType::IsIntegralType(input_type) &&
+        DataType::IsIntegralType(original_type) &&
+        DataType::IsIntegralType(result_type) &&
+        DataType::Size(result_type) <= DataType::Size(input_type);
 
     if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) {
       // If the merged conversion is implicit, do the simplification unconditionally.
@@ -1094,15 +1098,15 @@
         return;
       }
     }
-  } else if (input->IsAnd() && Primitive::IsIntegralType(result_type)) {
-    DCHECK(Primitive::IsIntegralType(input_type));
+  } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) {
+    DCHECK(DataType::IsIntegralType(input_type));
     HAnd* input_and = input->AsAnd();
     HConstant* constant = input_and->GetConstantRight();
     if (constant != nullptr) {
       int64_t value = Int64FromConstant(constant);
       DCHECK_NE(value, -1);  // "& -1" would have been optimized away in VisitAnd().
       size_t trailing_ones = CTZ(~static_cast<uint64_t>(value));
-      if (trailing_ones >= kBitsPerByte * Primitive::ComponentSize(result_type)) {
+      if (trailing_ones >= kBitsPerByte * DataType::Size(result_type)) {
         // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
         HInstruction* original_input = input_and->GetLeastConstantLeft();
         if (IsTypeConversionImplicit(original_input->GetType(), result_type)) {
@@ -1124,7 +1128,7 @@
 void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
-  bool integral_type = Primitive::IsIntegralType(instruction->GetType());
+  bool integral_type = DataType::IsIntegralType(instruction->GetType());
   if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
     // Replace code looking like
     //    ADD dst, src, 0
@@ -1226,7 +1230,7 @@
     // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
     // precisely clears the shifted-in sign bits.
     if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) {
-      size_t reg_bits = (instruction->GetResultType() == Primitive::kPrimLong) ? 64 : 32;
+      size_t reg_bits = (instruction->GetResultType() == DataType::Type::kInt64) ? 64 : 32;
       size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1);
       size_t num_tail_bits_set = CTZ(value + 1);
       if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) {
@@ -1447,7 +1451,7 @@
 void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   if ((input_cst != nullptr) && input_cst->IsOne()) {
     // Replace code looking like
@@ -1471,19 +1475,19 @@
     return;
   }
 
-  if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) {
+  if ((input_cst != nullptr) && DataType::IsFloatingPointType(type)) {
     // Try replacing code looking like
     //    DIV dst, src, constant
     // with
     //    MUL dst, src, 1 / constant
     HConstant* reciprocal = nullptr;
-    if (type == Primitive::Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       double value = input_cst->AsDoubleConstant()->GetValue();
       if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
         reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimFloat);
+      DCHECK_EQ(type, DataType::Type::kFloat32);
       float value = input_cst->AsFloatConstant()->GetValue();
       if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
         reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
@@ -1502,7 +1506,7 @@
 void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   HBasicBlock* block = instruction->GetBlock();
   ArenaAllocator* allocator = GetGraph()->GetArena();
 
@@ -1522,7 +1526,7 @@
   }
 
   if (input_cst->IsMinusOne() &&
-      (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
+      (DataType::IsFloatingPointType(type) || DataType::IsIntOrLongType(type))) {
     // Replace code looking like
     //    MUL dst, src, -1
     // with
@@ -1533,7 +1537,7 @@
     return;
   }
 
-  if (Primitive::IsFloatingPointType(type) &&
+  if (DataType::IsFloatingPointType(type) &&
       ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
        (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
     // Replace code looking like
@@ -1547,7 +1551,7 @@
     return;
   }
 
-  if (Primitive::IsIntOrLongType(type)) {
+  if (DataType::IsIntOrLongType(type)) {
     int64_t factor = Int64FromConstant(input_cst);
     // Even though constant propagation also takes care of the zero case, other
     // optimizations can lead to having a zero multiplication.
@@ -1630,7 +1634,7 @@
   }
 
   if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
-      !Primitive::IsFloatingPointType(input->GetType())) {
+      !DataType::IsFloatingPointType(input->GetType())) {
     // Replace code looking like
     //    SUB tmp, a, b
     //    NEG dst, tmp
@@ -1726,8 +1730,8 @@
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
 
-  Primitive::Type type = instruction->GetType();
-  if (Primitive::IsFloatingPointType(type)) {
+  DataType::Type type = instruction->GetType();
+  if (DataType::IsFloatingPointType(type)) {
     return;
   }
 
@@ -1818,7 +1822,7 @@
     // SUB instruction is not needed in this case, we may use
     // one of inputs of ADD instead.
     // It is applicable to integral types only.
-    DCHECK(Primitive::IsIntegralType(type));
+    DCHECK(DataType::IsIntegralType(type));
     if (left->InputAt(1) == right) {
       instruction->ReplaceWith(left->InputAt(0));
       RecordSimplification();
@@ -1853,7 +1857,7 @@
   }
 
   if ((input_cst != nullptr) && input_cst->IsOne()
-      && input_other->GetType() == Primitive::kPrimBoolean) {
+      && input_other->GetType() == DataType::Type::kBool) {
     // Replace code looking like
     //    XOR dst, src, 1
     // with
@@ -1930,7 +1934,7 @@
 
 void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke,
                                                   bool is_left,
-                                                  Primitive::Type type) {
+                                                  DataType::Type type) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
   DCHECK_EQ(invoke->GetInvokeType(), InvokeType::kStatic);
   HInstruction* value = invoke->InputAt(0);
@@ -1940,7 +1944,7 @@
     // Unconditionally set the type of the negated distance to `int`,
     // as shift and rotate operations expect a 32-bit (or narrower)
     // value for their distance input.
-    distance = new (GetGraph()->GetArena()) HNeg(Primitive::kPrimInt, distance);
+    distance = new (GetGraph()->GetArena()) HNeg(DataType::Type::kInt32, distance);
     invoke->GetBlock()->InsertInstructionBefore(distance, invoke);
   }
   HRor* ror = new (GetGraph()->GetArena()) HRor(type, value, distance);
@@ -1993,8 +1997,8 @@
 
   {
     ScopedObjectAccess soa(Thread::Current());
-    Primitive::Type source_component_type = Primitive::kPrimVoid;
-    Primitive::Type destination_component_type = Primitive::kPrimVoid;
+    DataType::Type source_component_type = DataType::Type::kVoid;
+    DataType::Type destination_component_type = DataType::Type::kVoid;
     ReferenceTypeInfo destination_rti = destination->GetReferenceTypeInfo();
     if (destination_rti.IsValid()) {
       if (destination_rti.IsObjectArray()) {
@@ -2004,8 +2008,8 @@
         optimizations.SetDestinationIsTypedObjectArray();
       }
       if (destination_rti.IsPrimitiveArrayClass()) {
-        destination_component_type =
-            destination_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType();
+        destination_component_type = DataTypeFromPrimitive(
+            destination_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
         optimizations.SetDestinationIsPrimitiveArray();
       } else if (destination_rti.IsNonPrimitiveArrayClass()) {
         optimizations.SetDestinationIsNonPrimitiveArray();
@@ -2018,13 +2022,14 @@
       }
       if (source_rti.IsPrimitiveArrayClass()) {
         optimizations.SetSourceIsPrimitiveArray();
-        source_component_type = source_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType();
+        source_component_type = DataTypeFromPrimitive(
+            source_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
       } else if (source_rti.IsNonPrimitiveArrayClass()) {
         optimizations.SetSourceIsNonPrimitiveArray();
       }
     }
     // For primitive arrays, use their optimized ArtMethod implementations.
-    if ((source_component_type != Primitive::kPrimVoid) &&
+    if ((source_component_type != DataType::Type::kVoid) &&
         (source_component_type == destination_component_type)) {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       PointerSize image_size = class_linker->GetImagePointerSize();
@@ -2032,28 +2037,28 @@
       mirror::Class* system = invoke->GetResolvedMethod()->GetDeclaringClass();
       ArtMethod* method = nullptr;
       switch (source_component_type) {
-        case Primitive::kPrimBoolean:
+        case DataType::Type::kBool:
           method = system->FindClassMethod("arraycopy", "([ZI[ZII)V", image_size);
           break;
-        case Primitive::kPrimByte:
+        case DataType::Type::kInt8:
           method = system->FindClassMethod("arraycopy", "([BI[BII)V", image_size);
           break;
-        case Primitive::kPrimChar:
+        case DataType::Type::kUint16:
           method = system->FindClassMethod("arraycopy", "([CI[CII)V", image_size);
           break;
-        case Primitive::kPrimShort:
+        case DataType::Type::kInt16:
           method = system->FindClassMethod("arraycopy", "([SI[SII)V", image_size);
           break;
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt32:
           method = system->FindClassMethod("arraycopy", "([II[III)V", image_size);
           break;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           method = system->FindClassMethod("arraycopy", "([FI[FII)V", image_size);
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           method = system->FindClassMethod("arraycopy", "([JI[JII)V", image_size);
           break;
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           method = system->FindClassMethod("arraycopy", "([DI[DII)V", image_size);
           break;
         default:
@@ -2074,14 +2079,14 @@
 
 void InstructionSimplifierVisitor::SimplifyCompare(HInvoke* invoke,
                                                    bool is_signum,
-                                                   Primitive::Type type) {
+                                                   DataType::Type type) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
   uint32_t dex_pc = invoke->GetDexPc();
   HInstruction* left = invoke->InputAt(0);
   HInstruction* right;
   if (!is_signum) {
     right = invoke->InputAt(1);
-  } else if (type == Primitive::kPrimLong) {
+  } else if (type == DataType::Type::kInt64) {
     right = GetGraph()->GetLongConstant(0);
   } else {
     right = GetGraph()->GetIntConstant(0);
@@ -2105,17 +2110,17 @@
   DCHECK(invoke->IsInvokeStaticOrDirect());
   uint32_t dex_pc = invoke->GetDexPc();
   HInstruction* x = invoke->InputAt(0);
-  Primitive::Type type = x->GetType();
+  DataType::Type type = x->GetType();
   // Set proper bit pattern for NaN and replace intrinsic with raw version.
   HInstruction* nan;
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     nan = GetGraph()->GetLongConstant(0x7ff8000000000000L);
     invoke->SetIntrinsic(Intrinsics::kDoubleDoubleToRawLongBits,
                          kNeedsEnvironmentOrCache,
                          kNoSideEffects,
                          kNoThrow);
   } else {
-    DCHECK_EQ(type, Primitive::kPrimFloat);
+    DCHECK_EQ(type, DataType::Type::kFloat32);
     nan = GetGraph()->GetIntConstant(0x7fc00000);
     invoke->SetIntrinsic(Intrinsics::kFloatFloatToRawIntBits,
                          kNeedsEnvironmentOrCache,
@@ -2145,7 +2150,7 @@
       index, length, dex_pc, invoke->GetDexMethodIndex());
   invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
   HArrayGet* array_get = new (arena) HArrayGet(
-      str, bounds_check, Primitive::kPrimChar, dex_pc, /* is_string_char_at */ true);
+      str, bounds_check, DataType::Type::kUint16, dex_pc, /* is_string_char_at */ true);
   invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get);
   bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment());
   GetGraph()->SetHasBoundsChecks(true);
@@ -2248,28 +2253,28 @@
       SimplifySystemArrayCopy(instruction);
       break;
     case Intrinsics::kIntegerRotateRight:
-      SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimInt);
+      SimplifyRotate(instruction, /* is_left */ false, DataType::Type::kInt32);
       break;
     case Intrinsics::kLongRotateRight:
-      SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimLong);
+      SimplifyRotate(instruction, /* is_left */ false, DataType::Type::kInt64);
       break;
     case Intrinsics::kIntegerRotateLeft:
-      SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimInt);
+      SimplifyRotate(instruction, /* is_left */ true, DataType::Type::kInt32);
       break;
     case Intrinsics::kLongRotateLeft:
-      SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimLong);
+      SimplifyRotate(instruction, /* is_left */ true, DataType::Type::kInt64);
       break;
     case Intrinsics::kIntegerCompare:
-      SimplifyCompare(instruction, /* is_signum */ false, Primitive::kPrimInt);
+      SimplifyCompare(instruction, /* is_signum */ false, DataType::Type::kInt32);
       break;
     case Intrinsics::kLongCompare:
-      SimplifyCompare(instruction, /* is_signum */ false, Primitive::kPrimLong);
+      SimplifyCompare(instruction, /* is_signum */ false, DataType::Type::kInt64);
       break;
     case Intrinsics::kIntegerSignum:
-      SimplifyCompare(instruction, /* is_signum */ true, Primitive::kPrimInt);
+      SimplifyCompare(instruction, /* is_signum */ true, DataType::Type::kInt32);
       break;
     case Intrinsics::kLongSignum:
-      SimplifyCompare(instruction, /* is_signum */ true, Primitive::kPrimLong);
+      SimplifyCompare(instruction, /* is_signum */ true, DataType::Type::kInt64);
       break;
     case Intrinsics::kFloatIsNaN:
     case Intrinsics::kDoubleIsNaN:
@@ -2337,7 +2342,7 @@
     HBinaryOperation* instruction) {
   DCHECK(instruction->IsCommutative());
 
-  if (!Primitive::IsIntegralType(instruction->GetType())) {
+  if (!DataType::IsIntegralType(instruction->GetType())) {
     return false;
   }
 
@@ -2387,12 +2392,12 @@
 }
 
 // Helper function that performs addition statically, considering the result type.
-static int64_t ComputeAddition(Primitive::Type type, int64_t x, int64_t y) {
+static int64_t ComputeAddition(DataType::Type type, int64_t x, int64_t y) {
   // Use the Compute() method for consistency with TryStaticEvaluation().
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     return HAdd::Compute<int32_t>(x, y);
   } else {
-    DCHECK_EQ(type, Primitive::kPrimLong);
+    DCHECK_EQ(type, DataType::Type::kInt64);
     return HAdd::Compute<int64_t>(x, y);
   }
 }
@@ -2414,8 +2419,8 @@
     HBinaryOperation* instruction) {
   DCHECK(instruction->IsAdd() || instruction->IsSub()) << instruction->DebugName();
 
-  Primitive::Type type = instruction->GetType();
-  if (!Primitive::IsIntegralType(type)) {
+  DataType::Type type = instruction->GetType();
+  if (!DataType::IsIntegralType(type)) {
     return false;
   }
 
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index a32d0ce..efd7cb4 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -38,8 +38,8 @@
   DCHECK(CanFitInShifterOperand(bitfield_op));
   DCHECK(!bitfield_op->HasEnvironmentUses());
 
-  Primitive::Type type = use->GetType();
-  if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
+  DataType::Type type = use->GetType();
+  if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
     return false;
   }
 
@@ -70,17 +70,17 @@
   int shift_amount = 0;
 
   HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
-  shift_amount &= use->GetType() == Primitive::kPrimInt
+  shift_amount &= use->GetType() == DataType::Type::kInt32
       ? kMaxIntShiftDistance
       : kMaxLongShiftDistance;
 
   if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
-    if (!use->IsAdd() && (!use->IsSub() || use->GetType() != Primitive::kPrimLong)) {
+    if (!use->IsAdd() && (!use->IsSub() || use->GetType() != DataType::Type::kInt64)) {
       return false;
     }
   // Shift by 1 is a special case that results in the same number and type of instructions
   // as this simplification, but potentially shorter code.
-  } else if (type == Primitive::kPrimLong && shift_amount == 1) {
+  } else if (type == DataType::Type::kInt64 && shift_amount == 1) {
     return false;
   }
 
@@ -143,7 +143,7 @@
 
 void InstructionSimplifierArmVisitor::VisitArrayGet(HArrayGet* instruction) {
   size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
 
   // TODO: Implement reading (length + compression) for String compression feature from
   // negative offset (count_offset - data_offset). Thumb2Assembler (now removed) did
@@ -153,9 +153,9 @@
     return;
   }
 
-  if (type == Primitive::kPrimLong
-      || type == Primitive::kPrimFloat
-      || type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kInt64
+      || type == DataType::Type::kFloat32
+      || type == DataType::Type::kFloat64) {
     // T32 doesn't support ShiftedRegOffset mem address mode for these types
     // to enable optimization.
     return;
@@ -170,13 +170,13 @@
 }
 
 void InstructionSimplifierArmVisitor::VisitArraySet(HArraySet* instruction) {
-  size_t access_size = Primitive::ComponentSize(instruction->GetComponentType());
+  size_t access_size = DataType::Size(instruction->GetComponentType());
   size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
-  Primitive::Type type = instruction->GetComponentType();
+  DataType::Type type = instruction->GetComponentType();
 
-  if (type == Primitive::kPrimLong
-      || type == Primitive::kPrimFloat
-      || type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kInt64
+      || type == DataType::Type::kFloat32
+      || type == DataType::Type::kFloat64) {
     // T32 doesn't support ShiftedRegOffset mem address mode for these types
     // to enable optimization.
     return;
@@ -215,15 +215,15 @@
 }
 
 void InstructionSimplifierArmVisitor::VisitTypeConversion(HTypeConversion* instruction) {
-  Primitive::Type result_type = instruction->GetResultType();
-  Primitive::Type input_type = instruction->GetInputType();
+  DataType::Type result_type = instruction->GetResultType();
+  DataType::Type input_type = instruction->GetInputType();
 
   if (input_type == result_type) {
     // We let the arch-independent code handle this.
     return;
   }
 
-  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
+  if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
     TryMergeIntoUsersShifterOperand(instruction);
   }
 }
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 7c9bfb1..1c3b79d 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -38,8 +38,8 @@
   DCHECK(CanFitInShifterOperand(bitfield_op));
   DCHECK(!bitfield_op->HasEnvironmentUses());
 
-  Primitive::Type type = use->GetType();
-  if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
+  DataType::Type type = use->GetType();
+  if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
     return false;
   }
 
@@ -150,7 +150,7 @@
 }
 
 void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
-  size_t access_size = Primitive::ComponentSize(instruction->GetComponentType());
+  size_t access_size = DataType::Size(instruction->GetComponentType());
   size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
   if (TryExtractArrayAccessAddress(instruction,
                                    instruction->GetArray(),
@@ -185,15 +185,15 @@
 }
 
 void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
-  Primitive::Type result_type = instruction->GetResultType();
-  Primitive::Type input_type = instruction->GetInputType();
+  DataType::Type result_type = instruction->GetResultType();
+  DataType::Type input_type = instruction->GetInputType();
 
   if (input_type == result_type) {
     // We let the arch-independent code handle this.
     return;
   }
 
-  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
+  if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
     TryMergeIntoUsersShifterOperand(instruction);
   }
 }
diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc
index 7a759b9..73d866f 100644
--- a/compiler/optimizing/instruction_simplifier_shared.cc
+++ b/compiler/optimizing/instruction_simplifier_shared.cc
@@ -25,7 +25,7 @@
 bool TrySimpleMultiplyAccumulatePatterns(HMul* mul,
                                          HBinaryOperation* input_binop,
                                          HInstruction* input_other) {
-  DCHECK(Primitive::IsIntOrLongType(mul->GetType()));
+  DCHECK(DataType::IsIntOrLongType(mul->GetType()));
   DCHECK(input_binop->IsAdd() || input_binop->IsSub());
   DCHECK_NE(input_binop, input_other);
   if (!input_binop->HasOnlyOneNonEnvironmentUse()) {
@@ -88,16 +88,16 @@
 }  // namespace
 
 bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa) {
-  Primitive::Type type = mul->GetType();
+  DataType::Type type = mul->GetType();
   switch (isa) {
     case kArm:
     case kThumb2:
-      if (type != Primitive::kPrimInt) {
+      if (type != DataType::Type::kInt32) {
         return false;
       }
       break;
     case kArm64:
-      if (!Primitive::IsIntOrLongType(type)) {
+      if (!DataType::IsIntOrLongType(type)) {
         return false;
       }
       break;
@@ -240,13 +240,13 @@
     return false;
   }
   if (access->IsArraySet() &&
-      access->AsArraySet()->GetValue()->GetType() == Primitive::kPrimNot) {
+      access->AsArraySet()->GetValue()->GetType() == DataType::Type::kReference) {
     // The access may require a runtime call or the original array pointer.
     return false;
   }
   if (kEmitCompilerReadBarrier &&
       access->IsArrayGet() &&
-      access->GetType() == Primitive::kPrimNot) {
+      access->GetType() == DataType::Type::kReference) {
     // For object arrays, the read barrier instrumentation requires
     // the original array pointer.
     // TODO: This can be relaxed for Baker CC.
@@ -290,10 +290,10 @@
 
   HGraph* graph = access->GetBlock()->GetGraph();
   ArenaAllocator* arena = graph->GetArena();
-  Primitive::Type packed_type = access->GetPackedType();
+  DataType::Type packed_type = access->GetPackedType();
   uint32_t data_offset = mirror::Array::DataOffset(
-      Primitive::ComponentSize(packed_type)).Uint32Value();
-  size_t component_shift = Primitive::ComponentSizeShift(packed_type);
+      DataType::Size(packed_type)).Uint32Value();
+  size_t component_shift = DataType::SizeShift(packed_type);
 
   bool is_extracting_beneficial = false;
   // It is beneficial to extract index intermediate address only if there are at least 2 users.
@@ -301,10 +301,10 @@
     HInstruction* user = use.GetUser();
     if (user->IsVecMemoryOperation() && user != access) {
       HVecMemoryOperation* another_access = user->AsVecMemoryOperation();
-      Primitive::Type another_packed_type = another_access->GetPackedType();
+      DataType::Type another_packed_type = another_access->GetPackedType();
       uint32_t another_data_offset = mirror::Array::DataOffset(
-          Primitive::ComponentSize(another_packed_type)).Uint32Value();
-      size_t another_component_shift = Primitive::ComponentSizeShift(another_packed_type);
+          DataType::Size(another_packed_type)).Uint32Value();
+      size_t another_component_shift = DataType::SizeShift(another_packed_type);
       if (another_data_offset == data_offset && another_component_shift == component_shift) {
         is_extracting_beneficial = true;
         break;
diff --git a/compiler/optimizing/instruction_simplifier_shared.h b/compiler/optimizing/instruction_simplifier_shared.h
index 31e2383..b016a87 100644
--- a/compiler/optimizing/instruction_simplifier_shared.h
+++ b/compiler/optimizing/instruction_simplifier_shared.h
@@ -26,10 +26,10 @@
 inline bool CanFitInShifterOperand(HInstruction* instruction) {
   if (instruction->IsTypeConversion()) {
     HTypeConversion* conversion = instruction->AsTypeConversion();
-    Primitive::Type result_type = conversion->GetResultType();
-    Primitive::Type input_type = conversion->GetInputType();
+    DataType::Type result_type = conversion->GetResultType();
+    DataType::Type input_type = conversion->GetInputType();
     // We don't expect to see the same type as input and result.
-    return Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type) &&
+    return DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type) &&
         (result_type != input_type);
   } else {
     return (instruction->IsShl() && instruction->AsShl()->InputAt(1)->IsIntConstant()) ||
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 96efe7f..75a1ce7 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -76,16 +76,16 @@
 #define __ codegen->GetVIXLAssembler()->
 
 static void MoveFromReturnRegister(Location trg,
-                                   Primitive::Type type,
+                                   DataType::Type type,
                                    CodeGeneratorARM64* codegen) {
   if (!trg.IsValid()) {
-    DCHECK(type == Primitive::kPrimVoid);
+    DCHECK(type == DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
-  if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
+  if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
     Register trg_reg = RegisterFrom(trg, type);
     Register res_reg = RegisterFrom(ARM64ReturnLocation(type), type);
     __ Mov(trg_reg, res_reg, kDiscardForSameWReg);
@@ -173,7 +173,7 @@
     DCHECK(instruction_->GetLocations()->Intrinsified());
     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
 
-    const int32_t element_size = Primitive::ComponentSize(Primitive::kPrimNot);
+    const int32_t element_size = DataType::Size(DataType::Type::kReference);
 
     Register src_curr_addr = XRegisterFrom(locations->GetTemp(0));
     Register dst_curr_addr = XRegisterFrom(locations->GetTemp(1));
@@ -303,18 +303,18 @@
 }
 
 static void GenReverseBytes(LocationSummary* locations,
-                            Primitive::Type type,
+                            DataType::Type type,
                             MacroAssembler* masm) {
   Location in = locations->InAt(0);
   Location out = locations->Out();
 
   switch (type) {
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ Rev16(WRegisterFrom(out), WRegisterFrom(in));
       __ Sxth(WRegisterFrom(out), WRegisterFrom(out));
       break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt32:
+    case DataType::Type::kInt64:
       __ Rev(RegisterFrom(out, type), RegisterFrom(in, type));
       break;
     default:
@@ -328,7 +328,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongReverseBytes(HInvoke* invoke) {
@@ -336,7 +336,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitShortReverseBytes(HInvoke* invoke) {
@@ -344,7 +344,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitShortReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetVIXLAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetVIXLAssembler());
 }
 
 static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -357,9 +357,9 @@
 }
 
 static void GenNumberOfLeadingZeros(LocationSummary* locations,
-                                    Primitive::Type type,
+                                    DataType::Type type,
                                     MacroAssembler* masm) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   Location in = locations->InAt(0);
   Location out = locations->Out();
@@ -372,7 +372,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
-  GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
+  GenNumberOfLeadingZeros(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
@@ -380,13 +380,13 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
-  GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
+  GenNumberOfLeadingZeros(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
 }
 
 static void GenNumberOfTrailingZeros(LocationSummary* locations,
-                                     Primitive::Type type,
+                                     DataType::Type type,
                                      MacroAssembler* masm) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   Location in = locations->InAt(0);
   Location out = locations->Out();
@@ -400,7 +400,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
-  GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
+  GenNumberOfTrailingZeros(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
@@ -408,13 +408,13 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
-  GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
+  GenNumberOfTrailingZeros(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
 }
 
 static void GenReverse(LocationSummary* locations,
-                       Primitive::Type type,
+                       DataType::Type type,
                        MacroAssembler* masm) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   Location in = locations->InAt(0);
   Location out = locations->Out();
@@ -427,7 +427,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerReverse(HInvoke* invoke) {
-  GenReverse(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
+  GenReverse(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongReverse(HInvoke* invoke) {
@@ -435,19 +435,19 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongReverse(HInvoke* invoke) {
-  GenReverse(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
+  GenReverse(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
 }
 
-static void GenBitCount(HInvoke* instr, Primitive::Type type, MacroAssembler* masm) {
-  DCHECK(Primitive::IsIntOrLongType(type)) << type;
-  DCHECK_EQ(instr->GetType(), Primitive::kPrimInt);
-  DCHECK_EQ(Primitive::PrimitiveKind(instr->InputAt(0)->GetType()), type);
+static void GenBitCount(HInvoke* instr, DataType::Type type, MacroAssembler* masm) {
+  DCHECK(DataType::IsIntOrLongType(type)) << type;
+  DCHECK_EQ(instr->GetType(), DataType::Type::kInt32);
+  DCHECK_EQ(DataType::Kind(instr->InputAt(0)->GetType()), type);
 
   UseScratchRegisterScope temps(masm);
 
   Register src = InputRegisterAt(instr, 0);
   Register dst = RegisterFrom(instr->GetLocations()->Out(), type);
-  FPRegister fpr = (type == Primitive::kPrimLong) ? temps.AcquireD() : temps.AcquireS();
+  FPRegister fpr = (type == DataType::Type::kInt64) ? temps.AcquireD() : temps.AcquireS();
 
   __ Fmov(fpr, src);
   __ Cnt(fpr.V8B(), fpr.V8B());
@@ -460,7 +460,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, Primitive::kPrimLong, GetVIXLAssembler());
+  GenBitCount(invoke, DataType::Type::kInt64, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitIntegerBitCount(HInvoke* invoke) {
@@ -468,19 +468,19 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, Primitive::kPrimInt, GetVIXLAssembler());
+  GenBitCount(invoke, DataType::Type::kInt32, GetVIXLAssembler());
 }
 
-static void GenHighestOneBit(HInvoke* invoke, Primitive::Type type, MacroAssembler* masm) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+static void GenHighestOneBit(HInvoke* invoke, DataType::Type type, MacroAssembler* masm) {
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   UseScratchRegisterScope temps(masm);
 
   Register src = InputRegisterAt(invoke, 0);
   Register dst = RegisterFrom(invoke->GetLocations()->Out(), type);
-  Register temp = (type == Primitive::kPrimLong) ? temps.AcquireX() : temps.AcquireW();
-  size_t high_bit = (type == Primitive::kPrimLong) ? 63u : 31u;
-  size_t clz_high_bit = (type == Primitive::kPrimLong) ? 6u : 5u;
+  Register temp = (type == DataType::Type::kInt64) ? temps.AcquireX() : temps.AcquireW();
+  size_t high_bit = (type == DataType::Type::kInt64) ? 63u : 31u;
+  size_t clz_high_bit = (type == DataType::Type::kInt64) ? 6u : 5u;
 
   __ Clz(temp, src);
   __ Mov(dst, UINT64_C(1) << high_bit);  // MOV (bitmask immediate)
@@ -493,7 +493,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke, Primitive::kPrimInt, GetVIXLAssembler());
+  GenHighestOneBit(invoke, DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongHighestOneBit(HInvoke* invoke) {
@@ -501,17 +501,17 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke, Primitive::kPrimLong, GetVIXLAssembler());
+  GenHighestOneBit(invoke, DataType::Type::kInt64, GetVIXLAssembler());
 }
 
-static void GenLowestOneBit(HInvoke* invoke, Primitive::Type type, MacroAssembler* masm) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+static void GenLowestOneBit(HInvoke* invoke, DataType::Type type, MacroAssembler* masm) {
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   UseScratchRegisterScope temps(masm);
 
   Register src = InputRegisterAt(invoke, 0);
   Register dst = RegisterFrom(invoke->GetLocations()->Out(), type);
-  Register temp = (type == Primitive::kPrimLong) ? temps.AcquireX() : temps.AcquireW();
+  Register temp = (type == DataType::Type::kInt64) ? temps.AcquireX() : temps.AcquireW();
 
   __ Neg(temp, src);
   __ And(dst, temp, src);
@@ -522,7 +522,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke, Primitive::kPrimInt, GetVIXLAssembler());
+  GenLowestOneBit(invoke, DataType::Type::kInt32, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitLongLowestOneBit(HInvoke* invoke) {
@@ -530,7 +530,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke, Primitive::kPrimLong, GetVIXLAssembler());
+  GenLowestOneBit(invoke, DataType::Type::kInt64, GetVIXLAssembler());
 }
 
 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -902,18 +902,18 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitThreadCurrentThread(HInvoke* invoke) {
-  codegen_->Load(Primitive::kPrimNot, WRegisterFrom(invoke->GetLocations()->Out()),
+  codegen_->Load(DataType::Type::kReference, WRegisterFrom(invoke->GetLocations()->Out()),
                  MemOperand(tr, Thread::PeerOffset<kArm64PointerSize>().Int32Value()));
 }
 
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          CodeGeneratorARM64* codegen) {
   LocationSummary* locations = invoke->GetLocations();
-  DCHECK((type == Primitive::kPrimInt) ||
-         (type == Primitive::kPrimLong) ||
-         (type == Primitive::kPrimNot));
+  DCHECK((type == DataType::Type::kInt32) ||
+         (type == DataType::Type::kInt64) ||
+         (type == DataType::Type::kReference));
   Location base_loc = locations->InAt(1);
   Register base = WRegisterFrom(base_loc);      // Object pointer.
   Location offset_loc = locations->InAt(2);
@@ -921,7 +921,7 @@
   Location trg_loc = locations->Out();
   Register trg = RegisterFrom(trg_loc, type);
 
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case.
     Register temp = WRegisterFrom(locations->GetTemp(0));
     codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
@@ -942,7 +942,7 @@
       codegen->Load(type, trg, mem_op);
     }
 
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       DCHECK(trg.IsW());
       codegen->MaybeGenerateReadBarrierSlow(invoke, trg_loc, trg_loc, base_loc, 0u, offset_loc);
     }
@@ -991,22 +991,22 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 
 static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) {
@@ -1048,7 +1048,7 @@
 }
 
 static void GenUnsafePut(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          bool is_ordered,
                          CodeGeneratorARM64* codegen) {
@@ -1066,7 +1066,7 @@
     // freeing the temporary registers so they can be used in `MarkGCCard`.
     UseScratchRegisterScope temps(masm);
 
-    if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    if (kPoisonHeapReferences && type == DataType::Type::kReference) {
       DCHECK(value.IsW());
       Register temp = temps.AcquireW();
       __ Mov(temp.W(), value.W());
@@ -1081,7 +1081,7 @@
     }
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(base, value, value_can_be_null);
   }
@@ -1089,63 +1089,63 @@
 
 void IntrinsicCodeGeneratorARM64::VisitUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutObject(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutLong(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke,
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
@@ -1153,7 +1153,7 @@
 
 static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena,
                                        HInvoke* invoke,
-                                       Primitive::Type type) {
+                                       DataType::Type type) {
   bool can_call = kEmitCompilerReadBarrier &&
       kUseBakerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
@@ -1172,17 +1172,17 @@
   // operations to potentially clobber the output. Likewise when
   // emitting a (Baker) read barrier, which may call.
   Location::OutputOverlap overlaps =
-      ((kPoisonHeapReferences && type == Primitive::kPrimNot) || can_call)
+      ((kPoisonHeapReferences && type == DataType::Type::kReference) || can_call)
       ? Location::kOutputOverlap
       : Location::kNoOutputOverlap;
   locations->SetOut(Location::RequiresRegister(), overlaps);
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // Temporary register for (Baker) read barrier.
     locations->AddTemp(Location::RequiresRegister());
   }
 }
 
-static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorARM64* codegen) {
+static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorARM64* codegen) {
   MacroAssembler* masm = codegen->GetVIXLAssembler();
   LocationSummary* locations = invoke->GetLocations();
 
@@ -1196,7 +1196,7 @@
   Register value = RegisterFrom(locations->InAt(4), type);         // Value.
 
   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Mark card for object assuming new value is stored.
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(base, value, value_can_be_null);
@@ -1228,7 +1228,7 @@
 
   __ Add(tmp_ptr, base.X(), Operand(offset));
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     codegen->GetAssembler()->PoisonHeapReference(expected);
     if (value.Is(expected)) {
       // Do not poison `value`, as it is the same register as
@@ -1253,7 +1253,7 @@
   __ Bind(&exit_loop);
   __ Cset(out, eq);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     codegen->GetAssembler()->UnpoisonHeapReference(expected);
     if (value.Is(expected)) {
       // Do not unpoison `value`, as it is the same register as
@@ -1265,10 +1265,10 @@
 }
 
 void IntrinsicLocationsBuilderARM64::VisitUnsafeCASInt(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntIntIntToInt(arena_, invoke, DataType::Type::kInt32);
 }
 void IntrinsicLocationsBuilderARM64::VisitUnsafeCASLong(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntIntIntToInt(arena_, invoke, DataType::Type::kInt64);
 }
 void IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject(HInvoke* invoke) {
   // The only read barrier implementation supporting the
@@ -1277,21 +1277,21 @@
     return;
   }
 
-  CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntIntIntToInt(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorARM64::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimInt, codegen_);
+  GenCas(invoke, DataType::Type::kInt32, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeCASLong(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimLong, codegen_);
+  GenCas(invoke, DataType::Type::kInt64, codegen_);
 }
 void IntrinsicCodeGeneratorARM64::VisitUnsafeCASObject(HInvoke* invoke) {
   // The only read barrier implementation supporting the
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCas(invoke, Primitive::kPrimNot, codegen_);
+  GenCas(invoke, DataType::Type::kReference, codegen_);
 }
 
 void IntrinsicLocationsBuilderARM64::VisitStringCompareTo(HInvoke* invoke) {
@@ -1397,7 +1397,7 @@
   DCHECK_ALIGNED(value_offset, 8);
   static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
 
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   // Promote temp2 to an X reg, ready for LDR.
@@ -1457,7 +1457,7 @@
     __ Bind(&different_compression);
 
     // Comparison for different compression style.
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
     temp1 = temp1.W();
     temp2 = temp2.W();
@@ -1731,7 +1731,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     Register char_reg = WRegisterFrom(locations->InAt(1));
     __ Tst(char_reg, 0xFFFF0000);
     slow_path = new (allocator) IntrinsicSlowPathARM64(invoke);
@@ -1762,7 +1762,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimInt));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
 
   // Need to send start_index=0.
   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
@@ -1783,7 +1783,7 @@
   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimInt));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
 }
 
 void IntrinsicCodeGeneratorARM64::VisitStringIndexOfAfter(HInvoke* invoke) {
@@ -1800,7 +1800,7 @@
   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
   locations->SetInAt(3, LocationFrom(calling_convention.GetRegisterAt(3)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromBytes(HInvoke* invoke) {
@@ -1826,7 +1826,7 @@
   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromChars(HInvoke* invoke) {
@@ -1846,7 +1846,7 @@
                                                             kIntrinsified);
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
 }
 
 void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromString(HInvoke* invoke) {
@@ -1866,8 +1866,8 @@
 
 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
-  DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType()));
-  DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
+  DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
+  DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
 
   LocationSummary* const locations = new (arena) LocationSummary(invoke,
                                                                  LocationSummary::kCallOnMainOnly,
@@ -1880,9 +1880,9 @@
 
 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
   DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
-  DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType()));
-  DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(1)->GetType()));
-  DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
+  DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
+  DCHECK(DataType::IsFloatingPointType(invoke->InputAt(1)->GetType()));
+  DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
 
   LocationSummary* const locations = new (arena) LocationSummary(invoke,
                                                                  LocationSummary::kCallOnMainOnly,
@@ -2056,7 +2056,7 @@
   LocationSummary* locations = invoke->GetLocations();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   // Location of data in char array buffer.
@@ -2135,7 +2135,7 @@
   __ B(&done);
 
   if (mirror::kUseStringCompression) {
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
     __ Bind(&compressed_string_preloop);
     __ Add(src_ptr, src_ptr, Operand(srcBegin));
@@ -2219,7 +2219,7 @@
       if (!length_is_input_length) {
         // Check that length(input) >= length.
         __ Ldr(temp, MemOperand(input, length_offset));
-        __ Cmp(temp, OperandFrom(length, Primitive::kPrimInt));
+        __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32));
         __ B(slow_path->GetEntryLabel(), lt);
       }
     } else {
@@ -2229,7 +2229,7 @@
       __ B(slow_path->GetEntryLabel(), lt);
 
       // Check that (length(input) - pos) >= length.
-      __ Cmp(temp, OperandFrom(length, Primitive::kPrimInt));
+      __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32));
       __ B(slow_path->GetEntryLabel(), lt);
     }
   } else if (length_is_input_length) {
@@ -2244,7 +2244,7 @@
     __ Ldr(temp, MemOperand(input, length_offset));
     __ Subs(temp, temp, pos_reg);
     // Ccmp if length(input) >= pos, else definitely bail to slow path (N!=V == lt).
-    __ Ccmp(temp, OperandFrom(length, Primitive::kPrimInt), NFlag, ge);
+    __ Ccmp(temp, OperandFrom(length, DataType::Type::kInt32), NFlag, ge);
     __ B(slow_path->GetEntryLabel(), lt);
   }
 }
@@ -2253,7 +2253,7 @@
 // source address for System.arraycopy* intrinsics in `src_base`,
 // `dst_base` and `src_end` respectively.
 static void GenSystemArrayCopyAddresses(MacroAssembler* masm,
-                                        Primitive::Type type,
+                                        DataType::Type type,
                                         const Register& src,
                                         const Location& src_pos,
                                         const Register& dst,
@@ -2263,10 +2263,10 @@
                                         const Register& dst_base,
                                         const Register& src_end) {
   // This routine is used by the SystemArrayCopy and the SystemArrayCopyChar intrinsics.
-  DCHECK(type == Primitive::kPrimNot || type == Primitive::kPrimChar)
+  DCHECK(type == DataType::Type::kReference || type == DataType::Type::kUint16)
       << "Unexpected element type: " << type;
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const int32_t element_size_shift = Primitive::ComponentSizeShift(type);
+  const int32_t element_size = DataType::Size(type);
+  const int32_t element_size_shift = DataType::SizeShift(type);
   const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
 
   if (src_pos.IsConstant()) {
@@ -2353,7 +2353,7 @@
   src_stop_addr = src_stop_addr.X();
 
   GenSystemArrayCopyAddresses(masm,
-                              Primitive::kPrimChar,
+                              DataType::Type::kUint16,
                               src,
                               src_pos,
                               dst,
@@ -2364,7 +2364,7 @@
                               src_stop_addr);
 
   // Iterate over the arrays and do a raw copy of the chars.
-  const int32_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const int32_t char_size = DataType::Size(DataType::Type::kUint16);
   UseScratchRegisterScope temps(masm);
   Register tmp = temps.AcquireW();
   vixl::aarch64::Label loop, done;
@@ -2781,8 +2781,8 @@
       Register dst_curr_addr = temp2.X();
       Register src_stop_addr = temp3.X();
       vixl::aarch64::Label done;
-      const Primitive::Type type = Primitive::kPrimNot;
-      const int32_t element_size = Primitive::ComponentSize(type);
+      const DataType::Type type = DataType::Type::kReference;
+      const int32_t element_size = DataType::Size(type);
 
       if (length.IsRegister()) {
         // Don't enter the copy loop if the length is null.
@@ -2957,7 +2957,7 @@
   IntrinsicVisitor::ComputeIntegerValueOfLocations(
       invoke,
       codegen_,
-      calling_convention.GetReturnLocation(Primitive::kPrimNot),
+      calling_convention.GetReturnLocation(DataType::Type::kReference),
       Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
 }
 
@@ -2966,7 +2966,7 @@
   LocationSummary* locations = invoke->GetLocations();
   MacroAssembler* masm = GetVIXLAssembler();
 
-  Register out = RegisterFrom(locations->Out(), Primitive::kPrimNot);
+  Register out = RegisterFrom(locations->Out(), DataType::Type::kReference);
   UseScratchRegisterScope temps(masm);
   Register temp = temps.AcquireW();
   InvokeRuntimeCallingConvention calling_convention;
@@ -2996,7 +2996,7 @@
       codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
     }
   } else {
-    Register in = RegisterFrom(locations->InAt(0), Primitive::kPrimInt);
+    Register in = RegisterFrom(locations->InAt(0), DataType::Type::kInt32);
     // Check bounds of our cache.
     __ Add(out.W(), in.W(), -info.low);
     __ Cmp(out.W(), info.high - info.low + 1);
@@ -3007,8 +3007,8 @@
     uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
     __ Ldr(temp.W(), codegen_->DeduplicateBootImageAddressLiteral(data_offset + address));
     MemOperand source = HeapOperand(
-        temp, out.X(), LSL, Primitive::ComponentSizeShift(Primitive::kPrimNot));
-    codegen_->Load(Primitive::kPrimNot, out, source);
+        temp, out.X(), LSL, DataType::SizeShift(DataType::Type::kReference));
+    codegen_->Load(DataType::Type::kReference, out, source);
     codegen_->GetAssembler()->MaybeUnpoisonHeapReference(out);
     __ B(&done);
     __ Bind(&allocate);
@@ -3034,7 +3034,7 @@
 
 void IntrinsicCodeGeneratorARM64::VisitThreadInterrupted(HInvoke* invoke) {
   MacroAssembler* masm = GetVIXLAssembler();
-  Register out = RegisterFrom(invoke->GetLocations()->Out(), Primitive::kPrimInt);
+  Register out = RegisterFrom(invoke->GetLocations()->Out(), DataType::Type::kInt32);
   UseScratchRegisterScope temps(masm);
   Register temp = temps.AcquireX();
 
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index e2494f0..7ce576c 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -126,16 +126,16 @@
 
 // Compute base address for the System.arraycopy intrinsic in `base`.
 static void GenSystemArrayCopyBaseAddress(ArmVIXLAssembler* assembler,
-                                          Primitive::Type type,
+                                          DataType::Type type,
                                           const vixl32::Register& array,
                                           const Location& pos,
                                           const vixl32::Register& base) {
   // This routine is only used by the SystemArrayCopy intrinsic at the
-  // moment. We can allow Primitive::kPrimNot as `type` to implement
+  // moment. We can allow DataType::Type::kReference as `type` to implement
   // the SystemArrayCopyChar intrinsic.
-  DCHECK_EQ(type, Primitive::kPrimNot);
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const uint32_t element_size_shift = Primitive::ComponentSizeShift(type);
+  DCHECK_EQ(type, DataType::Type::kReference);
+  const int32_t element_size = DataType::Size(type);
+  const uint32_t element_size_shift = DataType::SizeShift(type);
   const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
 
   if (pos.IsConstant()) {
@@ -149,16 +149,16 @@
 
 // Compute end address for the System.arraycopy intrinsic in `end`.
 static void GenSystemArrayCopyEndAddress(ArmVIXLAssembler* assembler,
-                                         Primitive::Type type,
+                                         DataType::Type type,
                                          const Location& copy_length,
                                          const vixl32::Register& base,
                                          const vixl32::Register& end) {
   // This routine is only used by the SystemArrayCopy intrinsic at the
-  // moment. We can allow Primitive::kPrimNot as `type` to implement
+  // moment. We can allow DataType::Type::kReference as `type` to implement
   // the SystemArrayCopyChar intrinsic.
-  DCHECK_EQ(type, Primitive::kPrimNot);
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const uint32_t element_size_shift = Primitive::ComponentSizeShift(type);
+  DCHECK_EQ(type, DataType::Type::kReference);
+  const int32_t element_size = DataType::Size(type);
+  const uint32_t element_size_shift = DataType::SizeShift(type);
 
   if (copy_length.IsConstant()) {
     int32_t constant = Int32ConstantFrom(copy_length);
@@ -188,8 +188,8 @@
     DCHECK(instruction_->GetLocations()->Intrinsified());
     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
 
-    Primitive::Type type = Primitive::kPrimNot;
-    const int32_t element_size = Primitive::ComponentSize(type);
+    DataType::Type type = DataType::Type::kReference;
+    const int32_t element_size = DataType::Size(type);
 
     vixl32::Register dest = InputRegisterAt(instruction_, 2);
     Location dest_pos = locations->InAt(3);
@@ -349,16 +349,16 @@
 }
 
 static void GenNumberOfLeadingZeros(HInvoke* invoke,
-                                    Primitive::Type type,
+                                    DataType::Type type,
                                     CodeGeneratorARMVIXL* codegen) {
   ArmVIXLAssembler* assembler = codegen->GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
   Location in = locations->InAt(0);
   vixl32::Register out = RegisterFrom(locations->Out());
 
-  DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong));
+  DCHECK((type == DataType::Type::kInt32) || (type == DataType::Type::kInt64));
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     vixl32::Register in_reg_lo = LowRegisterFrom(in);
     vixl32::Register in_reg_hi = HighRegisterFrom(in);
     vixl32::Label end;
@@ -380,7 +380,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
-  GenNumberOfLeadingZeros(invoke, Primitive::kPrimInt, codegen_);
+  GenNumberOfLeadingZeros(invoke, DataType::Type::kInt32, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
@@ -388,19 +388,19 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
-  GenNumberOfLeadingZeros(invoke, Primitive::kPrimLong, codegen_);
+  GenNumberOfLeadingZeros(invoke, DataType::Type::kInt64, codegen_);
 }
 
 static void GenNumberOfTrailingZeros(HInvoke* invoke,
-                                     Primitive::Type type,
+                                     DataType::Type type,
                                      CodeGeneratorARMVIXL* codegen) {
-  DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong));
+  DCHECK((type == DataType::Type::kInt32) || (type == DataType::Type::kInt64));
 
   ArmVIXLAssembler* assembler = codegen->GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
   vixl32::Register out = RegisterFrom(locations->Out());
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     vixl32::Register in_reg_lo = LowRegisterFrom(locations->InAt(0));
     vixl32::Register in_reg_hi = HighRegisterFrom(locations->InAt(0));
     vixl32::Label end;
@@ -426,7 +426,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
-  GenNumberOfTrailingZeros(invoke, Primitive::kPrimInt, codegen_);
+  GenNumberOfTrailingZeros(invoke, DataType::Type::kInt32, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
@@ -434,7 +434,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
-  GenNumberOfTrailingZeros(invoke, Primitive::kPrimLong, codegen_);
+  GenNumberOfTrailingZeros(invoke, DataType::Type::kInt64, codegen_);
 }
 
 static void MathAbsFP(HInvoke* invoke, ArmVIXLAssembler* assembler) {
@@ -963,7 +963,7 @@
 }
 
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          CodeGeneratorARMVIXL* codegen) {
   LocationSummary* locations = invoke->GetLocations();
@@ -975,7 +975,7 @@
   Location trg_loc = locations->Out();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       vixl32::Register trg = RegisterFrom(trg_loc);
       __ Ldr(trg, MemOperand(base, offset));
       if (is_volatile) {
@@ -984,7 +984,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       vixl32::Register trg = RegisterFrom(trg_loc);
       if (kEmitCompilerReadBarrier) {
         if (kUseBakerReadBarrier) {
@@ -1011,7 +1011,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       vixl32::Register trg_lo = LowRegisterFrom(trg_loc);
       vixl32::Register trg_hi = HighRegisterFrom(trg_loc);
       if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) {
@@ -1036,7 +1036,7 @@
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
                                           HInvoke* invoke,
-                                          Primitive::Type type) {
+                                          DataType::Type type) {
   bool can_call = kEmitCompilerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
@@ -1053,7 +1053,7 @@
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(),
                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // We need a temporary register for the read barrier marking slow
     // path in CodeGeneratorARMVIXL::GenerateReferenceLoadWithBakerReadBarrier.
     locations->AddTemp(Location::RequiresRegister());
@@ -1061,46 +1061,46 @@
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGet(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetLong(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetObject(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 
 static void CreateIntIntIntIntToVoid(ArenaAllocator* arena,
                                      const ArmInstructionSetFeatures& features,
-                                     Primitive::Type type,
+                                     DataType::Type type,
                                      bool is_volatile,
                                      HInvoke* invoke) {
   LocationSummary* locations = new (arena) LocationSummary(invoke,
@@ -1111,13 +1111,13 @@
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetInAt(3, Location::RequiresRegister());
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     // Potentially need temps for ldrexd-strexd loop.
     if (is_volatile && !features.HasAtomicLdrdAndStrd()) {
       locations->AddTemp(Location::RequiresRegister());  // Temp_lo.
       locations->AddTemp(Location::RequiresRegister());  // Temp_hi.
     }
-  } else if (type == Primitive::kPrimNot) {
+  } else if (type == DataType::Type::kReference) {
     // Temps for card-marking.
     locations->AddTemp(Location::RequiresRegister());  // Temp.
     locations->AddTemp(Location::RequiresRegister());  // Card.
@@ -1125,38 +1125,44 @@
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePut(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kInt32, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutOrdered(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kInt32, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutVolatile(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ true, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kInt32, /* is_volatile */ true, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutObject(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kReference, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kReference, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ true, invoke);
+  CreateIntIntIntIntToVoid(
+      arena_, features_, DataType::Type::kReference, /* is_volatile */ true, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutLong(HInvoke* invoke) {
   CreateIntIntIntIntToVoid(
-      arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke);
+      arena_, features_, DataType::Type::kInt64, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   CreateIntIntIntIntToVoid(
-      arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke);
+      arena_, features_, DataType::Type::kInt64, /* is_volatile */ false, invoke);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   CreateIntIntIntIntToVoid(
-      arena_, features_, Primitive::kPrimLong, /* is_volatile */ true, invoke);
+      arena_, features_, DataType::Type::kInt64, /* is_volatile */ true, invoke);
 }
 
 static void GenUnsafePut(LocationSummary* locations,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          bool is_ordered,
                          CodeGeneratorARMVIXL* codegen) {
@@ -1170,7 +1176,7 @@
     __ Dmb(vixl32::ISH);
   }
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     vixl32::Register value_lo = LowRegisterFrom(locations->InAt(3));
     vixl32::Register value_hi = HighRegisterFrom(locations->InAt(3));
     value = value_lo;
@@ -1193,7 +1199,7 @@
   } else {
     value = RegisterFrom(locations->InAt(3));
     vixl32::Register source = value;
-    if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    if (kPoisonHeapReferences && type == DataType::Type::kReference) {
       vixl32::Register temp = RegisterFrom(locations->GetTemp(0));
       __ Mov(temp, value);
       assembler->PoisonHeapReference(temp);
@@ -1206,7 +1212,7 @@
     __ Dmb(vixl32::ISH);
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     vixl32::Register temp = RegisterFrom(locations->GetTemp(0));
     vixl32::Register card = RegisterFrom(locations->GetTemp(1));
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
@@ -1216,63 +1222,63 @@
 
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutObject(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutLong(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
@@ -1280,7 +1286,7 @@
 
 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena,
                                                 HInvoke* invoke,
-                                                Primitive::Type type) {
+                                                DataType::Type type) {
   bool can_call = kEmitCompilerReadBarrier &&
       kUseBakerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
@@ -1299,7 +1305,7 @@
   // operations to potentially clobber the output. Likewise when
   // emitting a (Baker) read barrier, which may call.
   Location::OutputOverlap overlaps =
-      ((kPoisonHeapReferences && type == Primitive::kPrimNot) || can_call)
+      ((kPoisonHeapReferences && type == DataType::Type::kReference) || can_call)
       ? Location::kOutputOverlap
       : Location::kNoOutputOverlap;
   locations->SetOut(Location::RequiresRegister(), overlaps);
@@ -1311,8 +1317,8 @@
   locations->AddTemp(Location::RequiresRegister());  // Temp 1.
 }
 
-static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorARMVIXL* codegen) {
-  DCHECK_NE(type, Primitive::kPrimLong);
+static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorARMVIXL* codegen) {
+  DCHECK_NE(type, DataType::Type::kInt64);
 
   ArmVIXLAssembler* assembler = codegen->GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
@@ -1330,7 +1336,7 @@
   vixl32::Register tmp_ptr = RegisterFrom(tmp_ptr_loc);               // Pointer to actual memory.
   vixl32::Register tmp = RegisterFrom(locations->GetTemp(1));         // Value in memory.
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // The only read barrier implementation supporting the
     // UnsafeCASObject intrinsic is the Baker-style read barriers.
     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
@@ -1362,7 +1368,7 @@
 
   __ Add(tmp_ptr, base, offset);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     codegen->GetAssembler()->PoisonHeapReference(expected);
     if (value.Is(expected)) {
       // Do not poison `value`, as it is the same register as
@@ -1409,7 +1415,7 @@
     __ mov(cc, out, 0);
   }
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     codegen->GetAssembler()->UnpoisonHeapReference(expected);
     if (value.Is(expected)) {
       // Do not unpoison `value`, as it is the same register as
@@ -1421,7 +1427,7 @@
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeCASInt(HInvoke* invoke) {
-  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, DataType::Type::kInt32);
 }
 void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeCASObject(HInvoke* invoke) {
   // The only read barrier implementation supporting the
@@ -1430,17 +1436,17 @@
     return;
   }
 
-  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, DataType::Type::kReference);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimInt, codegen_);
+  GenCas(invoke, DataType::Type::kInt32, codegen_);
 }
 void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeCASObject(HInvoke* invoke) {
   // The only read barrier implementation supporting the
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCas(invoke, Primitive::kPrimNot, codegen_);
+  GenCas(invoke, DataType::Type::kReference, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitStringCompareTo(HInvoke* invoke) {
@@ -1558,7 +1564,7 @@
   static_assert(IsAligned<8>(kObjectAlignment),
                 "String data must be 8-byte aligned for unrolled CompareTo loop.");
 
-  const unsigned char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const unsigned char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
@@ -1645,7 +1651,7 @@
     __ Bind(&different_compression);
 
     // Comparison for different compression style.
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
 
     // We want to free up the temp3, currently holding `str.count`, for comparison.
@@ -1943,7 +1949,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     vixl32::Register char_reg = InputRegisterAt(invoke, 1);
     // 0xffff is not modified immediate but 0x10000 is, so use `>= 0x10000` instead of `> 0xffff`.
     __ Cmp(char_reg, static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()) + 1);
@@ -2450,8 +2456,8 @@
     // Null constant length: not need to emit the loop code at all.
   } else {
     vixl32::Label done;
-    const Primitive::Type type = Primitive::kPrimNot;
-    const int32_t element_size = Primitive::ComponentSize(type);
+    const DataType::Type type = DataType::Type::kReference;
+    const int32_t element_size = DataType::Size(type);
 
     if (length.IsRegister()) {
       // Don't enter the copy loop if the length is null.
@@ -2576,8 +2582,8 @@
   }
 
   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
-  DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
-  DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+  DCHECK_EQ(invoke->InputAt(0)->GetType(), DataType::Type::kFloat64);
+  DCHECK_EQ(invoke->GetType(), DataType::Type::kFloat64);
 
   LocationSummary* const locations = new (arena) LocationSummary(invoke,
                                                                  LocationSummary::kCallOnMainOnly,
@@ -2602,9 +2608,9 @@
   }
 
   DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
-  DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
-  DCHECK_EQ(invoke->InputAt(1)->GetType(), Primitive::kPrimDouble);
-  DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+  DCHECK_EQ(invoke->InputAt(0)->GetType(), DataType::Type::kFloat64);
+  DCHECK_EQ(invoke->InputAt(1)->GetType(), DataType::Type::kFloat64);
+  DCHECK_EQ(invoke->GetType(), DataType::Type::kFloat64);
 
   LocationSummary* const locations = new (arena) LocationSummary(invoke,
                                                                  LocationSummary::kCallOnMainOnly,
@@ -2859,12 +2865,12 @@
   __ Revsh(OutputRegister(invoke), InputRegisterAt(invoke, 0));
 }
 
-static void GenBitCount(HInvoke* instr, Primitive::Type type, ArmVIXLAssembler* assembler) {
-  DCHECK(Primitive::IsIntOrLongType(type)) << type;
-  DCHECK_EQ(instr->GetType(), Primitive::kPrimInt);
-  DCHECK_EQ(Primitive::PrimitiveKind(instr->InputAt(0)->GetType()), type);
+static void GenBitCount(HInvoke* instr, DataType::Type type, ArmVIXLAssembler* assembler) {
+  DCHECK(DataType::IsIntOrLongType(type)) << type;
+  DCHECK_EQ(instr->GetType(), DataType::Type::kInt32);
+  DCHECK_EQ(DataType::Kind(instr->InputAt(0)->GetType()), type);
 
-  bool is_long = type == Primitive::kPrimLong;
+  bool is_long = type == DataType::Type::kInt64;
   LocationSummary* locations = instr->GetLocations();
   Location in = locations->InAt(0);
   vixl32::Register src_0 = is_long ? LowRegisterFrom(in) : RegisterFrom(in);
@@ -2893,7 +2899,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, Primitive::kPrimInt, GetAssembler());
+  GenBitCount(invoke, DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitLongBitCount(HInvoke* invoke) {
@@ -2901,19 +2907,19 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, Primitive::kPrimLong, GetAssembler());
+  GenBitCount(invoke, DataType::Type::kInt64, GetAssembler());
 }
 
 static void GenHighestOneBit(HInvoke* invoke,
-                             Primitive::Type type,
+                             DataType::Type type,
                              CodeGeneratorARMVIXL* codegen) {
-  DCHECK(Primitive::IsIntOrLongType(type));
+  DCHECK(DataType::IsIntOrLongType(type));
 
   ArmVIXLAssembler* assembler = codegen->GetAssembler();
   UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
   const vixl32::Register temp = temps.Acquire();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     LocationSummary* locations = invoke->GetLocations();
     Location in = locations->InAt(0);
     Location out = locations->Out();
@@ -2959,7 +2965,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitIntegerHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke, Primitive::kPrimInt, codegen_);
+  GenHighestOneBit(invoke, DataType::Type::kInt32, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitLongHighestOneBit(HInvoke* invoke) {
@@ -2967,19 +2973,19 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitLongHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke, Primitive::kPrimLong, codegen_);
+  GenHighestOneBit(invoke, DataType::Type::kInt64, codegen_);
 }
 
 static void GenLowestOneBit(HInvoke* invoke,
-                            Primitive::Type type,
+                            DataType::Type type,
                             CodeGeneratorARMVIXL* codegen) {
-  DCHECK(Primitive::IsIntOrLongType(type));
+  DCHECK(DataType::IsIntOrLongType(type));
 
   ArmVIXLAssembler* assembler = codegen->GetAssembler();
   UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
   const vixl32::Register temp = temps.Acquire();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     LocationSummary* locations = invoke->GetLocations();
     Location in = locations->InAt(0);
     Location out = locations->Out();
@@ -3024,7 +3030,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitIntegerLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke, Primitive::kPrimInt, codegen_);
+  GenLowestOneBit(invoke, DataType::Type::kInt32, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitLongLowestOneBit(HInvoke* invoke) {
@@ -3032,7 +3038,7 @@
 }
 
 void IntrinsicCodeGeneratorARMVIXL::VisitLongLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke, Primitive::kPrimLong, codegen_);
+  GenLowestOneBit(invoke, DataType::Type::kInt64, codegen_);
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitStringGetCharsNoCheck(HInvoke* invoke) {
@@ -3056,7 +3062,7 @@
   LocationSummary* locations = invoke->GetLocations();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   // Location of data in char array buffer.
@@ -3144,7 +3150,7 @@
   if (mirror::kUseStringCompression) {
     __ B(final_label);
 
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
     // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
     __ Bind(&compressed_string_preloop);
@@ -3285,7 +3291,7 @@
     uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
     uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
     __ Ldr(temp, codegen_->DeduplicateBootImageAddressLiteral(data_offset + address));
-    codegen_->LoadFromShiftedRegOffset(Primitive::kPrimNot, locations->Out(), temp, out);
+    codegen_->LoadFromShiftedRegOffset(DataType::Type::kReference, locations->Out(), temp, out);
     assembler->MaybeUnpoisonHeapReference(out);
     __ B(&done);
     __ Bind(&allocate);
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index fe5579c..8847256 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -61,16 +61,16 @@
 #define __ codegen->GetAssembler()->
 
 static void MoveFromReturnRegister(Location trg,
-                                   Primitive::Type type,
+                                   DataType::Type type,
                                    CodeGeneratorMIPS* codegen) {
   if (!trg.IsValid()) {
-    DCHECK_EQ(type, Primitive::kPrimVoid);
+    DCHECK_EQ(type, DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
-  if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
+  if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
     Register trg_reg = trg.AsRegister<Register>();
     if (trg_reg != V0) {
       __ Move(V0, trg_reg);
@@ -78,7 +78,7 @@
   } else {
     FRegister trg_reg = trg.AsFpuRegister<FRegister>();
     if (trg_reg != F0) {
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ MovS(F0, trg_reg);
       } else {
         __ MovD(F0, trg_reg);
@@ -247,17 +247,17 @@
 }
 
 static void GenReverse(LocationSummary* locations,
-                       Primitive::Type type,
+                       DataType::Type type,
                        bool isR2OrNewer,
                        bool isR6,
                        bool reverseBits,
                        MipsAssembler* assembler) {
-  DCHECK(type == Primitive::kPrimShort ||
-         type == Primitive::kPrimInt ||
-         type == Primitive::kPrimLong);
-  DCHECK(type != Primitive::kPrimShort || !reverseBits);
+  DCHECK(type == DataType::Type::kInt16 ||
+         type == DataType::Type::kInt32 ||
+         type == DataType::Type::kInt64);
+  DCHECK(type != DataType::Type::kInt16 || !reverseBits);
 
-  if (type == Primitive::kPrimShort) {
+  if (type == DataType::Type::kInt16) {
     Register in = locations->InAt(0).AsRegister<Register>();
     Register out = locations->Out().AsRegister<Register>();
 
@@ -271,7 +271,7 @@
       __ Srl(out, out, 24);
       __ Or(out, out, TMP);
     }
-  } else if (type == Primitive::kPrimInt) {
+  } else if (type == DataType::Type::kInt32) {
     Register in = locations->InAt(0).AsRegister<Register>();
     Register out = locations->Out().AsRegister<Register>();
 
@@ -316,7 +316,7 @@
         __ Or(out, TMP, out);
       }
     }
-  } else if (type == Primitive::kPrimLong) {
+  } else if (type == DataType::Type::kInt64) {
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
@@ -407,7 +407,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
   GenReverse(invoke->GetLocations(),
-             Primitive::kPrimInt,
+             DataType::Type::kInt32,
              IsR2OrNewer(),
              IsR6(),
              /* reverseBits */ false,
@@ -421,7 +421,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) {
   GenReverse(invoke->GetLocations(),
-             Primitive::kPrimLong,
+             DataType::Type::kInt64,
              IsR2OrNewer(),
              IsR6(),
              /* reverseBits */ false,
@@ -435,7 +435,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) {
   GenReverse(invoke->GetLocations(),
-             Primitive::kPrimShort,
+             DataType::Type::kInt16,
              IsR2OrNewer(),
              IsR6(),
              /* reverseBits */ false,
@@ -584,7 +584,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) {
   GenReverse(invoke->GetLocations(),
-             Primitive::kPrimInt,
+             DataType::Type::kInt32,
              IsR2OrNewer(),
              IsR6(),
              /* reverseBits */ true,
@@ -598,7 +598,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
   GenReverse(invoke->GetLocations(),
-             Primitive::kPrimLong,
+             DataType::Type::kInt64,
              IsR2OrNewer(),
              IsR6(),
              /* reverseBits */ true,
@@ -614,7 +614,7 @@
 }
 
 static void GenBitCount(LocationSummary* locations,
-                        Primitive::Type type,
+                        DataType::Type type,
                         bool isR6,
                         MipsAssembler* assembler) {
   Register out = locations->Out().AsRegister<Register>();
@@ -641,7 +641,7 @@
   // instructions compared to a loop-based algorithm which required 47
   // instructions.
 
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     Register in = locations->InAt(0).AsRegister<Register>();
 
     __ Srl(TMP, in, 1);
@@ -665,7 +665,7 @@
     }
     __ Srl(out, out, 24);
   } else {
-    DCHECK_EQ(type, Primitive::kPrimLong);
+    DCHECK_EQ(type, DataType::Type::kInt64);
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
     Register tmp_hi = locations->GetTemp(0).AsRegister<Register>();
@@ -729,7 +729,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
+  GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
 }
 
 // int java.lang.Long.bitCount(int)
@@ -744,7 +744,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
+  GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
 }
 
 static void MathAbsFP(LocationSummary* locations,
@@ -865,7 +865,7 @@
 
 static void GenMinMaxFP(LocationSummary* locations,
                         bool is_min,
-                        Primitive::Type type,
+                        DataType::Type type,
                         bool is_R6,
                         MipsAssembler* assembler) {
   FRegister out = locations->Out().AsFpuRegister<FRegister>();
@@ -884,7 +884,7 @@
     // returned. This is why there is extra logic preceding the use of
     // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
     // NaN, return the NaN, otherwise return the min/max.
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ CmpUnD(FTMP, a, b);
       __ Bc1eqz(FTMP, &noNaNs);
 
@@ -907,7 +907,7 @@
         __ MaxD(out, a, b);
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimFloat);
+      DCHECK_EQ(type, DataType::Type::kFloat32);
       __ CmpUnS(FTMP, a, b);
       __ Bc1eqz(FTMP, &noNaNs);
 
@@ -938,16 +938,16 @@
     MipsLabel select;
     MipsLabel done;
 
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ CunD(a, b);
     } else {
-      DCHECK_EQ(type, Primitive::kPrimFloat);
+      DCHECK_EQ(type, DataType::Type::kFloat32);
       __ CunS(a, b);
     }
     __ Bc1f(&ordered);
 
     // a or b (or both) is a NaN. Return one, which is a NaN.
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ CeqD(b, b);
     } else {
       __ CeqS(b, b);
@@ -959,7 +959,7 @@
     // Neither is a NaN.
     // a == b? (-0.0 compares equal with +0.0)
     // If equal, handle zeroes, else compare further.
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ CeqD(a, b);
     } else {
       __ CeqS(a, b);
@@ -967,7 +967,7 @@
     __ Bc1f(&compare);
 
     // a == b either bit for bit or one is -0.0 and the other is +0.0.
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ MoveFromFpuHigh(TMP, a);
       __ MoveFromFpuHigh(AT, b);
     } else {
@@ -983,7 +983,7 @@
       __ And(TMP, TMP, AT);
     }
 
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ Mfc1(AT, a);
       __ Mtc1(AT, out);
       __ MoveToFpuHigh(TMP, out);
@@ -994,7 +994,7 @@
 
     __ Bind(&compare);
 
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       if (is_min) {
         // return (a <= b) ? a : b;
         __ ColeD(a, b);
@@ -1014,7 +1014,7 @@
 
     __ Bind(&select);
 
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ MovtD(out, a);
       __ MovfD(out, b);
     } else {
@@ -1043,7 +1043,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
   GenMinMaxFP(invoke->GetLocations(),
               /* is_min */ true,
-              Primitive::kPrimDouble,
+              DataType::Type::kFloat64,
               IsR6(),
               GetAssembler());
 }
@@ -1056,7 +1056,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
   GenMinMaxFP(invoke->GetLocations(),
               /* is_min */ true,
-              Primitive::kPrimFloat,
+              DataType::Type::kFloat32,
               IsR6(),
               GetAssembler());
 }
@@ -1069,7 +1069,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
   GenMinMaxFP(invoke->GetLocations(),
               /* is_min */ false,
-              Primitive::kPrimDouble,
+              DataType::Type::kFloat64,
               IsR6(),
               GetAssembler());
 }
@@ -1082,7 +1082,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
   GenMinMaxFP(invoke->GetLocations(),
               /* is_min */ false,
-              Primitive::kPrimFloat,
+              DataType::Type::kFloat32,
               IsR6(),
               GetAssembler());
 }
@@ -1098,7 +1098,7 @@
 
 static void GenMinMax(LocationSummary* locations,
                       bool is_min,
-                      Primitive::Type type,
+                      DataType::Type type,
                       bool is_R6,
                       MipsAssembler* assembler) {
   if (is_R6) {
@@ -1125,7 +1125,7 @@
     // as the output register; the else clause also handles the case
     // where the output register is distinct from both the first, and the
     // second input registers.
-    if (type == Primitive::kPrimLong) {
+    if (type == DataType::Type::kInt64) {
       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
@@ -1168,7 +1168,7 @@
         __ Or(out_hi, out_hi, AT);
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimInt);
+      DCHECK_EQ(type, DataType::Type::kInt32);
       Register a = locations->InAt(0).AsRegister<Register>();
       Register b = locations->InAt(1).AsRegister<Register>();
       Register out = locations->Out().AsRegister<Register>();
@@ -1190,7 +1190,7 @@
       }
     }
   } else {
-    if (type == Primitive::kPrimLong) {
+    if (type == DataType::Type::kInt64) {
       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
@@ -1234,7 +1234,7 @@
         }
       }
     } else {
-      DCHECK_EQ(type, Primitive::kPrimInt);
+      DCHECK_EQ(type, DataType::Type::kInt32);
       Register a = locations->InAt(0).AsRegister<Register>();
       Register b = locations->InAt(1).AsRegister<Register>();
       Register out = locations->Out().AsRegister<Register>();
@@ -1273,7 +1273,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMinIntInt(HInvoke* invoke) {
   GenMinMax(invoke->GetLocations(),
             /* is_min */ true,
-            Primitive::kPrimInt,
+            DataType::Type::kInt32,
             IsR6(),
             GetAssembler());
 }
@@ -1286,7 +1286,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMinLongLong(HInvoke* invoke) {
   GenMinMax(invoke->GetLocations(),
             /* is_min */ true,
-            Primitive::kPrimLong,
+            DataType::Type::kInt64,
             IsR6(),
             GetAssembler());
 }
@@ -1299,7 +1299,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
   GenMinMax(invoke->GetLocations(),
             /* is_min */ false,
-            Primitive::kPrimInt,
+            DataType::Type::kInt32,
             IsR6(),
             GetAssembler());
 }
@@ -1312,7 +1312,7 @@
 void IntrinsicCodeGeneratorMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
   GenMinMax(invoke->GetLocations(),
             /* is_min */ false,
-            Primitive::kPrimLong,
+            DataType::Type::kInt64,
             IsR6(),
             GetAssembler());
 }
@@ -1519,7 +1519,7 @@
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
                                           HInvoke* invoke,
-                                          Primitive::Type type) {
+                                          DataType::Type type) {
   bool can_call = kEmitCompilerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
@@ -1536,7 +1536,7 @@
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(),
                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // We need a temporary register for the read barrier marking slow
     // path in InstructionCodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier.
     locations->AddTemp(Location::RequiresRegister());
@@ -1546,14 +1546,14 @@
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          bool is_R6,
                          CodeGeneratorMIPS* codegen) {
   LocationSummary* locations = invoke->GetLocations();
-  DCHECK((type == Primitive::kPrimInt) ||
-         (type == Primitive::kPrimLong) ||
-         (type == Primitive::kPrimNot)) << type;
+  DCHECK((type == DataType::Type::kInt32) ||
+         (type == DataType::Type::kInt64) ||
+         (type == DataType::Type::kReference)) << type;
   MipsAssembler* assembler = codegen->GetAssembler();
   // Target register.
   Location trg_loc = locations->Out();
@@ -1566,12 +1566,12 @@
   Location offset_loc = locations->InAt(2);
   Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
 
-  if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
+  if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == DataType::Type::kReference))) {
     __ Addu(TMP, base, offset_lo);
   }
 
   switch (type) {
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
       Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
       CHECK(!is_volatile);  // TODO: support atomic 8-byte volatile loads.
@@ -1587,7 +1587,7 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register trg = trg_loc.AsRegister<Register>();
       if (is_R6) {
         __ Lw(trg, TMP, 0);
@@ -1601,7 +1601,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       Register trg = trg_loc.AsRegister<Register>();
       if (kEmitCompilerReadBarrier) {
         if (kUseBakerReadBarrier) {
@@ -1657,47 +1657,47 @@
 
 // int sun.misc.Unsafe.getInt(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGet(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, IsR6(), codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, IsR6(), codegen_);
 }
 
 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, IsR6(), codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, IsR6(), codegen_);
 }
 
 // long sun.misc.Unsafe.getLong(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64);
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, IsR6(), codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, IsR6(), codegen_);
 }
 
 // Object sun.misc.Unsafe.getObject(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, IsR6(), codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, IsR6(), codegen_);
 }
 
 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, IsR6(), codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, IsR6(), codegen_);
 }
 
 static void CreateIntIntIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -1713,14 +1713,14 @@
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
 static void GenUnsafePut(LocationSummary* locations,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          bool is_ordered,
                          bool is_R6,
                          CodeGeneratorMIPS* codegen) {
-  DCHECK((type == Primitive::kPrimInt) ||
-         (type == Primitive::kPrimLong) ||
-         (type == Primitive::kPrimNot)) << type;
+  DCHECK((type == DataType::Type::kInt32) ||
+         (type == DataType::Type::kInt64) ||
+         (type == DataType::Type::kReference)) << type;
   MipsAssembler* assembler = codegen->GetAssembler();
   // Object pointer.
   Register base = locations->InAt(1).AsRegister<Register>();
@@ -1733,10 +1733,10 @@
   if (is_volatile || is_ordered) {
     __ Sync(0);
   }
-  if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
+  if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
     Register value = locations->InAt(3).AsRegister<Register>();
 
-    if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    if (kPoisonHeapReferences && type == DataType::Type::kReference) {
       __ PoisonHeapReference(AT, value);
       value = AT;
     }
@@ -1766,7 +1766,7 @@
     __ Sync(0);
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(base, locations->InAt(3).AsRegister<Register>(), value_can_be_null);
   }
@@ -1779,7 +1779,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ false,
                IsR6(),
@@ -1793,7 +1793,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ true,
                IsR6(),
@@ -1807,7 +1807,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ true,
                /* is_ordered */ false,
                IsR6(),
@@ -1821,7 +1821,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObject(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ false,
                IsR6(),
@@ -1835,7 +1835,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ true,
                IsR6(),
@@ -1849,7 +1849,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ true,
                /* is_ordered */ false,
                IsR6(),
@@ -1863,7 +1863,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLong(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ false,
                IsR6(),
@@ -1877,7 +1877,7 @@
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ true,
                IsR6(),
@@ -1908,7 +1908,7 @@
 
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
-static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS* codegen) {
+static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorMIPS* codegen) {
   MipsAssembler* assembler = codegen->GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
   bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
@@ -1924,7 +1924,7 @@
   DCHECK_NE(offset_lo, out);
   DCHECK_NE(expected, out);
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // The only read barrier implementation supporting the
     // UnsafeCASObject intrinsic is the Baker-style read barriers.
     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
@@ -1954,7 +1954,7 @@
   MipsLabel loop_head, exit_loop;
   __ Addu(TMP, base, offset_lo);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     __ PoisonHeapReference(expected);
     // Do not poison `value`, if it is the same register as
     // `expected`, which has just been poisoned.
@@ -1970,7 +1970,7 @@
 
   __ Sync(0);
   __ Bind(&loop_head);
-  if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
+  if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
     if (isR6) {
       __ LlR6(out, TMP);
     } else {
@@ -1988,11 +1988,11 @@
                         // in the case that the store fails.  Whether the
                         // store succeeds, or fails, it will load the
                         // correct Boolean value into the 'out' register.
-  // This test isn't really necessary. We only support Primitive::kPrimInt,
-  // Primitive::kPrimNot, and we already verified that we're working on one
+  // This test isn't really necessary. We only support DataType::Type::kInt,
+  // DataType::Type::kReference, and we already verified that we're working on one
   // of those two types. It's left here in case the code needs to support
   // other types in the future.
-  if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
+  if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
     if (isR6) {
       __ ScR6(out, TMP);
     } else {
@@ -2004,7 +2004,7 @@
   __ Bind(&exit_loop);
   __ Sync(0);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     __ UnpoisonHeapReference(expected);
     // Do not unpoison `value`, if it is the same register as
     // `expected`, which has just been unpoisoned.
@@ -2020,7 +2020,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimInt, codegen_);
+  GenCas(invoke, DataType::Type::kInt32, codegen_);
 }
 
 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
@@ -2039,7 +2039,7 @@
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCas(invoke, Primitive::kPrimNot, codegen_);
+  GenCas(invoke, DataType::Type::kReference, codegen_);
 }
 
 // int java.lang.String.compareTo(String anotherString)
@@ -2050,7 +2050,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 }
 
@@ -2218,7 +2218,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     Register char_reg = locations->InAt(1).AsRegister<Register>();
     // The "bltu" conditional branch tests to see if the character value
     // fits in a valid 16-bit (MIPS halfword) value. If it doesn't then
@@ -2256,7 +2256,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 
   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
@@ -2282,7 +2282,7 @@
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 
   // Need a temp for slow-path codepoint compare.
@@ -2307,7 +2307,7 @@
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 }
 
@@ -2332,7 +2332,7 @@
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 }
 
@@ -2353,7 +2353,7 @@
                                                             kIntrinsified);
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
 }
 
@@ -2370,16 +2370,16 @@
 }
 
 static void GenIsInfinite(LocationSummary* locations,
-                          const Primitive::Type type,
+                          const DataType::Type type,
                           const bool isR6,
                           MipsAssembler* assembler) {
   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
   Register out = locations->Out().AsRegister<Register>();
 
-  DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
+  DCHECK(type == DataType::Type::kFloat32 || type == DataType::Type::kFloat64);
 
   if (isR6) {
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
         __ ClassD(FTMP, in);
     } else {
         __ ClassS(FTMP, in);
@@ -2389,7 +2389,7 @@
     __ Sltu(out, ZERO, out);
   } else {
     // If one, or more, of the exponent bits is zero, then the number can't be infinite.
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ MoveFromFpuHigh(TMP, in);
       __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble));
     } else {
@@ -2400,7 +2400,7 @@
 
     __ Sll(TMP, TMP, 1);
 
-    if (type == Primitive::kPrimDouble) {
+    if (type == DataType::Type::kFloat64) {
       __ Mfc1(AT, in);
       __ Or(TMP, TMP, AT);
     }
@@ -2415,7 +2415,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
-  GenIsInfinite(invoke->GetLocations(), Primitive::kPrimFloat, IsR6(), GetAssembler());
+  GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat32, IsR6(), GetAssembler());
 }
 
 // boolean java.lang.Double.isInfinite(double)
@@ -2424,16 +2424,16 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
-  GenIsInfinite(invoke->GetLocations(), Primitive::kPrimDouble, IsR6(), GetAssembler());
+  GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat64, IsR6(), GetAssembler());
 }
 
 static void GenHighestOneBit(LocationSummary* locations,
-                             const Primitive::Type type,
+                             const DataType::Type type,
                              bool isR6,
                              MipsAssembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
@@ -2480,7 +2480,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
+  GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
 }
 
 // long java.lang.Long.highestOneBit(long)
@@ -2489,16 +2489,16 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
+  GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
 }
 
 static void GenLowestOneBit(LocationSummary* locations,
-                            const Primitive::Type type,
+                            const DataType::Type type,
                             bool isR6,
                             MipsAssembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
@@ -2528,7 +2528,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
+  GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
 }
 
 // long java.lang.Long.lowestOneBit(long)
@@ -2537,7 +2537,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
+  GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
 }
 
 // int java.lang.Math.round(float)
@@ -2686,9 +2686,9 @@
   LocationSummary* locations = invoke->GetLocations();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
-  const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+  const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
 
   Register srcObj = locations->InAt(0).AsRegister<Register>();
   Register srcBegin = locations->InAt(1).AsRegister<Register>();
@@ -2764,7 +2764,7 @@
   InvokeRuntimeCallingConvention calling_convention;
 
   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
 }
 
 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -2775,7 +2775,7 @@
 
   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
 }
 
 static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
@@ -3112,10 +3112,10 @@
 
   // Okay, everything checks out.  Finally time to do the copy.
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
-  const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+  const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
 
   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
 
@@ -3154,7 +3154,7 @@
   IntrinsicVisitor::ComputeIntegerValueOfLocations(
       invoke,
       codegen_,
-      calling_convention.GetReturnLocation(Primitive::kPrimNot),
+      calling_convention.GetReturnLocation(DataType::Type::kReference),
       Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
 }
 
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 80448f1..d0234d8 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -49,16 +49,16 @@
 #define __ codegen->GetAssembler()->
 
 static void MoveFromReturnRegister(Location trg,
-                                   Primitive::Type type,
+                                   DataType::Type type,
                                    CodeGeneratorMIPS64* codegen) {
   if (!trg.IsValid()) {
-    DCHECK_EQ(type, Primitive::kPrimVoid);
+    DCHECK_EQ(type, DataType::Type::kVoid);
     return;
   }
 
-  DCHECK_NE(type, Primitive::kPrimVoid);
+  DCHECK_NE(type, DataType::Type::kVoid);
 
-  if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
+  if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
     GpuRegister trg_reg = trg.AsRegister<GpuRegister>();
     if (trg_reg != V0) {
       __ Move(V0, trg_reg);
@@ -66,7 +66,7 @@
   } else {
     FpuRegister trg_reg = trg.AsFpuRegister<FpuRegister>();
     if (trg_reg != F0) {
-      if (type == Primitive::kPrimFloat) {
+      if (type == DataType::Type::kFloat32) {
         __ MovS(F0, trg_reg);
       } else {
         __ MovD(F0, trg_reg);
@@ -224,21 +224,21 @@
 }
 
 static void GenReverseBytes(LocationSummary* locations,
-                            Primitive::Type type,
+                            DataType::Type type,
                             Mips64Assembler* assembler) {
   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
 
   switch (type) {
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ Dsbh(out, in);
       __ Seh(out, out);
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ Rotr(out, in, 16);
       __ Wsbh(out, out);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ Dsbh(out, in);
       __ Dshd(out, out);
       break;
@@ -254,7 +254,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 // long java.lang.Long.reverseBytes(long)
@@ -263,7 +263,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 // short java.lang.Short.reverseBytes(short)
@@ -272,7 +272,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 static void GenNumberOfLeadingZeroes(LocationSummary* locations,
@@ -344,14 +344,14 @@
 }
 
 static void GenReverse(LocationSummary* locations,
-                       Primitive::Type type,
+                       DataType::Type type,
                        Mips64Assembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
 
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     __ Rotr(out, in, 16);
     __ Wsbh(out, out);
     __ Bitswap(out, out);
@@ -368,7 +368,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverse(HInvoke* invoke) {
-  GenReverse(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenReverse(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 // long java.lang.Long.reverse(long)
@@ -377,7 +377,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitLongReverse(HInvoke* invoke) {
-  GenReverse(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenReverse(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -389,12 +389,12 @@
 }
 
 static void GenBitCount(LocationSummary* locations,
-                        const Primitive::Type type,
+                        const DataType::Type type,
                         Mips64Assembler* assembler) {
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
 
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
 
   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
   //
@@ -419,7 +419,7 @@
   // number of instructions executed even when a large number of bits
   // are set.
 
-  if (type == Primitive::kPrimInt) {
+  if (type == DataType::Type::kInt32) {
     __ Srl(TMP, in, 1);
     __ LoadConst32(AT, 0x55555555);
     __ And(TMP, TMP, AT);
@@ -436,7 +436,7 @@
     __ LoadConst32(TMP, 0x01010101);
     __ MulR6(out, out, TMP);
     __ Srl(out, out, 24);
-  } else if (type == Primitive::kPrimLong) {
+  } else if (type == DataType::Type::kInt64) {
     __ Dsrl(TMP, in, 1);
     __ LoadConst64(AT, 0x5555555555555555L);
     __ And(TMP, TMP, AT);
@@ -462,7 +462,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 // int java.lang.Long.bitCount(long)
@@ -471,7 +471,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 static void MathAbsFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
@@ -546,7 +546,7 @@
 
 static void GenMinMaxFP(LocationSummary* locations,
                         bool is_min,
-                        Primitive::Type type,
+                        DataType::Type type,
                         Mips64Assembler* assembler) {
   FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>();
   FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>();
@@ -563,7 +563,7 @@
   // returned. This is why there is extra logic preceding the use of
   // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
   // NaN, return the NaN, otherwise return the min/max.
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     __ CmpUnD(FTMP, a, b);
     __ Bc1eqz(FTMP, &noNaNs);
 
@@ -586,7 +586,7 @@
       __ MaxD(out, a, b);
     }
   } else {
-    DCHECK_EQ(type, Primitive::kPrimFloat);
+    DCHECK_EQ(type, DataType::Type::kFloat32);
     __ CmpUnS(FTMP, a, b);
     __ Bc1eqz(FTMP, &noNaNs);
 
@@ -628,7 +628,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimDouble, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat64, GetAssembler());
 }
 
 // float java.lang.Math.min(float, float)
@@ -637,7 +637,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimFloat, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat32, GetAssembler());
 }
 
 // double java.lang.Math.max(double, double)
@@ -646,7 +646,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimDouble, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat64, GetAssembler());
 }
 
 // float java.lang.Math.max(float, float)
@@ -655,7 +655,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimFloat, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat32, GetAssembler());
 }
 
 static void GenMinMax(LocationSummary* locations,
@@ -885,12 +885,12 @@
   GenRoundingMode(invoke->GetLocations(), kCeil, GetAssembler());
 }
 
-static void GenRound(LocationSummary* locations, Mips64Assembler* assembler, Primitive::Type type) {
+static void GenRound(LocationSummary* locations, Mips64Assembler* assembler, DataType::Type type) {
   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
   FpuRegister half = locations->GetTemp(0).AsFpuRegister<FpuRegister>();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
 
-  DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
+  DCHECK(type == DataType::Type::kFloat32 || type == DataType::Type::kFloat64);
 
   Mips64Label done;
 
@@ -903,7 +903,7 @@
   // return out;
 
   // out = floor(in);
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     __ FloorLD(FTMP, in);
     __ Dmfc1(out, FTMP);
   } else {
@@ -912,7 +912,7 @@
   }
 
   // if (out != MAX_VALUE && out != MIN_VALUE)
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     __ Daddiu(TMP, out, 1);
     __ Dati(TMP, 0x8000);  // TMP = out + 0x8000 0000 0000 0001
                            // or    out - 0x7FFF FFFF FFFF FFFF.
@@ -933,7 +933,7 @@
   }
 
   // TMP = (0.5 <= (in - out)) ? -1 : 0;
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     __ Cvtdl(FTMP, FTMP);  // Convert output of floor.l.d back to "double".
     __ LoadConst64(AT, bit_cast<int64_t, double>(0.5));
     __ SubD(FTMP, in, FTMP);
@@ -950,7 +950,7 @@
   }
 
   // Return out -= TMP.
-  if (type == Primitive::kPrimDouble) {
+  if (type == DataType::Type::kFloat64) {
     __ Dsubu(out, out, TMP);
   } else {
     __ Subu(out, out, TMP);
@@ -970,7 +970,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
-  GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimFloat);
+  GenRound(invoke->GetLocations(), GetAssembler(), DataType::Type::kFloat32);
 }
 
 // long java.lang.Math.round(double)
@@ -984,7 +984,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
-  GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimDouble);
+  GenRound(invoke->GetLocations(), GetAssembler(), DataType::Type::kFloat64);
 }
 
 // byte libcore.io.Memory.peekByte(long address)
@@ -1119,7 +1119,7 @@
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
                                           HInvoke* invoke,
-                                          Primitive::Type type) {
+                                          DataType::Type type) {
   bool can_call = kEmitCompilerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
@@ -1136,7 +1136,7 @@
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(),
                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
-  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
+  if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // We need a temporary register for the read barrier marking slow
     // path in InstructionCodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier.
     locations->AddTemp(Location::RequiresRegister());
@@ -1146,13 +1146,13 @@
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          CodeGeneratorMIPS64* codegen) {
   LocationSummary* locations = invoke->GetLocations();
-  DCHECK((type == Primitive::kPrimInt) ||
-         (type == Primitive::kPrimLong) ||
-         (type == Primitive::kPrimNot)) << type;
+  DCHECK((type == DataType::Type::kInt32) ||
+         (type == DataType::Type::kInt64) ||
+         (type == DataType::Type::kReference)) << type;
   Mips64Assembler* assembler = codegen->GetAssembler();
   // Target register.
   Location trg_loc = locations->Out();
@@ -1164,26 +1164,26 @@
   Location offset_loc = locations->InAt(2);
   GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
 
-  if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
+  if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == DataType::Type::kReference))) {
     __ Daddu(TMP, base, offset);
   }
 
   switch (type) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ Ld(trg, TMP, 0);
       if (is_volatile) {
         __ Sync(0);
       }
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ Lw(trg, TMP, 0);
       if (is_volatile) {
         __ Sync(0);
       }
       break;
 
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       if (kEmitCompilerReadBarrier) {
         if (kUseBakerReadBarrier) {
           Location temp = locations->GetTemp(0);
@@ -1227,56 +1227,56 @@
 
 // int sun.misc.Unsafe.getInt(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGet(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 
 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 
 // long sun.misc.Unsafe.getLong(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 
 // long sun.misc.Unsafe.getLongVolatile(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 
 // Object sun.misc.Unsafe.getObject(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 
 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference);
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 
 static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) {
@@ -1292,13 +1292,13 @@
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
 static void GenUnsafePut(LocationSummary* locations,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          bool is_ordered,
                          CodeGeneratorMIPS64* codegen) {
-  DCHECK((type == Primitive::kPrimInt) ||
-         (type == Primitive::kPrimLong) ||
-         (type == Primitive::kPrimNot));
+  DCHECK((type == DataType::Type::kInt32) ||
+         (type == DataType::Type::kInt64) ||
+         (type == DataType::Type::kReference));
   Mips64Assembler* assembler = codegen->GetAssembler();
   // Object pointer.
   GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
@@ -1311,9 +1311,9 @@
     __ Sync(0);
   }
   switch (type) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-      if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
+      if (kPoisonHeapReferences && type == DataType::Type::kReference) {
         __ PoisonHeapReference(AT, value);
         __ Sw(AT, TMP, 0);
       } else {
@@ -1321,7 +1321,7 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ Sd(value, TMP, 0);
       break;
 
@@ -1333,7 +1333,7 @@
     __ Sync(0);
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(base, value, value_can_be_null);
   }
@@ -1346,7 +1346,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
@@ -1359,7 +1359,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
@@ -1372,7 +1372,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimInt,
+               DataType::Type::kInt32,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
@@ -1385,7 +1385,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
@@ -1398,7 +1398,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
@@ -1411,7 +1411,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimNot,
+               DataType::Type::kReference,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
@@ -1424,7 +1424,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ false,
                codegen_);
@@ -1437,7 +1437,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ false,
                /* is_ordered */ true,
                codegen_);
@@ -1450,7 +1450,7 @@
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(),
-               Primitive::kPrimLong,
+               DataType::Type::kInt64,
                /* is_volatile */ true,
                /* is_ordered */ false,
                codegen_);
@@ -1480,7 +1480,7 @@
 
 // Note that the caller must supply a properly aligned memory address.
 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
-static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS64* codegen) {
+static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorMIPS64* codegen) {
   Mips64Assembler* assembler = codegen->GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
   GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
@@ -1495,7 +1495,7 @@
   DCHECK_NE(offset, out);
   DCHECK_NE(expected, out);
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // The only read barrier implementation supporting the
     // UnsafeCASObject intrinsic is the Baker-style read barriers.
     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
@@ -1525,7 +1525,7 @@
   Mips64Label loop_head, exit_loop;
   __ Daddu(TMP, base, offset);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     __ PoisonHeapReference(expected);
     // Do not poison `value`, if it is the same register as
     // `expected`, which has just been poisoned.
@@ -1541,13 +1541,13 @@
 
   __ Sync(0);
   __ Bind(&loop_head);
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ Lld(out, TMP);
   } else {
     // Note: We will need a read barrier here, when read barrier
     // support is added to the MIPS64 back end.
     __ Ll(out, TMP);
-    if (type == Primitive::kPrimNot) {
+    if (type == DataType::Type::kReference) {
       // The LL instruction sign-extends the 32-bit value, but
       // 32-bit references must be zero-extended. Zero-extend `out`.
       __ Dext(out, out, 0, 32);
@@ -1561,7 +1561,7 @@
                         // in the case that the store fails.  Whether the
                         // store succeeds, or fails, it will load the
                         // correct Boolean value into the 'out' register.
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ Scd(out, TMP);
   } else {
     __ Sc(out, TMP);
@@ -1571,7 +1571,7 @@
   __ Bind(&exit_loop);
   __ Sync(0);
 
-  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     __ UnpoisonHeapReference(expected);
     // Do not unpoison `value`, if it is the same register as
     // `expected`, which has just been unpoisoned.
@@ -1587,7 +1587,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimInt, codegen_);
+  GenCas(invoke, DataType::Type::kInt32, codegen_);
 }
 
 // boolean sun.misc.Unsafe.compareAndSwapLong(Object o, long offset, long expected, long x)
@@ -1596,7 +1596,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
-  GenCas(invoke, Primitive::kPrimLong, codegen_);
+  GenCas(invoke, DataType::Type::kInt64, codegen_);
 }
 
 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
@@ -1615,7 +1615,7 @@
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCas(invoke, Primitive::kPrimNot, codegen_);
+  GenCas(invoke, DataType::Type::kReference, codegen_);
 }
 
 // int java.lang.String.compareTo(String anotherString)
@@ -1626,7 +1626,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 }
 
@@ -1790,7 +1790,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     GpuRegister char_reg = locations->InAt(1).AsRegister<GpuRegister>();
     __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
     slow_path = new (allocator) IntrinsicSlowPathMIPS64(invoke);
@@ -1822,7 +1822,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 
   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
@@ -1844,7 +1844,7 @@
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 }
 
@@ -1863,7 +1863,7 @@
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 }
 
@@ -1890,7 +1890,7 @@
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 }
 
@@ -1912,7 +1912,7 @@
                                                             kIntrinsified);
   InvokeRuntimeCallingConvention calling_convention;
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+  Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
 }
 
@@ -1985,9 +1985,9 @@
   LocationSummary* locations = invoke->GetLocations();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
-  const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+  const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
 
   GpuRegister srcObj = locations->InAt(0).AsRegister<GpuRegister>();
   GpuRegister srcBegin = locations->InAt(1).AsRegister<GpuRegister>();
@@ -2213,10 +2213,10 @@
 
   // Okay, everything checks out.  Finally time to do the copy.
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
-  const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+  const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
 
   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
 
@@ -2250,14 +2250,14 @@
 }
 
 static void GenHighestOneBit(LocationSummary* locations,
-                             Primitive::Type type,
+                             DataType::Type type,
                              Mips64Assembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
 
   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ Dclz(TMP, in);
     __ LoadConst64(AT, INT64_C(0x8000000000000000));
     __ Dsrlv(AT, AT, TMP);
@@ -2281,7 +2281,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 // long java.lang.Long.highestOneBit(long)
@@ -2290,18 +2290,18 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
-  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 static void GenLowestOneBit(LocationSummary* locations,
-                            Primitive::Type type,
+                            DataType::Type type,
                             Mips64Assembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
+  DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
 
   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ Dsubu(TMP, ZERO, in);
   } else {
     __ Subu(TMP, ZERO, in);
@@ -2315,7 +2315,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 // long java.lang.Long.lowestOneBit(long)
@@ -2324,7 +2324,7 @@
 }
 
 void IntrinsicCodeGeneratorMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
-  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -2334,7 +2334,7 @@
   InvokeRuntimeCallingConvention calling_convention;
 
   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
 }
 
 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -2345,7 +2345,7 @@
 
   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
-  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+  locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
 }
 
 static void GenFPToFPCall(HInvoke* invoke,
@@ -2533,7 +2533,7 @@
   IntrinsicVisitor::ComputeIntegerValueOfLocations(
       invoke,
       codegen_,
-      calling_convention.GetReturnLocation(Primitive::kPrimNot),
+      calling_convention.GetReturnLocation(DataType::Type::kReference),
       Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
 }
 
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index abd9014..a591622 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -97,7 +97,7 @@
     DCHECK(instruction_->GetLocations()->Intrinsified());
     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
 
-    int32_t element_size = Primitive::ComponentSize(Primitive::kPrimNot);
+    int32_t element_size = DataType::Size(DataType::Type::kReference);
     uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value();
 
     Register src = locations->InAt(0).AsRegister<Register>();
@@ -282,17 +282,17 @@
 }
 
 static void GenReverseBytes(LocationSummary* locations,
-                            Primitive::Type size,
+                            DataType::Type size,
                             X86Assembler* assembler) {
   Register out = locations->Out().AsRegister<Register>();
 
   switch (size) {
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
       __ bswapl(out);
       __ sarl(out, Immediate(16));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ bswapl(out);
       break;
     default:
@@ -306,7 +306,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitIntegerReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitLongReverseBytes(HInvoke* invoke) {
@@ -335,7 +335,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 
@@ -1307,7 +1307,7 @@
 
   // Okay, everything checks out.  Finally time to do the copy.
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
@@ -1540,7 +1540,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     __ cmpl(search_value, Immediate(std::numeric_limits<uint16_t>::max()));
     slow_path = new (allocator) IntrinsicSlowPathX86(invoke);
     codegen->AddSlowPath(slow_path);
@@ -1766,7 +1766,7 @@
   X86Assembler* assembler = GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
 
-  size_t char_component_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  size_t char_component_size = DataType::Size(DataType::Type::kUint16);
   // Location of data in char array buffer.
   const uint32_t data_offset = mirror::Array::DataOffset(char_component_size).Uint32Value();
   // Location of char array data in string.
@@ -1782,7 +1782,7 @@
   Register dstBegin = locations->InAt(4).AsRegister<Register>();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   // Compute the number of chars (words) to move.
@@ -1802,7 +1802,7 @@
   if (mirror::kUseStringCompression) {
     // Location of count in string
     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
     __ pushl(EAX);
     __ cfi().AdjustCFAOffset(stack_adjust);
@@ -1849,22 +1849,22 @@
   __ cfi().AdjustCFAOffset(-stack_adjust);
 }
 
-static void GenPeek(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
+static void GenPeek(LocationSummary* locations, DataType::Type size, X86Assembler* assembler) {
   Register address = locations->InAt(0).AsRegisterPairLow<Register>();
   Location out_loc = locations->Out();
   // x86 allows unaligned access. We do not have to check the input or use specific instructions
   // to avoid a SIGBUS.
   switch (size) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
       __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
       break;
@@ -1879,7 +1879,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
@@ -1887,7 +1887,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
@@ -1895,7 +1895,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
@@ -1903,30 +1903,30 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
-static void CreateLongIntToVoidLocations(ArenaAllocator* arena, Primitive::Type size,
+static void CreateLongIntToVoidLocations(ArenaAllocator* arena, DataType::Type size,
                                          HInvoke* invoke) {
   LocationSummary* locations = new (arena) LocationSummary(invoke,
                                                            LocationSummary::kNoCall,
                                                            kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
   HInstruction* value = invoke->InputAt(1);
-  if (size == Primitive::kPrimByte) {
+  if (size == DataType::Type::kInt8) {
     locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
   } else {
     locations->SetInAt(1, Location::RegisterOrConstant(value));
   }
 }
 
-static void GenPoke(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
+static void GenPoke(LocationSummary* locations, DataType::Type size, X86Assembler* assembler) {
   Register address = locations->InAt(0).AsRegisterPairLow<Register>();
   Location value_loc = locations->InAt(1);
   // x86 allows unaligned access. We do not have to check the input or use specific instructions
   // to avoid a SIGBUS.
   switch (size) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       if (value_loc.IsConstant()) {
         __ movb(Address(address, 0),
                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
@@ -1934,7 +1934,7 @@
         __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
       }
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       if (value_loc.IsConstant()) {
         __ movw(Address(address, 0),
                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
@@ -1942,7 +1942,7 @@
         __ movw(Address(address, 0), value_loc.AsRegister<Register>());
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       if (value_loc.IsConstant()) {
         __ movl(Address(address, 0),
                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
@@ -1950,7 +1950,7 @@
         __ movl(Address(address, 0), value_loc.AsRegister<Register>());
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (value_loc.IsConstant()) {
         int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
         __ movl(Address(address, 0), Immediate(Low32Bits(value)));
@@ -1967,35 +1967,35 @@
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
-  CreateLongIntToVoidLocations(arena_, Primitive::kPrimByte, invoke);
+  CreateLongIntToVoidLocations(arena_, DataType::Type::kInt8, invoke);
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
-  CreateLongIntToVoidLocations(arena_, Primitive::kPrimInt, invoke);
+  CreateLongIntToVoidLocations(arena_, DataType::Type::kInt32, invoke);
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
-  CreateLongIntToVoidLocations(arena_, Primitive::kPrimLong, invoke);
+  CreateLongIntToVoidLocations(arena_, DataType::Type::kInt64, invoke);
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
-  CreateLongIntToVoidLocations(arena_, Primitive::kPrimShort, invoke);
+  CreateLongIntToVoidLocations(arena_, DataType::Type::kInt16, invoke);
 }
 
 void IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
@@ -2011,7 +2011,7 @@
 }
 
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          CodeGeneratorX86* codegen) {
   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
@@ -2023,13 +2023,13 @@
   Location output_loc = locations->Out();
 
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       Register output = output_loc.AsRegister<Register>();
       __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       Register output = output_loc.AsRegister<Register>();
       if (kEmitCompilerReadBarrier) {
         if (kUseBakerReadBarrier) {
@@ -2048,7 +2048,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
         Register output_lo = output_loc.AsRegisterPairLow<Register>();
         Register output_hi = output_loc.AsRegisterPairHigh<Register>();
         if (is_volatile) {
@@ -2073,7 +2073,7 @@
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
                                           HInvoke* invoke,
-                                          Primitive::Type type,
+                                          DataType::Type type,
                                           bool is_volatile) {
   bool can_call = kEmitCompilerReadBarrier &&
       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
@@ -2089,7 +2089,7 @@
   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   locations->SetInAt(1, Location::RequiresRegister());
   locations->SetInAt(2, Location::RequiresRegister());
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     if (is_volatile) {
       // Need to use XMM to read volatile.
       locations->AddTemp(Location::RequiresFpuRegister());
@@ -2104,47 +2104,48 @@
 }
 
 void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ false);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ true);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt32, /* is_volatile */ true);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ false);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ true);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kInt64, /* is_volatile */ true);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ false);
+  CreateIntIntIntToIntLocations(
+      arena_, invoke, DataType::Type::kReference, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ true);
+  CreateIntIntIntToIntLocations(arena_, invoke, DataType::Type::kReference, /* is_volatile */ true);
 }
 
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 
 
 static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
-                                                       Primitive::Type type,
+                                                       DataType::Type type,
                                                        HInvoke* invoke,
                                                        bool is_volatile) {
   LocationSummary* locations = new (arena) LocationSummary(invoke,
@@ -2154,12 +2155,12 @@
   locations->SetInAt(1, Location::RequiresRegister());
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetInAt(3, Location::RequiresRegister());
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Need temp registers for card-marking.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     // Ensure the value is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
-  } else if (type == Primitive::kPrimLong && is_volatile) {
+  } else if (type == DataType::Type::kInt64 && is_volatile) {
     locations->AddTemp(Location::RequiresFpuRegister());
     locations->AddTemp(Location::RequiresFpuRegister());
   }
@@ -2167,45 +2168,45 @@
 
 void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kInt32, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kInt32, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ true);
+      arena_, DataType::Type::kInt32, invoke, /* is_volatile */ true);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kReference, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kReference, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ true);
+      arena_, DataType::Type::kReference, invoke, /* is_volatile */ true);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kInt64, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
+      arena_, DataType::Type::kInt64, invoke, /* is_volatile */ false);
 }
 void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
-      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ true);
+      arena_, DataType::Type::kInt64, invoke, /* is_volatile */ true);
 }
 
 // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
 // memory model.
 static void GenUnsafePut(LocationSummary* locations,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile,
                          CodeGeneratorX86* codegen) {
   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
@@ -2213,7 +2214,7 @@
   Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
   Location value_loc = locations->InAt(3);
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     Register value_lo = value_loc.AsRegisterPairLow<Register>();
     Register value_hi = value_loc.AsRegisterPairHigh<Register>();
     if (is_volatile) {
@@ -2227,7 +2228,7 @@
       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
     }
-  } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  } else if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     __ movl(temp, value_loc.AsRegister<Register>());
     __ PoisonHeapReference(temp);
@@ -2240,7 +2241,7 @@
     codegen->MemoryFence();
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
                         locations->GetTemp(1).AsRegister<Register>(),
@@ -2251,35 +2252,38 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 
 static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena,
-                                       Primitive::Type type,
+                                       DataType::Type type,
                                        HInvoke* invoke) {
   bool can_call = kEmitCompilerReadBarrier &&
       kUseBakerReadBarrier &&
@@ -2296,7 +2300,7 @@
   locations->SetInAt(2, Location::RequiresRegister());
   // Expected value must be in EAX or EDX:EAX.
   // For long, new value must be in ECX:EBX.
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     locations->SetInAt(3, Location::RegisterPairLocation(EAX, EDX));
     locations->SetInAt(4, Location::RegisterPairLocation(EBX, ECX));
   } else {
@@ -2306,7 +2310,7 @@
 
   // Force a byte register for the output.
   locations->SetOut(Location::RegisterLocation(EAX));
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Need temporary registers for card-marking, and possibly for
     // (Baker) read barrier.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
@@ -2316,11 +2320,11 @@
 }
 
 void IntrinsicLocationsBuilderX86::VisitUnsafeCASInt(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimInt, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kInt32, invoke);
 }
 
 void IntrinsicLocationsBuilderX86::VisitUnsafeCASLong(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimLong, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kInt64, invoke);
 }
 
 void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
@@ -2330,10 +2334,10 @@
     return;
   }
 
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kReference, invoke);
 }
 
-static void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86* codegen) {
+static void GenCAS(DataType::Type type, HInvoke* invoke, CodeGeneratorX86* codegen) {
   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
   LocationSummary* locations = invoke->GetLocations();
 
@@ -2345,7 +2349,7 @@
   // The address of the field within the holding object.
   Address field_addr(base, offset, ScaleFactor::TIMES_1, 0);
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // The only read barrier implementation supporting the
     // UnsafeCASObject intrinsic is the Baker-style read barriers.
     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
@@ -2426,12 +2430,12 @@
       // `expected`, as it is the same as register `out` (EAX).
     }
   } else {
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       // Ensure the expected value is in EAX (required by the CMPXCHG
       // instruction).
       DCHECK_EQ(locations->InAt(3).AsRegister<Register>(), EAX);
       __ LockCmpxchgl(field_addr, locations->InAt(4).AsRegister<Register>());
-    } else if (type == Primitive::kPrimLong) {
+    } else if (type == DataType::Type::kInt64) {
       // Ensure the expected value is in EAX:EDX and that the new
       // value is in EBX:ECX (required by the CMPXCHG8B instruction).
       DCHECK_EQ(locations->InAt(3).AsRegisterPairLow<Register>(), EAX);
@@ -2453,11 +2457,11 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCAS(Primitive::kPrimInt, invoke, codegen_);
+  GenCAS(DataType::Type::kInt32, invoke, codegen_);
 }
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) {
-  GenCAS(Primitive::kPrimLong, invoke, codegen_);
+  GenCAS(DataType::Type::kInt64, invoke, codegen_);
 }
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) {
@@ -2465,7 +2469,7 @@
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCAS(Primitive::kPrimNot, invoke, codegen_);
+  GenCAS(DataType::Type::kReference, invoke, codegen_);
 }
 
 void IntrinsicLocationsBuilderX86::VisitIntegerReverse(HInvoke* invoke) {
@@ -2824,16 +2828,16 @@
 
 // Compute base address for the System.arraycopy intrinsic in `base`.
 static void GenSystemArrayCopyBaseAddress(X86Assembler* assembler,
-                                          Primitive::Type type,
+                                          DataType::Type type,
                                           const Register& array,
                                           const Location& pos,
                                           const Register& base) {
   // This routine is only used by the SystemArrayCopy intrinsic at the
-  // moment. We can allow Primitive::kPrimNot as `type` to implement
+  // moment. We can allow DataType::Type::kReference as `type` to implement
   // the SystemArrayCopyChar intrinsic.
-  DCHECK_EQ(type, Primitive::kPrimNot);
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const ScaleFactor scale_factor = static_cast<ScaleFactor>(Primitive::ComponentSizeShift(type));
+  DCHECK_EQ(type, DataType::Type::kReference);
+  const int32_t element_size = DataType::Size(type);
+  const ScaleFactor scale_factor = static_cast<ScaleFactor>(DataType::SizeShift(type));
   const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
 
   if (pos.IsConstant()) {
@@ -2846,16 +2850,16 @@
 
 // Compute end source address for the System.arraycopy intrinsic in `end`.
 static void GenSystemArrayCopyEndAddress(X86Assembler* assembler,
-                                         Primitive::Type type,
+                                         DataType::Type type,
                                          const Location& copy_length,
                                          const Register& base,
                                          const Register& end) {
   // This routine is only used by the SystemArrayCopy intrinsic at the
-  // moment. We can allow Primitive::kPrimNot as `type` to implement
+  // moment. We can allow DataType::Type::kReference as `type` to implement
   // the SystemArrayCopyChar intrinsic.
-  DCHECK_EQ(type, Primitive::kPrimNot);
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const ScaleFactor scale_factor = static_cast<ScaleFactor>(Primitive::ComponentSizeShift(type));
+  DCHECK_EQ(type, DataType::Type::kReference);
+  const int32_t element_size = DataType::Size(type);
+  const ScaleFactor scale_factor = static_cast<ScaleFactor>(DataType::SizeShift(type));
 
   if (copy_length.IsConstant()) {
     int32_t constant = copy_length.GetConstant()->AsIntConstant()->GetValue();
@@ -3169,8 +3173,8 @@
     __ j(kNotEqual, intrinsic_slow_path->GetEntryLabel());
   }
 
-  const Primitive::Type type = Primitive::kPrimNot;
-  const int32_t element_size = Primitive::ComponentSize(type);
+  const DataType::Type type = DataType::Type::kReference;
+  const int32_t element_size = DataType::Size(type);
 
   // Compute the base source address in `temp1`.
   GenSystemArrayCopyBaseAddress(GetAssembler(), type, src, src_pos, temp1);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 7798c0d..a2545ee 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -90,7 +90,7 @@
     DCHECK(instruction_->GetLocations()->Intrinsified());
     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
 
-    int32_t element_size = Primitive::ComponentSize(Primitive::kPrimNot);
+    int32_t element_size = DataType::Size(DataType::Type::kReference);
 
     CpuRegister src_curr_addr = locations->GetTemp(0).AsRegister<CpuRegister>();
     CpuRegister dst_curr_addr = locations->GetTemp(1).AsRegister<CpuRegister>();
@@ -193,20 +193,20 @@
 }
 
 static void GenReverseBytes(LocationSummary* locations,
-                            Primitive::Type size,
+                            DataType::Type size,
                             X86_64Assembler* assembler) {
   CpuRegister out = locations->Out().AsRegister<CpuRegister>();
 
   switch (size) {
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
       __ bswapl(out);
       __ sarl(out, Immediate(16));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ bswapl(out);
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ bswapq(out);
       break;
     default:
@@ -220,7 +220,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitIntegerReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitLongReverseBytes(HInvoke* invoke) {
@@ -228,7 +228,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitLongReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitShortReverseBytes(HInvoke* invoke) {
@@ -236,7 +236,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitShortReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 
@@ -1084,7 +1084,7 @@
 
   // Okay, everything checks out.  Finally time to do the copy.
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
@@ -1125,7 +1125,7 @@
 // source address for the System.arraycopy intrinsic in `src_base`,
 // `dst_base` and `src_end` respectively.
 static void GenSystemArrayCopyAddresses(X86_64Assembler* assembler,
-                                        Primitive::Type type,
+                                        DataType::Type type,
                                         const CpuRegister& src,
                                         const Location& src_pos,
                                         const CpuRegister& dst,
@@ -1135,9 +1135,9 @@
                                         const CpuRegister& dst_base,
                                         const CpuRegister& src_end) {
   // This routine is only used by the SystemArrayCopy intrinsic.
-  DCHECK_EQ(type, Primitive::kPrimNot);
-  const int32_t element_size = Primitive::ComponentSize(type);
-  const ScaleFactor scale_factor = static_cast<ScaleFactor>(Primitive::ComponentSizeShift(type));
+  DCHECK_EQ(type, DataType::Type::kReference);
+  const int32_t element_size = DataType::Size(type);
+  const ScaleFactor scale_factor = static_cast<ScaleFactor>(DataType::SizeShift(type));
   const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
 
   if (src_pos.IsConstant()) {
@@ -1410,8 +1410,8 @@
     __ j(kNotEqual, intrinsic_slow_path->GetEntryLabel());
   }
 
-  const Primitive::Type type = Primitive::kPrimNot;
-  const int32_t element_size = Primitive::ComponentSize(type);
+  const DataType::Type type = DataType::Type::kReference;
+  const int32_t element_size = DataType::Size(type);
 
   // Compute base source address, base destination address, and end
   // source address in `temp1`, `temp2` and `temp3` respectively.
@@ -1705,7 +1705,7 @@
       __ Bind(slow_path->GetExitLabel());
       return;
     }
-  } else if (code_point->GetType() != Primitive::kPrimChar) {
+  } else if (code_point->GetType() != DataType::Type::kUint16) {
     __ cmpl(search_value, Immediate(std::numeric_limits<uint16_t>::max()));
     slow_path = new (allocator) IntrinsicSlowPathX86_64(invoke);
     codegen->AddSlowPath(slow_path);
@@ -1922,7 +1922,7 @@
   X86_64Assembler* assembler = GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
 
-  size_t char_component_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  size_t char_component_size = DataType::Size(DataType::Type::kUint16);
   // Location of data in char array buffer.
   const uint32_t data_offset = mirror::Array::DataOffset(char_component_size).Uint32Value();
   // Location of char array data in string.
@@ -1938,7 +1938,7 @@
   CpuRegister dstBegin = locations->InAt(4).AsRegister<CpuRegister>();
 
   // Check assumption that sizeof(Char) is 2 (used in scaling below).
-  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+  const size_t char_size = DataType::Size(DataType::Type::kUint16);
   DCHECK_EQ(char_size, 2u);
 
   NearLabel done;
@@ -1952,7 +1952,7 @@
   }
   if (mirror::kUseStringCompression) {
     NearLabel copy_uncompressed, copy_loop;
-    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
     DCHECK_EQ(c_char_size, 1u);
     // Location of count in string.
     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
@@ -1993,22 +1993,22 @@
   __ Bind(&done);
 }
 
-static void GenPeek(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
+static void GenPeek(LocationSummary* locations, DataType::Type size, X86_64Assembler* assembler) {
   CpuRegister address = locations->InAt(0).AsRegister<CpuRegister>();
   CpuRegister out = locations->Out().AsRegister<CpuRegister>();  // == address, here for clarity.
   // x86 allows unaligned access. We do not have to check the input or use specific instructions
   // to avoid a SIGBUS.
   switch (size) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       __ movsxb(out, Address(address, 0));
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       __ movsxw(out, Address(address, 0));
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ movl(out, Address(address, 0));
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ movq(out, Address(address, 0));
       break;
     default:
@@ -2022,7 +2022,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekByte(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekIntNative(HInvoke* invoke) {
@@ -2030,7 +2030,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekIntNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekLongNative(HInvoke* invoke) {
@@ -2038,7 +2038,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekLongNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekShortNative(HInvoke* invoke) {
@@ -2046,7 +2046,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekShortNative(HInvoke* invoke) {
-  GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenPeek(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -2057,13 +2057,13 @@
   locations->SetInAt(1, Location::RegisterOrInt32Constant(invoke->InputAt(1)));
 }
 
-static void GenPoke(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
+static void GenPoke(LocationSummary* locations, DataType::Type size, X86_64Assembler* assembler) {
   CpuRegister address = locations->InAt(0).AsRegister<CpuRegister>();
   Location value = locations->InAt(1);
   // x86 allows unaligned access. We do not have to check the input or use specific instructions
   // to avoid a SIGBUS.
   switch (size) {
-    case Primitive::kPrimByte:
+    case DataType::Type::kInt8:
       if (value.IsConstant()) {
         __ movb(Address(address, 0),
                 Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
@@ -2071,7 +2071,7 @@
         __ movb(Address(address, 0), value.AsRegister<CpuRegister>());
       }
       break;
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt16:
       if (value.IsConstant()) {
         __ movw(Address(address, 0),
                 Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
@@ -2079,7 +2079,7 @@
         __ movw(Address(address, 0), value.AsRegister<CpuRegister>());
       }
       break;
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       if (value.IsConstant()) {
         __ movl(Address(address, 0),
                 Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
@@ -2087,7 +2087,7 @@
         __ movl(Address(address, 0), value.AsRegister<CpuRegister>());
       }
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (value.IsConstant()) {
         int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
         DCHECK(IsInt<32>(v));
@@ -2108,7 +2108,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeByte(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeIntNative(HInvoke* invoke) {
@@ -2116,7 +2116,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeIntNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeLongNative(HInvoke* invoke) {
@@ -2124,7 +2124,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeLongNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeShortNative(HInvoke* invoke) {
@@ -2132,7 +2132,7 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeShortNative(HInvoke* invoke) {
-  GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+  GenPoke(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitThreadCurrentThread(HInvoke* invoke) {
@@ -2149,7 +2149,7 @@
 }
 
 static void GenUnsafeGet(HInvoke* invoke,
-                         Primitive::Type type,
+                         DataType::Type type,
                          bool is_volatile ATTRIBUTE_UNUSED,
                          CodeGeneratorX86_64* codegen) {
   X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen->GetAssembler());
@@ -2162,11 +2162,11 @@
   CpuRegister output = output_loc.AsRegister<CpuRegister>();
 
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
       break;
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       if (kEmitCompilerReadBarrier) {
         if (kUseBakerReadBarrier) {
           Address src(base, offset, ScaleFactor::TIMES_1, 0);
@@ -2184,7 +2184,7 @@
       break;
     }
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       __ movq(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
       break;
 
@@ -2234,27 +2234,27 @@
 
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGet(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLong(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetObject(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
-  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 
 
 static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
-                                                       Primitive::Type type,
+                                                       DataType::Type type,
                                                        HInvoke* invoke) {
   LocationSummary* locations = new (arena) LocationSummary(invoke,
                                                            LocationSummary::kNoCall,
@@ -2263,7 +2263,7 @@
   locations->SetInAt(1, Location::RequiresRegister());
   locations->SetInAt(2, Location::RequiresRegister());
   locations->SetInAt(3, Location::RequiresRegister());
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Need temp registers for card-marking.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     locations->AddTemp(Location::RequiresRegister());
@@ -2271,45 +2271,45 @@
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePut(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt32, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutOrdered(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt32, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutVolatile(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt32, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObject(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kReference, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kReference, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kReference, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLong(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt64, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt64, invoke);
 }
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
-  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, DataType::Type::kInt64, invoke);
 }
 
 // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
 // memory model.
-static void GenUnsafePut(LocationSummary* locations, Primitive::Type type, bool is_volatile,
+static void GenUnsafePut(LocationSummary* locations, DataType::Type type, bool is_volatile,
                          CodeGeneratorX86_64* codegen) {
   X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen->GetAssembler());
   CpuRegister base = locations->InAt(1).AsRegister<CpuRegister>();
   CpuRegister offset = locations->InAt(2).AsRegister<CpuRegister>();
   CpuRegister value = locations->InAt(3).AsRegister<CpuRegister>();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     __ movq(Address(base, offset, ScaleFactor::TIMES_1, 0), value);
-  } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+  } else if (kPoisonHeapReferences && type == DataType::Type::kReference) {
     CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
     __ movl(temp, value);
     __ PoisonHeapReference(temp);
@@ -2322,7 +2322,7 @@
     codegen->MemoryFence();
   }
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
                         locations->GetTemp(1).AsRegister<CpuRegister>(),
@@ -2333,35 +2333,38 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePut(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObject(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_);
+  GenUnsafePut(
+      invoke->GetLocations(), DataType::Type::kReference, /* is_volatile */ true, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLong(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ false, codegen_);
 }
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
-  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_);
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /* is_volatile */ true, codegen_);
 }
 
 static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena,
-                                       Primitive::Type type,
+                                       DataType::Type type,
                                        HInvoke* invoke) {
   bool can_call = kEmitCompilerReadBarrier &&
       kUseBakerReadBarrier &&
@@ -2379,7 +2382,7 @@
   locations->SetInAt(4, Location::RequiresRegister());
 
   locations->SetOut(Location::RequiresRegister());
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // Need temporary registers for card-marking, and possibly for
     // (Baker) read barrier.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
@@ -2388,11 +2391,11 @@
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASInt(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimInt, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kInt32, invoke);
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASLong(HInvoke* invoke) {
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimLong, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kInt64, invoke);
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASObject(HInvoke* invoke) {
@@ -2402,10 +2405,10 @@
     return;
   }
 
-  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
+  CreateIntIntIntIntIntToInt(arena_, DataType::Type::kReference, invoke);
 }
 
-static void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86_64* codegen) {
+static void GenCAS(DataType::Type type, HInvoke* invoke, CodeGeneratorX86_64* codegen) {
   X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen->GetAssembler());
   LocationSummary* locations = invoke->GetLocations();
 
@@ -2418,7 +2421,7 @@
   Location out_loc = locations->Out();
   CpuRegister out = out_loc.AsRegister<CpuRegister>();
 
-  if (type == Primitive::kPrimNot) {
+  if (type == DataType::Type::kReference) {
     // The only read barrier implementation supporting the
     // UnsafeCASObject intrinsic is the Baker-style read barriers.
     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
@@ -2500,9 +2503,9 @@
       __ UnpoisonHeapReference(expected);
     }
   } else {
-    if (type == Primitive::kPrimInt) {
+    if (type == DataType::Type::kInt32) {
       __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
-    } else if (type == Primitive::kPrimLong) {
+    } else if (type == DataType::Type::kInt64) {
       __ LockCmpxchgq(Address(base, offset, TIMES_1, 0), value);
     } else {
       LOG(FATAL) << "Unexpected CAS type " << type;
@@ -2518,11 +2521,11 @@
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASInt(HInvoke* invoke) {
-  GenCAS(Primitive::kPrimInt, invoke, codegen_);
+  GenCAS(DataType::Type::kInt32, invoke, codegen_);
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASLong(HInvoke* invoke) {
-  GenCAS(Primitive::kPrimLong, invoke, codegen_);
+  GenCAS(DataType::Type::kInt64, invoke, codegen_);
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASObject(HInvoke* invoke) {
@@ -2530,7 +2533,7 @@
   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
 
-  GenCAS(Primitive::kPrimNot, invoke, codegen_);
+  GenCAS(DataType::Type::kReference, invoke, codegen_);
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitIntegerReverse(HInvoke* invoke) {
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 8967d7c..0617e60 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -78,7 +78,7 @@
     parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                    dex::TypeIndex(0),
                                                    0,
-                                                   Primitive::kPrimNot);
+                                                   DataType::Type::kReference);
     entry_->AddInstruction(parameter_);
     int_constant_ = graph_->GetIntConstant(42);
     float_constant_ = graph_->GetFloatConstant(42.0f);
@@ -125,7 +125,7 @@
   // Populate the loop with instructions: set/get field with different types.
   HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
                                                                 nullptr,
-                                                                Primitive::kPrimLong,
+                                                                DataType::Type::kInt64,
                                                                 MemberOffset(10),
                                                                 false,
                                                                 kUnknownFieldIndex,
@@ -134,7 +134,7 @@
                                                                 0);
   loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
   HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
-      parameter_, int_constant_, nullptr, Primitive::kPrimInt, MemberOffset(20),
+      parameter_, int_constant_, nullptr, DataType::Type::kInt32, MemberOffset(20),
       false, kUnknownFieldIndex, kUnknownClassDefIndex, graph_->GetDexFile(), 0);
   loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
 
@@ -152,7 +152,7 @@
   ScopedNullHandle<mirror::DexCache> dex_cache;
   HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
                                                                 nullptr,
-                                                                Primitive::kPrimLong,
+                                                                DataType::Type::kInt64,
                                                                 MemberOffset(10),
                                                                 false,
                                                                 kUnknownFieldIndex,
@@ -163,7 +163,7 @@
   HInstruction* set_field = new (&allocator_) HInstanceFieldSet(parameter_,
                                                                 get_field,
                                                                 nullptr,
-                                                                Primitive::kPrimLong,
+                                                                DataType::Type::kInt64,
                                                                 MemberOffset(10),
                                                                 false,
                                                                 kUnknownFieldIndex,
@@ -184,10 +184,10 @@
 
   // Populate the loop with instructions: set/get array with different types.
   HInstruction* get_array = new (&allocator_) HArrayGet(
-      parameter_, int_constant_, Primitive::kPrimInt, 0);
+      parameter_, int_constant_, DataType::Type::kInt32, 0);
   loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
   HInstruction* set_array = new (&allocator_) HArraySet(
-      parameter_, int_constant_, float_constant_, Primitive::kPrimFloat, 0);
+      parameter_, int_constant_, float_constant_, DataType::Type::kFloat32, 0);
   loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
 
   EXPECT_EQ(get_array->GetBlock(), loop_body_);
@@ -202,10 +202,10 @@
 
   // Populate the loop with instructions: set/get array with same types.
   HInstruction* get_array = new (&allocator_) HArrayGet(
-      parameter_, int_constant_, Primitive::kPrimFloat, 0);
+      parameter_, int_constant_, DataType::Type::kFloat32, 0);
   loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
   HInstruction* set_array = new (&allocator_) HArraySet(
-      parameter_, get_array, float_constant_, Primitive::kPrimFloat, 0);
+      parameter_, get_array, float_constant_, DataType::Type::kFloat32, 0);
   loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
 
   EXPECT_EQ(get_array->GetBlock(), loop_body_);
diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index 02bc254..d46b904 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -369,7 +369,7 @@
   }
 
   void CreateReferenceInfoForReferenceType(HInstruction* instruction) {
-    if (instruction->GetType() != Primitive::kPrimNot) {
+    if (instruction->GetType() != DataType::Type::kReference) {
       return;
     }
     DCHECK(FindReferenceInfoOf(instruction) == nullptr);
diff --git a/compiler/optimizing/load_store_analysis_test.cc b/compiler/optimizing/load_store_analysis_test.cc
index 81344b5..0df2f27 100644
--- a/compiler/optimizing/load_store_analysis_test.cc
+++ b/compiler/optimizing/load_store_analysis_test.cc
@@ -49,16 +49,17 @@
   // array_set1    ArraySet [array, c1, c3]
   // array_set2    ArraySet [array, index, c3]
   HInstruction* array = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* index = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* array_get1 = new (&allocator_) HArrayGet(array, c1, Primitive::kPrimInt, 0);
-  HInstruction* array_get2 = new (&allocator_) HArrayGet(array, c2, Primitive::kPrimInt, 0);
-  HInstruction* array_set1 = new (&allocator_) HArraySet(array, c1, c3, Primitive::kPrimInt, 0);
-  HInstruction* array_set2 = new (&allocator_) HArraySet(array, index, c3, Primitive::kPrimInt, 0);
+  HInstruction* array_get1 = new (&allocator_) HArrayGet(array, c1, DataType::Type::kInt32, 0);
+  HInstruction* array_get2 = new (&allocator_) HArrayGet(array, c2, DataType::Type::kInt32, 0);
+  HInstruction* array_set1 = new (&allocator_) HArraySet(array, c1, c3, DataType::Type::kInt32, 0);
+  HInstruction* array_set2 =
+      new (&allocator_) HArraySet(array, index, c3, DataType::Type::kInt32, 0);
   entry->AddInstruction(array);
   entry->AddInstruction(index);
   entry->AddInstruction(array_get1);
@@ -121,11 +122,11 @@
   HInstruction* object = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                            dex::TypeIndex(0),
                                                            0,
-                                                           Primitive::kPrimNot);
+                                                           DataType::Type::kReference);
   HInstanceFieldSet* set_field10 = new (&allocator_) HInstanceFieldSet(object,
                                                                        c1,
                                                                        nullptr,
-                                                                       Primitive::kPrimInt,
+                                                                       DataType::Type::kInt32,
                                                                        MemberOffset(10),
                                                                        false,
                                                                        kUnknownFieldIndex,
@@ -134,7 +135,7 @@
                                                                        0);
   HInstanceFieldGet* get_field10 = new (&allocator_) HInstanceFieldGet(object,
                                                                        nullptr,
-                                                                       Primitive::kPrimInt,
+                                                                       DataType::Type::kInt32,
                                                                        MemberOffset(10),
                                                                        false,
                                                                        kUnknownFieldIndex,
@@ -143,7 +144,7 @@
                                                                        0);
   HInstanceFieldGet* get_field20 = new (&allocator_) HInstanceFieldGet(object,
                                                                        nullptr,
-                                                                       Primitive::kPrimInt,
+                                                                       DataType::Type::kInt32,
                                                                        MemberOffset(20),
                                                                        false,
                                                                        kUnknownFieldIndex,
@@ -191,26 +192,28 @@
   graph_->BuildDominatorTree();
 
   HInstruction* array = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* index = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
   HInstruction* c0 = graph_->GetIntConstant(0);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c_neg1 = graph_->GetIntConstant(-1);
-  HInstruction* add0 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c0);
-  HInstruction* add1 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c1);
-  HInstruction* sub0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c0);
-  HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, index, c1);
-  HInstruction* sub_neg1 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_neg1);
-  HInstruction* rev_sub1 = new (&allocator_) HSub(Primitive::kPrimInt, c1, index);
-  HInstruction* arr_set1 = new (&allocator_) HArraySet(array, c0, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set2 = new (&allocator_) HArraySet(array, c1, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set3 = new (&allocator_) HArraySet(array, add0, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set4 = new (&allocator_) HArraySet(array, add1, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set5 = new (&allocator_) HArraySet(array, sub0, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set6 = new (&allocator_) HArraySet(array, sub1, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set7 = new (&allocator_) HArraySet(array, rev_sub1, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set8 = new (&allocator_) HArraySet(array, sub_neg1, c0, Primitive::kPrimInt, 0);
+  HInstruction* add0 = new (&allocator_) HAdd(DataType::Type::kInt32, index, c0);
+  HInstruction* add1 = new (&allocator_) HAdd(DataType::Type::kInt32, index, c1);
+  HInstruction* sub0 = new (&allocator_) HSub(DataType::Type::kInt32, index, c0);
+  HInstruction* sub1 = new (&allocator_) HSub(DataType::Type::kInt32, index, c1);
+  HInstruction* sub_neg1 = new (&allocator_) HSub(DataType::Type::kInt32, index, c_neg1);
+  HInstruction* rev_sub1 = new (&allocator_) HSub(DataType::Type::kInt32, c1, index);
+  HInstruction* arr_set1 = new (&allocator_) HArraySet(array, c0, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set2 = new (&allocator_) HArraySet(array, c1, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set3 = new (&allocator_) HArraySet(array, add0, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set4 = new (&allocator_) HArraySet(array, add1, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set5 = new (&allocator_) HArraySet(array, sub0, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set6 = new (&allocator_) HArraySet(array, sub1, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set7 =
+      new (&allocator_) HArraySet(array, rev_sub1, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set8 =
+      new (&allocator_) HArraySet(array, sub_neg1, c0, DataType::Type::kInt32, 0);
 
   entry->AddInstruction(array);
   entry->AddInstruction(index);
@@ -275,9 +278,9 @@
   graph_->BuildDominatorTree();
 
   HInstruction* array = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* index = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
 
   HInstruction* c0 = graph_->GetIntConstant(0);
   HInstruction* c_0x80000000 = graph_->GetIntConstant(0x80000000);
@@ -287,34 +290,41 @@
   HInstruction* c_0x80000001 = graph_->GetIntConstant(0x80000001);
 
   // `index+0x80000000` and `index-0x80000000` array indices MAY alias.
-  HInstruction* add_0x80000000 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x80000000);
-  HInstruction* sub_0x80000000 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0x80000000);
+  HInstruction* add_0x80000000 = new (&allocator_) HAdd(
+      DataType::Type::kInt32, index, c_0x80000000);
+  HInstruction* sub_0x80000000 = new (&allocator_) HSub(
+      DataType::Type::kInt32, index, c_0x80000000);
   HInstruction* arr_set_1 = new (&allocator_) HArraySet(
-      array, add_0x80000000, c0, Primitive::kPrimInt, 0);
+      array, add_0x80000000, c0, DataType::Type::kInt32, 0);
   HInstruction* arr_set_2 = new (&allocator_) HArraySet(
-      array, sub_0x80000000, c0, Primitive::kPrimInt, 0);
+      array, sub_0x80000000, c0, DataType::Type::kInt32, 0);
 
   // `index+0x10` and `index-0xFFFFFFF0` array indices MAY alias.
-  HInstruction* add_0x10 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x10);
-  HInstruction* sub_0xFFFFFFF0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0xFFFFFFF0);
+  HInstruction* add_0x10 = new (&allocator_) HAdd(DataType::Type::kInt32, index, c_0x10);
+  HInstruction* sub_0xFFFFFFF0 = new (&allocator_) HSub(
+      DataType::Type::kInt32, index, c_0xFFFFFFF0);
   HInstruction* arr_set_3 = new (&allocator_) HArraySet(
-      array, add_0x10, c0, Primitive::kPrimInt, 0);
+      array, add_0x10, c0, DataType::Type::kInt32, 0);
   HInstruction* arr_set_4 = new (&allocator_) HArraySet(
-      array, sub_0xFFFFFFF0, c0, Primitive::kPrimInt, 0);
+      array, sub_0xFFFFFFF0, c0, DataType::Type::kInt32, 0);
 
   // `index+0x7FFFFFFF` and `index-0x80000001` array indices MAY alias.
-  HInstruction* add_0x7FFFFFFF = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x7FFFFFFF);
-  HInstruction* sub_0x80000001 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0x80000001);
+  HInstruction* add_0x7FFFFFFF = new (&allocator_) HAdd(
+      DataType::Type::kInt32, index, c_0x7FFFFFFF);
+  HInstruction* sub_0x80000001 = new (&allocator_) HSub(
+      DataType::Type::kInt32, index, c_0x80000001);
   HInstruction* arr_set_5 = new (&allocator_) HArraySet(
-      array, add_0x7FFFFFFF, c0, Primitive::kPrimInt, 0);
+      array, add_0x7FFFFFFF, c0, DataType::Type::kInt32, 0);
   HInstruction* arr_set_6 = new (&allocator_) HArraySet(
-      array, sub_0x80000001, c0, Primitive::kPrimInt, 0);
+      array, sub_0x80000001, c0, DataType::Type::kInt32, 0);
 
   // `index+0` and `index-0` array indices MAY alias.
-  HInstruction* add_0 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c0);
-  HInstruction* sub_0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c0);
-  HInstruction* arr_set_7 = new (&allocator_) HArraySet(array, add_0, c0, Primitive::kPrimInt, 0);
-  HInstruction* arr_set_8 = new (&allocator_) HArraySet(array, sub_0, c0, Primitive::kPrimInt, 0);
+  HInstruction* add_0 = new (&allocator_) HAdd(DataType::Type::kInt32, index, c0);
+  HInstruction* sub_0 = new (&allocator_) HSub(DataType::Type::kInt32, index, c0);
+  HInstruction* arr_set_7 = new (&allocator_) HArraySet(
+      array, add_0, c0, DataType::Type::kInt32, 0);
+  HInstruction* arr_set_8 = new (&allocator_) HArraySet(
+      array, sub_0, c0, DataType::Type::kInt32, 0);
 
   entry->AddInstruction(array);
   entry->AddInstruction(index);
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8a9acf1..bd14f2b 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -271,21 +271,21 @@
     }
   }
 
-  HInstruction* GetDefaultValue(Primitive::Type type) {
+  HInstruction* GetDefaultValue(DataType::Type type) {
     switch (type) {
-      case Primitive::kPrimNot:
+      case DataType::Type::kReference:
         return GetGraph()->GetNullConstant();
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
+      case DataType::Type::kBool:
+      case DataType::Type::kInt8:
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+      case DataType::Type::kInt32:
         return GetGraph()->GetIntConstant(0);
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         return GetGraph()->GetLongConstant(0);
-      case Primitive::kPrimFloat:
+      case DataType::Type::kFloat32:
         return GetGraph()->GetFloatConstant(0);
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat64:
         return GetGraph()->GetDoubleConstant(0);
       default:
         UNREACHABLE();
@@ -328,8 +328,7 @@
       // This acts like GVN but with better aliasing analysis.
       heap_values[idx] = instruction;
     } else {
-      if (Primitive::PrimitiveKind(heap_value->GetType())
-              != Primitive::PrimitiveKind(instruction->GetType())) {
+      if (DataType::Kind(heap_value->GetType()) != DataType::Kind(instruction->GetType())) {
         // The only situation where the same heap location has different type is when
         // we do an array get on an instruction that originates from the null constant
         // (the null could be behind a field access, an array access, a null check or
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index baa0453..6c918a3 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -71,31 +71,38 @@
   return false;
 }
 
-// Detect a sign extension from the given type. Returns the promoted operand on success.
+// Detect a sign extension in instruction from the given type. The to64 parameter
+// denotes if result is long, and thus sign extension from int can be included.
+// Returns the promoted operand on success.
 static bool IsSignExtensionAndGet(HInstruction* instruction,
-                                  Primitive::Type type,
-                                  /*out*/ HInstruction** operand) {
+                                  DataType::Type type,
+                                  /*out*/ HInstruction** operand,
+                                  bool to64 = false) {
   // Accept any already wider constant that would be handled properly by sign
   // extension when represented in the *width* of the given narrower data type
   // (the fact that char normally zero extends does not matter here).
   int64_t value = 0;
   if (IsInt64AndGet(instruction, /*out*/ &value)) {
     switch (type) {
-      case Primitive::kPrimByte:
-        if (std::numeric_limits<int8_t>::min() <= value &&
-            std::numeric_limits<int8_t>::max() >= value) {
+      case DataType::Type::kInt8:
+        if (IsInt<8>(value)) {
           *operand = instruction;
           return true;
         }
         return false;
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-        if (std::numeric_limits<int16_t>::min() <= value &&
-            std::numeric_limits<int16_t>::max() <= value) {
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+        if (IsInt<16>(value)) {
           *operand = instruction;
           return true;
         }
         return false;
+      case DataType::Type::kInt32:
+        if (IsInt<32>(value)) {
+          *operand = instruction;
+          return to64;
+        }
+        return false;
       default:
         return false;
     }
@@ -106,44 +113,56 @@
                                          instruction->IsStaticFieldGet() ||
                                          instruction->IsInstanceFieldGet())) {
     switch (type) {
-      case Primitive::kPrimByte:
-      case Primitive::kPrimShort:
+      case DataType::Type::kInt8:
+      case DataType::Type::kInt16:
         *operand = instruction;
         return true;
+      case DataType::Type::kInt32:
+        *operand = instruction;
+        return to64;
       default:
         return false;
     }
   }
-  // TODO: perhaps explicit conversions later too?
-  //       (this may return something different from instruction)
+  // Explicit type conversion to long.
+  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
+    return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  }
   return false;
 }
 
-// Detect a zero extension from the given type. Returns the promoted operand on success.
+// Detect a zero extension in instruction from the given type. The to64 parameter
+// denotes if result is long, and thus zero extension from int can be included.
+// Returns the promoted operand on success.
 static bool IsZeroExtensionAndGet(HInstruction* instruction,
-                                  Primitive::Type type,
-                                  /*out*/ HInstruction** operand) {
+                                  DataType::Type type,
+                                  /*out*/ HInstruction** operand,
+                                  bool to64 = false) {
   // Accept any already wider constant that would be handled properly by zero
   // extension when represented in the *width* of the given narrower data type
-  // (the fact that byte/short normally sign extend does not matter here).
+  // (the fact that byte/short/int normally sign extend does not matter here).
   int64_t value = 0;
   if (IsInt64AndGet(instruction, /*out*/ &value)) {
     switch (type) {
-      case Primitive::kPrimByte:
-        if (std::numeric_limits<uint8_t>::min() <= value &&
-            std::numeric_limits<uint8_t>::max() >= value) {
+      case DataType::Type::kInt8:
+        if (IsUint<8>(value)) {
           *operand = instruction;
           return true;
         }
         return false;
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-        if (std::numeric_limits<uint16_t>::min() <= value &&
-            std::numeric_limits<uint16_t>::max() <= value) {
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+        if (IsUint<16>(value)) {
           *operand = instruction;
           return true;
         }
         return false;
+      case DataType::Type::kInt32:
+        if (IsUint<32>(value)) {
+          *operand = instruction;
+          return to64;
+        }
+        return false;
       default:
         return false;
     }
@@ -153,7 +172,7 @@
   if (instruction->GetType() == type && (instruction->IsArrayGet() ||
                                          instruction->IsStaticFieldGet() ||
                                          instruction->IsInstanceFieldGet())) {
-    if (type == Primitive::kPrimChar) {
+    if (type == DataType::Type::kUint16) {
       *operand = instruction;
       return true;
     }
@@ -170,14 +189,21 @@
         (IsInt64AndGet(b, /*out*/ &mask) && (IsSignExtensionAndGet(a, type, /*out*/ operand) ||
                                              IsZeroExtensionAndGet(a, type, /*out*/ operand)))) {
       switch ((*operand)->GetType()) {
-        case Primitive::kPrimByte:  return mask == std::numeric_limits<uint8_t>::max();
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort: return mask == std::numeric_limits<uint16_t>::max();
+        case DataType::Type::kInt8:
+          return mask == std::numeric_limits<uint8_t>::max();
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+          return mask == std::numeric_limits<uint16_t>::max();
+        case DataType::Type::kInt32:
+          return mask == std::numeric_limits<uint32_t>::max() && to64;
         default: return false;
       }
     }
   }
-  // TODO: perhaps explicit conversions later too?
+  // Explicit type conversion to long.
+  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
+    return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  }
   return false;
 }
 
@@ -185,7 +211,7 @@
 // Returns true on success and sets is_unsigned accordingly.
 static bool IsNarrowerOperands(HInstruction* a,
                                HInstruction* b,
-                               Primitive::Type type,
+                               DataType::Type type,
                                /*out*/ HInstruction** r,
                                /*out*/ HInstruction** s,
                                /*out*/ bool* is_unsigned) {
@@ -201,7 +227,7 @@
 
 // As above, single operand.
 static bool IsNarrowerOperand(HInstruction* a,
-                              Primitive::Type type,
+                              DataType::Type type,
                               /*out*/ HInstruction** r,
                               /*out*/ bool* is_unsigned) {
   if (IsSignExtensionAndGet(a, type, r)) {
@@ -214,6 +240,55 @@
   return false;
 }
 
+// Compute relative vector length based on type difference.
+static size_t GetOtherVL(DataType::Type other_type, DataType::Type vector_type, size_t vl) {
+  switch (other_type) {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+      switch (vector_type) {
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8: return vl;
+        default: break;
+      }
+      return vl;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      switch (vector_type) {
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8: return vl >> 1;
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16: return vl;
+        default: break;
+      }
+      break;
+    case DataType::Type::kInt32:
+      switch (vector_type) {
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8: return vl >> 2;
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16: return vl >> 1;
+        case DataType::Type::kInt32: return vl;
+        default: break;
+      }
+      break;
+    case DataType::Type::kInt64:
+      switch (vector_type) {
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8: return vl >> 3;
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16: return vl >> 2;
+        case DataType::Type::kInt32: return vl >> 1;
+        case DataType::Type::kInt64: return vl;
+        default: break;
+      }
+      break;
+    default:
+      break;
+  }
+  LOG(FATAL) << "Unsupported idiom conversion";
+  UNREACHABLE();
+}
+
 // Detect up to two instructions a and b, and an acccumulated constant c.
 static bool IsAddConstHelper(HInstruction* instruction,
                              /*out*/ HInstruction** a,
@@ -260,16 +335,16 @@
 }
 
 // Detect reductions of the following forms,
-// under assumption phi has only *one* use:
 //   x = x_phi + ..
 //   x = x_phi - ..
 //   x = max(x_phi, ..)
 //   x = min(x_phi, ..)
 static bool HasReductionFormat(HInstruction* reduction, HInstruction* phi) {
   if (reduction->IsAdd()) {
-    return reduction->InputAt(0) == phi || reduction->InputAt(1) == phi;
+    return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi) ||
+           (reduction->InputAt(0) != phi && reduction->InputAt(1) == phi);
   } else if (reduction->IsSub()) {
-    return reduction->InputAt(0) == phi;
+    return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi);
   } else if (reduction->IsInvokeStaticOrDirect()) {
     switch (reduction->AsInvokeStaticOrDirect()->GetIntrinsic()) {
       case Intrinsics::kMathMinIntInt:
@@ -280,7 +355,8 @@
       case Intrinsics::kMathMaxLongLong:
       case Intrinsics::kMathMaxFloatFloat:
       case Intrinsics::kMathMaxDoubleDouble:
-        return reduction->InputAt(0) == phi || reduction->InputAt(1) == phi;
+        return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi) ||
+               (reduction->InputAt(0) != phi && reduction->InputAt(1) == phi);
       default:
         return false;
     }
@@ -288,9 +364,9 @@
   return false;
 }
 
-// Translates operation to reduction kind.
-static HVecReduce::ReductionKind GetReductionKind(HInstruction* reduction) {
-  if (reduction->IsVecAdd() || reduction->IsVecSub()) {
+// Translates vector operation to reduction kind.
+static HVecReduce::ReductionKind GetReductionKind(HVecOperation* reduction) {
+  if (reduction->IsVecAdd() || reduction->IsVecSub() || reduction->IsVecSADAccumulate()) {
     return HVecReduce::kSum;
   } else if (reduction->IsVecMin()) {
     return HVecReduce::kMin;
@@ -720,7 +796,6 @@
                                   HBasicBlock* block,
                                   HBasicBlock* exit,
                                   int64_t trip_count) {
-  Primitive::Type induc_type = Primitive::kPrimInt;
   HBasicBlock* header = node->loop_info->GetHeader();
   HBasicBlock* preheader = node->loop_info->GetPreHeader();
 
@@ -739,6 +814,11 @@
   vector_header_ = header;
   vector_body_ = block;
 
+  // Loop induction type.
+  DataType::Type induc_type = main_phi->GetType();
+  DCHECK(induc_type == DataType::Type::kInt32 || induc_type == DataType::Type::kInt64)
+      << induc_type;
+
   // Generate dynamic loop peeling trip count, if needed, under the assumption
   // that the Android runtime guarantees at least "component size" alignment:
   // ptc = (ALIGN - (&a[initial] % ALIGN)) / type-size
@@ -767,10 +847,10 @@
     HInstruction* rem = Insert(
         preheader, new (global_allocator_) HAnd(induc_type,
                                                 diff,
-                                                graph_->GetIntConstant(chunk - 1)));
+                                                graph_->GetConstant(induc_type, chunk - 1)));
     vtc = Insert(preheader, new (global_allocator_) HSub(induc_type, stc, rem));
   }
-  vector_index_ = graph_->GetIntConstant(0);
+  vector_index_ = graph_->GetConstant(induc_type, 0);
 
   // Generate runtime disambiguation test:
   // vtc = a != b ? vtc : 0;
@@ -779,7 +859,8 @@
         preheader,
         new (global_allocator_) HNotEqual(vector_runtime_test_a_, vector_runtime_test_b_));
     vtc = Insert(preheader,
-                 new (global_allocator_) HSelect(rt, vtc, graph_->GetIntConstant(0), kNoDexPc));
+                 new (global_allocator_)
+                 HSelect(rt, vtc, graph_->GetConstant(induc_type, 0), kNoDexPc));
     needs_cleanup = true;
   }
 
@@ -793,7 +874,7 @@
                     graph_->TransformLoopForVectorization(vector_header_, vector_body_, exit),
                     vector_index_,
                     ptc,
-                    graph_->GetIntConstant(1),
+                    graph_->GetConstant(induc_type, 1),
                     kNoUnrollingFactor);
   }
 
@@ -806,7 +887,7 @@
                   graph_->TransformLoopForVectorization(vector_header_, vector_body_, exit),
                   vector_index_,
                   vtc,
-                  graph_->GetIntConstant(vector_length_),  // increment per unroll
+                  graph_->GetConstant(induc_type, vector_length_),  // increment per unroll
                   unroll);
   HLoopInformation* vloop = vector_header_->GetLoopInformation();
 
@@ -820,14 +901,20 @@
                     graph_->TransformLoopForVectorization(vector_header_, vector_body_, exit),
                     vector_index_,
                     stc,
-                    graph_->GetIntConstant(1),
+                    graph_->GetConstant(induc_type, 1),
                     kNoUnrollingFactor);
   }
 
   // Link reductions to their final uses.
   for (auto i = reductions_->begin(); i != reductions_->end(); ++i) {
     if (i->first->IsPhi()) {
-      i->first->ReplaceWith(ReduceAndExtractIfNeeded(i->second));
+      HInstruction* phi = i->first;
+      HInstruction* repl = ReduceAndExtractIfNeeded(i->second);
+      // Deal with regular uses.
+      for (const HUseListNode<HInstruction*>& use : phi->GetUses()) {
+        induction_range_.Replace(use.GetUser(), phi, repl);  // update induction use
+      }
+      phi->ReplaceWith(repl);
     }
   }
 
@@ -853,7 +940,7 @@
                                         HInstruction* step,
                                         uint32_t unroll) {
   DCHECK(unroll == 1 || vector_mode_ == kVector);
-  Primitive::Type induc_type = Primitive::kPrimInt;
+  DataType::Type induc_type = lo->GetType();
   // Prepare new loop.
   vector_preheader_ = new_preheader,
   vector_header_ = vector_preheader_->GetSingleSuccessor();
@@ -917,7 +1004,7 @@
   // (4) vectorizable right-hand-side value.
   uint64_t restrictions = kNone;
   if (instruction->IsArraySet()) {
-    Primitive::Type type = instruction->AsArraySet()->GetComponentType();
+    DataType::Type type = instruction->AsArraySet()->GetComponentType();
     HInstruction* base = instruction->InputAt(0);
     HInstruction* index = instruction->InputAt(1);
     HInstruction* value = instruction->InputAt(2);
@@ -941,9 +1028,11 @@
   // (2) vectorizable right-hand-side value.
   auto redit = reductions_->find(instruction);
   if (redit != reductions_->end()) {
-    Primitive::Type type = instruction->GetType();
-    if (TrySetVectorType(type, &restrictions) &&
-        VectorizeUse(node, instruction, generate_code, type, restrictions)) {
+    DataType::Type type = instruction->GetType();
+    // Recognize SAD idiom or direct reduction.
+    if (VectorizeSADIdiom(node, instruction, generate_code, type, restrictions) ||
+        (TrySetVectorType(type, &restrictions) &&
+         VectorizeUse(node, instruction, generate_code, type, restrictions))) {
       if (generate_code) {
         HInstruction* new_red = vector_map_->Get(instruction);
         vector_permanent_map_->Put(new_red, vector_map_->Get(redit->second));
@@ -966,7 +1055,7 @@
 bool HLoopOptimization::VectorizeUse(LoopNode* node,
                                      HInstruction* instruction,
                                      bool generate_code,
-                                     Primitive::Type type,
+                                     DataType::Type type,
                                      uint64_t restrictions) {
   // Accept anything for which code has already been generated.
   if (generate_code) {
@@ -1027,16 +1116,22 @@
     // Accept particular type conversions.
     HTypeConversion* conversion = instruction->AsTypeConversion();
     HInstruction* opa = conversion->InputAt(0);
-    Primitive::Type from = conversion->GetInputType();
-    Primitive::Type to = conversion->GetResultType();
-    if ((to == Primitive::kPrimByte ||
-         to == Primitive::kPrimChar ||
-         to == Primitive::kPrimShort) && from == Primitive::kPrimInt) {
-      // Accept a "narrowing" type conversion from a "wider" computation for
-      // (1) conversion into final required type,
-      // (2) vectorizable operand,
-      // (3) "wider" operations cannot bring in higher order bits.
-      if (to == type && VectorizeUse(node, opa, generate_code, type, restrictions | kNoHiBits)) {
+    DataType::Type from = conversion->GetInputType();
+    DataType::Type to = conversion->GetResultType();
+    if (DataType::IsIntegralType(from) && DataType::IsIntegralType(to)) {
+      size_t size_vec = DataType::Size(type);
+      size_t size_from = DataType::Size(from);
+      size_t size_to = DataType::Size(to);
+      // Accept an integral conversion
+      // (1a) narrowing into vector type, "wider" operations cannot bring in higher order bits, or
+      // (1b) widening from at least vector type, and
+      // (2) vectorizable operand.
+      if ((size_to < size_from &&
+           size_to == size_vec &&
+           VectorizeUse(node, opa, generate_code, type, restrictions | kNoHiBits)) ||
+          (size_to >= size_from &&
+           size_from >= size_vec &&
+           VectorizeUse(node, opa, generate_code, type, restrictions))) {
         if (generate_code) {
           if (vector_mode_ == kVector) {
             vector_map_->Put(instruction, vector_map_->Get(opa));  // operand pass-through
@@ -1046,7 +1141,7 @@
         }
         return true;
       }
-    } else if (to == Primitive::kPrimFloat && from == Primitive::kPrimInt) {
+    } else if (to == DataType::Type::kFloat32 && from == DataType::Type::kInt32) {
       DCHECK_EQ(to, type);
       // Accept int to float conversion for
       // (1) supported int,
@@ -1088,7 +1183,7 @@
       return true;
     }
   } else if (instruction->IsShl() || instruction->IsShr() || instruction->IsUShr()) {
-    // Recognize vectorization idioms.
+    // Recognize halving add idiom.
     if (VectorizeHalvingAddIdiom(node, instruction, generate_code, type, restrictions)) {
       return true;
     }
@@ -1121,7 +1216,7 @@
     if (VectorizeUse(node, r, generate_code, type, restrictions) &&
         IsInt64AndGet(opb, /*out*/ &distance)) {
       // Restrict shift distance to packed data type width.
-      int64_t max_distance = Primitive::ComponentSize(type) * 8;
+      int64_t max_distance = DataType::Size(type) * 8;
       if (0 <= distance && distance < max_distance) {
         if (generate_code) {
           GenerateVecOp(instruction, vector_map_->Get(r), opb, type);
@@ -1181,7 +1276,8 @@
           return false;  // reject, unless all operands are same-extension narrower
         }
         // Accept MIN/MAX(x, y) for vectorizable operands.
-        DCHECK(r != nullptr && s != nullptr);
+        DCHECK(r != nullptr);
+        DCHECK(s != nullptr);
         if (generate_code && vector_mode_ != kVector) {  // de-idiom
           r = opa;
           s = opb;
@@ -1203,7 +1299,7 @@
   return false;
 }
 
-bool HLoopOptimization::TrySetVectorType(Primitive::Type type, uint64_t* restrictions) {
+bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrictions) {
   const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures();
   switch (compiler_driver_->GetInstructionSet()) {
     case kArm:
@@ -1211,15 +1307,15 @@
       // Allow vectorization for all ARM devices, because Android assumes that
       // ARM 32-bit always supports advanced SIMD (64-bit SIMD).
       switch (type) {
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimByte:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8:
           *restrictions |= kNoDiv | kNoReduction;
           return TrySetVectorLength(8);
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
           *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction;
           return TrySetVectorLength(4);
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt32:
           *restrictions |= kNoDiv | kNoReduction;
           return TrySetVectorLength(2);
         default:
@@ -1230,24 +1326,24 @@
       // Allow vectorization for all ARM devices, because Android assumes that
       // ARMv8 AArch64 always supports advanced SIMD (128-bit SIMD).
       switch (type) {
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimByte:
-          *restrictions |= kNoDiv | kNoReduction;
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8:
+          *restrictions |= kNoDiv;
           return TrySetVectorLength(16);
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort:
-          *restrictions |= kNoDiv | kNoReduction;
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+          *restrictions |= kNoDiv;
           return TrySetVectorLength(8);
-        case Primitive::kPrimInt:
+        case DataType::Type::kInt32:
           *restrictions |= kNoDiv;
           return TrySetVectorLength(4);
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           *restrictions |= kNoDiv | kNoMul | kNoMinMax;
           return TrySetVectorLength(2);
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           *restrictions |= kNoReduction;
           return TrySetVectorLength(4);
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           *restrictions |= kNoReduction;
           return TrySetVectorLength(2);
         default:
@@ -1258,25 +1354,25 @@
       // Allow vectorization for SSE4.1-enabled X86 devices only (128-bit SIMD).
       if (features->AsX86InstructionSetFeatures()->HasSSE4_1()) {
         switch (type) {
-          case Primitive::kPrimBoolean:
-          case Primitive::kPrimByte:
+          case DataType::Type::kBool:
+          case DataType::Type::kInt8:
             *restrictions |=
-                kNoMul | kNoDiv | kNoShift | kNoAbs | kNoSignedHAdd | kNoUnroundedHAdd | kNoReduction;
+                kNoMul | kNoDiv | kNoShift | kNoAbs | kNoSignedHAdd | kNoUnroundedHAdd | kNoSAD;
             return TrySetVectorLength(16);
-          case Primitive::kPrimChar:
-          case Primitive::kPrimShort:
-            *restrictions |= kNoDiv | kNoAbs | kNoSignedHAdd | kNoUnroundedHAdd | kNoReduction;
+          case DataType::Type::kUint16:
+          case DataType::Type::kInt16:
+            *restrictions |= kNoDiv | kNoAbs | kNoSignedHAdd | kNoUnroundedHAdd | kNoSAD;
             return TrySetVectorLength(8);
-          case Primitive::kPrimInt:
-            *restrictions |= kNoDiv;
+          case DataType::Type::kInt32:
+            *restrictions |= kNoDiv | kNoSAD;
             return TrySetVectorLength(4);
-          case Primitive::kPrimLong:
-            *restrictions |= kNoMul | kNoDiv | kNoShr | kNoAbs | kNoMinMax;
+          case DataType::Type::kInt64:
+            *restrictions |= kNoMul | kNoDiv | kNoShr | kNoAbs | kNoMinMax | kNoSAD;
             return TrySetVectorLength(2);
-          case Primitive::kPrimFloat:
+          case DataType::Type::kFloat32:
             *restrictions |= kNoMinMax | kNoReduction;  // minmax: -0.0 vs +0.0
             return TrySetVectorLength(4);
-          case Primitive::kPrimDouble:
+          case DataType::Type::kFloat64:
             *restrictions |= kNoMinMax | kNoReduction;  // minmax: -0.0 vs +0.0
             return TrySetVectorLength(2);
           default:
@@ -1287,24 +1383,24 @@
     case kMips:
       if (features->AsMipsInstructionSetFeatures()->HasMsa()) {
         switch (type) {
-          case Primitive::kPrimBoolean:
-          case Primitive::kPrimByte:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kBool:
+          case DataType::Type::kInt8:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(16);
-          case Primitive::kPrimChar:
-          case Primitive::kPrimShort:
-            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction;
+          case DataType::Type::kUint16:
+          case DataType::Type::kInt16:
+            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
             return TrySetVectorLength(8);
-          case Primitive::kPrimInt:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kInt32:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(4);
-          case Primitive::kPrimLong:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kInt64:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(2);
-          case Primitive::kPrimFloat:
+          case DataType::Type::kFloat32:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
             return TrySetVectorLength(4);
-          case Primitive::kPrimDouble:
+          case DataType::Type::kFloat64:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
             return TrySetVectorLength(2);
           default:
@@ -1315,24 +1411,24 @@
     case kMips64:
       if (features->AsMips64InstructionSetFeatures()->HasMsa()) {
         switch (type) {
-          case Primitive::kPrimBoolean:
-          case Primitive::kPrimByte:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kBool:
+          case DataType::Type::kInt8:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(16);
-          case Primitive::kPrimChar:
-          case Primitive::kPrimShort:
-            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction;
+          case DataType::Type::kUint16:
+          case DataType::Type::kInt16:
+            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
             return TrySetVectorLength(8);
-          case Primitive::kPrimInt:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kInt32:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(4);
-          case Primitive::kPrimLong:
-            *restrictions |= kNoDiv | kNoReduction;
+          case DataType::Type::kInt64:
+            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
             return TrySetVectorLength(2);
-          case Primitive::kPrimFloat:
+          case DataType::Type::kFloat32:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
             return TrySetVectorLength(4);
-          case Primitive::kPrimDouble:
+          case DataType::Type::kFloat64:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
             return TrySetVectorLength(2);
           default:
@@ -1357,7 +1453,7 @@
   return vector_length_ == length;
 }
 
-void HLoopOptimization::GenerateVecInv(HInstruction* org, Primitive::Type type) {
+void HLoopOptimization::GenerateVecInv(HInstruction* org, DataType::Type type) {
   if (vector_map_->find(org) == vector_map_->end()) {
     // In scalar code, just use a self pass-through for scalar invariants
     // (viz. expression remains itself).
@@ -1371,8 +1467,16 @@
     if (it != vector_permanent_map_->end()) {
       vector = it->second;  // reuse during unrolling
     } else {
-      vector = new (global_allocator_) HVecReplicateScalar(
-          global_allocator_, org, type, vector_length_);
+      // Generates ReplicateScalar( (optional_type_conv) org ).
+      HInstruction* input = org;
+      DataType::Type input_type = input->GetType();
+      if (type != input_type && (type == DataType::Type::kInt64 ||
+                                 input_type == DataType::Type::kInt64)) {
+        input = Insert(vector_preheader_,
+                       new (global_allocator_) HTypeConversion(type, input, kNoDexPc));
+      }
+      vector = new (global_allocator_)
+          HVecReplicateScalar(global_allocator_, input, type, vector_length_);
       vector_permanent_map_->Put(org, Insert(vector_preheader_, vector));
     }
     vector_map_->Put(org, vector);
@@ -1384,7 +1488,7 @@
     HInstruction* subscript = vector_index_;
     int64_t value = 0;
     if (!IsInt64AndGet(offset, &value) || value != 0) {
-      subscript = new (global_allocator_) HAdd(Primitive::kPrimInt, subscript, offset);
+      subscript = new (global_allocator_) HAdd(DataType::Type::kInt32, subscript, offset);
       if (org->IsPhi()) {
         Insert(vector_body_, subscript);  // lacks layout placeholder
       }
@@ -1397,7 +1501,7 @@
                                        HInstruction* opa,
                                        HInstruction* opb,
                                        HInstruction* offset,
-                                       Primitive::Type type) {
+                                       DataType::Type type) {
   HInstruction* vector = nullptr;
   if (vector_mode_ == kVector) {
     // Vector store or load.
@@ -1465,10 +1569,15 @@
   // Prepare the new initialization.
   if (vector_mode_ == kVector) {
     // Generate a [initial, 0, .., 0] vector.
-    new_init = Insert(
-            vector_preheader_,
-            new (global_allocator_) HVecSetScalars(
-                global_allocator_, &new_init, phi->GetType(), vector_length_, 1));
+    HVecOperation* red_vector = new_red->AsVecOperation();
+    size_t vector_length = red_vector->GetVectorLength();
+    DataType::Type type = red_vector->GetPackedType();
+    new_init = Insert(vector_preheader_,
+                      new (global_allocator_) HVecSetScalars(global_allocator_,
+                                                             &new_init,
+                                                             type,
+                                                             vector_length,
+                                                             1));
   } else {
     new_init = ReduceAndExtractIfNeeded(new_init);
   }
@@ -1484,18 +1593,20 @@
   if (instruction->IsPhi()) {
     HInstruction* input = instruction->InputAt(1);
     if (input->IsVecOperation()) {
-      Primitive::Type type = input->AsVecOperation()->GetPackedType();
+      HVecOperation* input_vector = input->AsVecOperation();
+      size_t vector_length = input_vector->GetVectorLength();
+      DataType::Type type = input_vector->GetPackedType();
+      HVecReduce::ReductionKind kind = GetReductionKind(input_vector);
       HBasicBlock* exit = instruction->GetBlock()->GetSuccessors()[0];
       // Generate a vector reduction and scalar extract
       //    x = REDUCE( [x_1, .., x_n] )
       //    y = x_1
       // along the exit of the defining loop.
-      HVecReduce::ReductionKind kind = GetReductionKind(input);
       HInstruction* reduce = new (global_allocator_) HVecReduce(
-          global_allocator_, instruction, type, vector_length_, kind);
+          global_allocator_, instruction, type, vector_length, kind);
       exit->InsertInstructionBefore(reduce, exit->GetFirstInstruction());
       instruction = new (global_allocator_) HVecExtractScalar(
-          global_allocator_, reduce, type, vector_length_, 0);
+          global_allocator_, reduce, type, vector_length, 0);
       exit->InsertInstructionAfter(instruction, reduce);
     }
   }
@@ -1514,29 +1625,21 @@
 void HLoopOptimization::GenerateVecOp(HInstruction* org,
                                       HInstruction* opa,
                                       HInstruction* opb,
-                                      Primitive::Type type,
+                                      DataType::Type type,
                                       bool is_unsigned) {
-  if (vector_mode_ == kSequential) {
-    // Non-converting scalar code follows implicit integral promotion.
-    if (!org->IsTypeConversion() && (type == Primitive::kPrimBoolean ||
-                                     type == Primitive::kPrimByte ||
-                                     type == Primitive::kPrimChar ||
-                                     type == Primitive::kPrimShort)) {
-      type = Primitive::kPrimInt;
-    }
-  }
   HInstruction* vector = nullptr;
+  DataType::Type org_type = org->GetType();
   switch (org->GetKind()) {
     case HInstruction::kNeg:
       DCHECK(opb == nullptr);
       GENERATE_VEC(
           new (global_allocator_) HVecNeg(global_allocator_, opa, type, vector_length_),
-          new (global_allocator_) HNeg(type, opa));
+          new (global_allocator_) HNeg(org_type, opa));
     case HInstruction::kNot:
       DCHECK(opb == nullptr);
       GENERATE_VEC(
           new (global_allocator_) HVecNot(global_allocator_, opa, type, vector_length_),
-          new (global_allocator_) HNot(type, opa));
+          new (global_allocator_) HNot(org_type, opa));
     case HInstruction::kBooleanNot:
       DCHECK(opb == nullptr);
       GENERATE_VEC(
@@ -1546,47 +1649,47 @@
       DCHECK(opb == nullptr);
       GENERATE_VEC(
           new (global_allocator_) HVecCnv(global_allocator_, opa, type, vector_length_),
-          new (global_allocator_) HTypeConversion(type, opa, kNoDexPc));
+          new (global_allocator_) HTypeConversion(org_type, opa, kNoDexPc));
     case HInstruction::kAdd:
       GENERATE_VEC(
           new (global_allocator_) HVecAdd(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HAdd(type, opa, opb));
+          new (global_allocator_) HAdd(org_type, opa, opb));
     case HInstruction::kSub:
       GENERATE_VEC(
           new (global_allocator_) HVecSub(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HSub(type, opa, opb));
+          new (global_allocator_) HSub(org_type, opa, opb));
     case HInstruction::kMul:
       GENERATE_VEC(
           new (global_allocator_) HVecMul(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HMul(type, opa, opb));
+          new (global_allocator_) HMul(org_type, opa, opb));
     case HInstruction::kDiv:
       GENERATE_VEC(
           new (global_allocator_) HVecDiv(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HDiv(type, opa, opb, kNoDexPc));
+          new (global_allocator_) HDiv(org_type, opa, opb, kNoDexPc));
     case HInstruction::kAnd:
       GENERATE_VEC(
           new (global_allocator_) HVecAnd(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HAnd(type, opa, opb));
+          new (global_allocator_) HAnd(org_type, opa, opb));
     case HInstruction::kOr:
       GENERATE_VEC(
           new (global_allocator_) HVecOr(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HOr(type, opa, opb));
+          new (global_allocator_) HOr(org_type, opa, opb));
     case HInstruction::kXor:
       GENERATE_VEC(
           new (global_allocator_) HVecXor(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HXor(type, opa, opb));
+          new (global_allocator_) HXor(org_type, opa, opb));
     case HInstruction::kShl:
       GENERATE_VEC(
           new (global_allocator_) HVecShl(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HShl(type, opa, opb));
+          new (global_allocator_) HShl(org_type, opa, opb));
     case HInstruction::kShr:
       GENERATE_VEC(
           new (global_allocator_) HVecShr(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HShr(type, opa, opb));
+          new (global_allocator_) HShr(org_type, opa, opb));
     case HInstruction::kUShr:
       GENERATE_VEC(
           new (global_allocator_) HVecUShr(global_allocator_, opa, opb, type, vector_length_),
-          new (global_allocator_) HUShr(type, opa, opb));
+          new (global_allocator_) HUShr(org_type, opa, opb));
     case HInstruction::kInvokeStaticOrDirect: {
       HInvokeStaticOrDirect* invoke = org->AsInvokeStaticOrDirect();
       if (vector_mode_ == kVector) {
@@ -1667,8 +1770,8 @@
 //
 
 // Method recognizes the following idioms:
-//   rounding halving add (a + b + 1) >> 1 for unsigned/signed operands a, b
-//   regular  halving add (a + b)     >> 1 for unsigned/signed operands a, b
+//   rounding  halving add (a + b + 1) >> 1 for unsigned/signed operands a, b
+//   truncated halving add (a + b)     >> 1 for unsigned/signed operands a, b
 // Provided that the operands are promoted to a wider form to do the arithmetic and
 // then cast back to narrower form, the idioms can be mapped into efficient SIMD
 // implementation that operates directly in narrower form (plus one extra bit).
@@ -1677,7 +1780,7 @@
 bool HLoopOptimization::VectorizeHalvingAddIdiom(LoopNode* node,
                                                  HInstruction* instruction,
                                                  bool generate_code,
-                                                 Primitive::Type type,
+                                                 DataType::Type type,
                                                  uint64_t restrictions) {
   // Test for top level arithmetic shift right x >> 1 or logical shift right x >>> 1
   // (note whether the sign bit in wider precision is shifted in has no effect
@@ -1712,7 +1815,8 @@
       }
       // Accept recognized halving add for vectorizable operands. Vectorized code uses the
       // shorthand idiomatic operation. Sequential code uses the original scalar expressions.
-      DCHECK(r != nullptr && s != nullptr);
+      DCHECK(r != nullptr);
+      DCHECK(s != nullptr);
       if (generate_code && vector_mode_ != kVector) {  // de-idiom
         r = instruction->InputAt(0);
         s = instruction->InputAt(1);
@@ -1741,6 +1845,88 @@
   return false;
 }
 
+// Method recognizes the following idiom:
+//   q += ABS(a - b) for signed operands a, b
+// Provided that the operands have the same type or are promoted to a wider form.
+// Since this may involve a vector length change, the idiom is handled by going directly
+// to a sad-accumulate node (rather than relying combining finer grained nodes later).
+// TODO: unsigned SAD too?
+bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node,
+                                          HInstruction* instruction,
+                                          bool generate_code,
+                                          DataType::Type reduction_type,
+                                          uint64_t restrictions) {
+  // Filter integral "q += ABS(a - b);" reduction, where ABS and SUB
+  // are done in the same precision (either int or long).
+  if (!instruction->IsAdd() ||
+      (reduction_type != DataType::Type::kInt32 && reduction_type != DataType::Type::kInt64)) {
+    return false;
+  }
+  HInstruction* q = instruction->InputAt(0);
+  HInstruction* v = instruction->InputAt(1);
+  HInstruction* a = nullptr;
+  HInstruction* b = nullptr;
+  if (v->IsInvokeStaticOrDirect() &&
+       (v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsInt ||
+        v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsLong)) {
+    HInstruction* x = v->InputAt(0);
+    if (x->IsSub() && x->GetType() == reduction_type) {
+      a = x->InputAt(0);
+      b = x->InputAt(1);
+    }
+  }
+  if (a == nullptr || b == nullptr) {
+    return false;
+  }
+  // Accept same-type or consistent sign extension for narrower-type on operands a and b.
+  // The same-type or narrower operands are called r (a or lower) and s (b or lower).
+  HInstruction* r = a;
+  HInstruction* s = b;
+  bool is_unsigned = false;
+  DataType::Type sub_type = a->GetType();
+  if (a->IsTypeConversion()) {
+    sub_type = a->InputAt(0)->GetType();
+  } else if (b->IsTypeConversion()) {
+    sub_type = b->InputAt(0)->GetType();
+  }
+  if (reduction_type != sub_type &&
+      (!IsNarrowerOperands(a, b, sub_type, &r, &s, &is_unsigned) || is_unsigned)) {
+    return false;
+  }
+  // Try same/narrower type and deal with vector restrictions.
+  if (!TrySetVectorType(sub_type, &restrictions) || HasVectorRestrictions(restrictions, kNoSAD)) {
+    return false;
+  }
+  // Accept SAD idiom for vectorizable operands. Vectorized code uses the shorthand
+  // idiomatic operation. Sequential code uses the original scalar expressions.
+  DCHECK(r != nullptr);
+  DCHECK(s != nullptr);
+  if (generate_code && vector_mode_ != kVector) {  // de-idiom
+    r = s = v->InputAt(0);
+  }
+  if (VectorizeUse(node, q, generate_code, sub_type, restrictions) &&
+      VectorizeUse(node, r, generate_code, sub_type, restrictions) &&
+      VectorizeUse(node, s, generate_code, sub_type, restrictions)) {
+    if (generate_code) {
+      if (vector_mode_ == kVector) {
+        vector_map_->Put(instruction, new (global_allocator_) HVecSADAccumulate(
+            global_allocator_,
+            vector_map_->Get(q),
+            vector_map_->Get(r),
+            vector_map_->Get(s),
+            reduction_type,
+            GetOtherVL(reduction_type, sub_type, vector_length_)));
+        MaybeRecordStat(stats_, MethodCompilationStat::kLoopVectorizedIdiom);
+      } else {
+        GenerateVecOp(v, vector_map_->Get(r), nullptr, reduction_type);
+        GenerateVecOp(instruction, vector_map_->Get(q), vector_map_->Get(v), reduction_type);
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
 //
 // Vectorization heuristics.
 //
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index f347518..6e6e387 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -75,6 +75,7 @@
     kNoMinMax        = 1 << 8,   // no min/max
     kNoStringCharAt  = 1 << 9,   // no StringCharAt
     kNoReduction     = 1 << 10,  // no reduction
+    kNoSAD           = 1 << 11,  // no sum of absolute differences (SAD)
   };
 
   /*
@@ -90,7 +91,7 @@
    * Representation of a unit-stride array reference.
    */
   struct ArrayReference {
-    ArrayReference(HInstruction* b, HInstruction* o, Primitive::Type t, bool l)
+    ArrayReference(HInstruction* b, HInstruction* o, DataType::Type t, bool l)
         : base(b), offset(o), type(t), lhs(l) { }
     bool operator<(const ArrayReference& other) const {
       return
@@ -102,7 +103,7 @@
     }
     HInstruction* base;    // base address
     HInstruction* offset;  // offset + i
-    Primitive::Type type;  // component type
+    DataType::Type type;   // component type
     bool lhs;              // def/use
   };
 
@@ -146,32 +147,37 @@
   bool VectorizeUse(LoopNode* node,
                     HInstruction* instruction,
                     bool generate_code,
-                    Primitive::Type type,
+                    DataType::Type type,
                     uint64_t restrictions);
-  bool TrySetVectorType(Primitive::Type type, /*out*/ uint64_t* restrictions);
+  bool TrySetVectorType(DataType::Type type, /*out*/ uint64_t* restrictions);
   bool TrySetVectorLength(uint32_t length);
-  void GenerateVecInv(HInstruction* org, Primitive::Type type);
+  void GenerateVecInv(HInstruction* org, DataType::Type type);
   void GenerateVecSub(HInstruction* org, HInstruction* offset);
   void GenerateVecMem(HInstruction* org,
                       HInstruction* opa,
                       HInstruction* opb,
                       HInstruction* offset,
-                      Primitive::Type type);
+                      DataType::Type type);
   void GenerateVecReductionPhi(HPhi* phi);
   void GenerateVecReductionPhiInputs(HPhi* phi, HInstruction* reduction);
   HInstruction* ReduceAndExtractIfNeeded(HInstruction* instruction);
   void GenerateVecOp(HInstruction* org,
                      HInstruction* opa,
                      HInstruction* opb,
-                     Primitive::Type type,
+                     DataType::Type type,
                      bool is_unsigned = false);
 
   // Vectorization idioms.
   bool VectorizeHalvingAddIdiom(LoopNode* node,
                                 HInstruction* instruction,
                                 bool generate_code,
-                                Primitive::Type type,
+                                DataType::Type type,
                                 uint64_t restrictions);
+  bool VectorizeSADIdiom(LoopNode* node,
+                         HInstruction* instruction,
+                         bool generate_code,
+                         DataType::Type type,
+                         uint64_t restrictions);
 
   // Vectorization heuristics.
   bool IsVectorizationProfitable(int64_t trip_count);
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 1c5603d..95718ae 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -51,7 +51,7 @@
     parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                    dex::TypeIndex(0),
                                                    0,
-                                                   Primitive::kPrimInt);
+                                                   DataType::Type::kInt32);
     entry_block_->AddInstruction(parameter_);
     return_block_->AddInstruction(new (&allocator_) HReturnVoid());
     exit_block_->AddInstruction(new (&allocator_) HExit());
@@ -216,8 +216,8 @@
   header->AddInstruction(new (&allocator_) HIf(parameter_));
   body->AddInstruction(new (&allocator_) HGoto());
 
-  HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
-  HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, phi, parameter_);
+  HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
+  HInstruction* add = new (&allocator_) HAdd(DataType::Type::kInt32, phi, parameter_);
   header->AddPhi(phi);
   body->AddInstruction(add);
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 9cff6b0..41ea998 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -564,7 +564,7 @@
   // id and/or any invariants the graph is assuming when adding new instructions.
   if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
     cached_current_method_ = new (arena_) HCurrentMethod(
-        Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt,
+        Is64BitInstructionSet(instruction_set_) ? DataType::Type::kInt64 : DataType::Type::kInt32,
         entry_block_->GetDexPc());
     if (entry_block_->GetFirstInstruction() == nullptr) {
       entry_block_->AddInstruction(cached_current_method_);
@@ -585,19 +585,19 @@
   return dex_file_.PrettyMethod(method_idx_, with_signature);
 }
 
-HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc) {
+HConstant* HGraph::GetConstant(DataType::Type type, int64_t value, uint32_t dex_pc) {
   switch (type) {
-    case Primitive::Type::kPrimBoolean:
+    case DataType::Type::kBool:
       DCHECK(IsUint<1>(value));
       FALLTHROUGH_INTENDED;
-    case Primitive::Type::kPrimByte:
-    case Primitive::Type::kPrimChar:
-    case Primitive::Type::kPrimShort:
-    case Primitive::Type::kPrimInt:
-      DCHECK(IsInt(Primitive::ComponentSize(type) * kBitsPerByte, value));
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+    case DataType::Type::kInt32:
+      DCHECK(IsInt(DataType::Size(type) * kBitsPerByte, value));
       return GetIntConstant(static_cast<int32_t>(value), dex_pc);
 
-    case Primitive::Type::kPrimLong:
+    case DataType::Type::kInt64:
       return GetLongConstant(value, dex_pc);
 
     default:
@@ -838,9 +838,9 @@
     // We can only replace a control flow instruction with another control flow instruction.
     DCHECK(replacement->IsControlFlow());
     DCHECK_EQ(replacement->GetId(), -1);
-    DCHECK_EQ(replacement->GetType(), Primitive::kPrimVoid);
+    DCHECK_EQ(replacement->GetType(), DataType::Type::kVoid);
     DCHECK_EQ(initial->GetBlock(), this);
-    DCHECK_EQ(initial->GetType(), Primitive::kPrimVoid);
+    DCHECK_EQ(initial->GetType(), DataType::Type::kVoid);
     DCHECK(initial->GetUses().empty());
     DCHECK(initial->GetEnvUses().empty());
     replacement->SetBlock(this);
@@ -1219,7 +1219,7 @@
 size_t HConstructorFence::RemoveConstructorFences(HInstruction* instruction) {
   DCHECK(instruction->GetBlock() != nullptr);
   // Removing constructor fences only makes sense for instructions with an object return type.
-  DCHECK_EQ(Primitive::kPrimNot, instruction->GetType());
+  DCHECK_EQ(DataType::Type::kReference, instruction->GetType());
 
   // Return how many instructions were removed for statistic purposes.
   size_t remove_count = 0;
@@ -1382,11 +1382,11 @@
   if (GetInput()->IsIntConstant()) {
     int32_t value = GetInput()->AsIntConstant()->GetValue();
     switch (GetResultType()) {
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
-      case Primitive::kPrimFloat:
+      case DataType::Type::kFloat32:
         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat64:
         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
@@ -1394,11 +1394,11 @@
   } else if (GetInput()->IsLongConstant()) {
     int64_t value = GetInput()->AsLongConstant()->GetValue();
     switch (GetResultType()) {
-      case Primitive::kPrimInt:
+      case DataType::Type::kInt32:
         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
-      case Primitive::kPrimFloat:
+      case DataType::Type::kFloat32:
         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat64:
         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
@@ -1406,7 +1406,7 @@
   } else if (GetInput()->IsFloatConstant()) {
     float value = GetInput()->AsFloatConstant()->GetValue();
     switch (GetResultType()) {
-      case Primitive::kPrimInt:
+      case DataType::Type::kInt32:
         if (std::isnan(value))
           return graph->GetIntConstant(0, GetDexPc());
         if (value >= kPrimIntMax)
@@ -1414,7 +1414,7 @@
         if (value <= kPrimIntMin)
           return graph->GetIntConstant(kPrimIntMin, GetDexPc());
         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         if (std::isnan(value))
           return graph->GetLongConstant(0, GetDexPc());
         if (value >= kPrimLongMax)
@@ -1422,7 +1422,7 @@
         if (value <= kPrimLongMin)
           return graph->GetLongConstant(kPrimLongMin, GetDexPc());
         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
-      case Primitive::kPrimDouble:
+      case DataType::Type::kFloat64:
         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
@@ -1430,7 +1430,7 @@
   } else if (GetInput()->IsDoubleConstant()) {
     double value = GetInput()->AsDoubleConstant()->GetValue();
     switch (GetResultType()) {
-      case Primitive::kPrimInt:
+      case DataType::Type::kInt32:
         if (std::isnan(value))
           return graph->GetIntConstant(0, GetDexPc());
         if (value >= kPrimIntMax)
@@ -1438,7 +1438,7 @@
         if (value <= kPrimLongMin)
           return graph->GetIntConstant(kPrimIntMin, GetDexPc());
         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
-      case Primitive::kPrimLong:
+      case DataType::Type::kInt64:
         if (std::isnan(value))
           return graph->GetLongConstant(0, GetDexPc());
         if (value >= kPrimLongMax)
@@ -1446,7 +1446,7 @@
         if (value <= kPrimLongMin)
           return graph->GetLongConstant(kPrimLongMin, GetDexPc());
         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
-      case Primitive::kPrimFloat:
+      case DataType::Type::kFloat32:
         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
       default:
         return nullptr;
@@ -2604,7 +2604,7 @@
 
 void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) {
   if (kIsDebugBuild) {
-    DCHECK_EQ(GetType(), Primitive::kPrimNot);
+    DCHECK_EQ(GetType(), DataType::Type::kReference);
     ScopedObjectAccess soa(Thread::Current());
     DCHECK(rti.IsValid()) << "Invalid RTI for " << DebugName();
     if (IsBoundType()) {
@@ -2893,7 +2893,7 @@
   ArenaAllocator* allocator = GetArena();
 
   if (cond->IsCondition() &&
-      !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType())) {
+      !DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) {
     // Can't reverse floating point conditions.  We have to use HBooleanNot in that case.
     HInstruction* lhs = cond->InputAt(0);
     HInstruction* rhs = cond->InputAt(1);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index a6d0da1..c49cee3 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -28,6 +28,7 @@
 #include "base/iteration_range.h"
 #include "base/stl_util.h"
 #include "base/transform_array_ref.h"
+#include "data_type.h"
 #include "deoptimization_kind.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
@@ -40,7 +41,6 @@
 #include "method_reference.h"
 #include "mirror/class.h"
 #include "offsets.h"
-#include "primitive.h"
 #include "utils/intrusive_forward_list.h"
 
 namespace art {
@@ -511,7 +511,7 @@
   // Returns a constant of the given type and value. If it does not exist
   // already, it is created and inserted into the graph. This method is only for
   // integral types.
-  HConstant* GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc = kNoDexPc);
+  HConstant* GetConstant(DataType::Type type, int64_t value, uint32_t dex_pc = kNoDexPc);
 
   // TODO: This is problematic for the consistency of reference type propagation
   // because it can be created anytime after the pass and thus it will be left
@@ -1396,6 +1396,7 @@
   M(VecUShr, VecBinaryOperation)                                        \
   M(VecSetScalars, VecOperation)                                        \
   M(VecMultiplyAccumulate, VecOperation)                                \
+  M(VecSADAccumulate, VecOperation)                                     \
   M(VecLoad, VecMemoryOperation)                                        \
   M(VecStore, VecMemoryOperation)                                       \
 
@@ -1566,7 +1567,7 @@
  * The internal representation uses 38-bit and is described in the table below.
  * The first line indicates the side effect, and for field/array accesses the
  * second line indicates the type of the access (in the order of the
- * Primitive::Type enum).
+ * DataType::Type enum).
  * The two numbered lines below indicate the bit position in the bitfield (read
  * vertically).
  *
@@ -1615,23 +1616,23 @@
     return SideEffects(kAllReads);
   }
 
-  static SideEffects FieldWriteOfType(Primitive::Type type, bool is_volatile) {
+  static SideEffects FieldWriteOfType(DataType::Type type, bool is_volatile) {
     return is_volatile
         ? AllWritesAndReads()
         : SideEffects(TypeFlag(type, kFieldWriteOffset));
   }
 
-  static SideEffects ArrayWriteOfType(Primitive::Type type) {
+  static SideEffects ArrayWriteOfType(DataType::Type type) {
     return SideEffects(TypeFlag(type, kArrayWriteOffset));
   }
 
-  static SideEffects FieldReadOfType(Primitive::Type type, bool is_volatile) {
+  static SideEffects FieldReadOfType(DataType::Type type, bool is_volatile) {
     return is_volatile
         ? AllWritesAndReads()
         : SideEffects(TypeFlag(type, kFieldReadOffset));
   }
 
-  static SideEffects ArrayReadOfType(Primitive::Type type) {
+  static SideEffects ArrayReadOfType(DataType::Type type) {
     return SideEffects(TypeFlag(type, kArrayReadOffset));
   }
 
@@ -1760,13 +1761,13 @@
       ((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset;
 
   // Translates type to bit flag.
-  static uint64_t TypeFlag(Primitive::Type type, int offset) {
-    CHECK_NE(type, Primitive::kPrimVoid);
+  static uint64_t TypeFlag(DataType::Type type, int offset) {
+    CHECK_NE(type, DataType::Type::kVoid);
     const uint64_t one = 1;
-    const int shift = type;  // 0-based consecutive enum
+    const int shift = static_cast<int>(type);  // 0-based consecutive enum
     DCHECK_LE(kFieldWriteOffset, shift);
     DCHECK_LT(shift, kArrayWriteOffset);
-    return one << (type + offset);
+    return one << (shift + offset);
   }
 
   // Private constructor on direct flags value.
@@ -1955,7 +1956,7 @@
   virtual void Accept(HGraphVisitor* visitor) = 0;
   virtual const char* DebugName() const = 0;
 
-  virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; }
+  virtual DataType::Type GetType() const { return DataType::Type::kVoid; }
 
   virtual bool NeedsEnvironment() const { return false; }
 
@@ -1976,7 +1977,7 @@
   // simplifies the null check elimination.
   // TODO: Consider merging can_be_null into ReferenceTypeInfo.
   virtual bool CanBeNull() const {
-    DCHECK_EQ(GetType(), Primitive::kPrimNot) << "CanBeNull only applies to reference types";
+    DCHECK_EQ(GetType(), DataType::Type::kReference) << "CanBeNull only applies to reference types";
     return true;
   }
 
@@ -1985,13 +1986,13 @@
   }
 
   virtual bool IsActualObject() const {
-    return GetType() == Primitive::kPrimNot;
+    return GetType() == DataType::Type::kReference;
   }
 
   void SetReferenceTypeInfo(ReferenceTypeInfo rti);
 
   ReferenceTypeInfo GetReferenceTypeInfo() const {
-    DCHECK_EQ(GetType(), Primitive::kPrimNot);
+    DCHECK_EQ(GetType(), DataType::Type::kReference);
     return ReferenceTypeInfo::CreateUnchecked(reference_type_handle_,
                                               GetPackedFlag<kFlagReferenceTypeIsExact>());
   }
@@ -2504,24 +2505,24 @@
 template<intptr_t N>
 class HExpression : public HTemplateInstruction<N> {
  public:
-  HExpression<N>(Primitive::Type type, SideEffects side_effects, uint32_t dex_pc)
+  HExpression<N>(DataType::Type type, SideEffects side_effects, uint32_t dex_pc)
       : HTemplateInstruction<N>(side_effects, dex_pc) {
     this->template SetPackedField<TypeField>(type);
   }
   virtual ~HExpression() {}
 
-  Primitive::Type GetType() const OVERRIDE {
+  DataType::Type GetType() const OVERRIDE {
     return TypeField::Decode(this->GetPackedFields());
   }
 
  protected:
   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kNumberOfExpressionPackedBits = kFieldType + kFieldTypeSize;
   static_assert(kNumberOfExpressionPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-  using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
+  using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
 };
 
 // Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
@@ -2561,7 +2562,7 @@
   HPhi(ArenaAllocator* arena,
        uint32_t reg_number,
        size_t number_of_inputs,
-       Primitive::Type type,
+       DataType::Type type,
        uint32_t dex_pc = kNoDexPc)
       : HVariableInputSizeInstruction(
             SideEffects::None(),
@@ -2571,7 +2572,7 @@
             kArenaAllocPhiInputs),
         reg_number_(reg_number) {
     SetPackedField<TypeField>(ToPhiType(type));
-    DCHECK_NE(GetType(), Primitive::kPrimVoid);
+    DCHECK_NE(GetType(), DataType::Type::kVoid);
     // Phis are constructed live and marked dead if conflicting or unused.
     // Individual steps of SsaBuilder should assume that if a phi has been
     // marked dead, it can be ignored and will be removed by SsaPhiElimination.
@@ -2580,21 +2581,21 @@
   }
 
   // Returns a type equivalent to the given `type`, but that a `HPhi` can hold.
-  static Primitive::Type ToPhiType(Primitive::Type type) {
-    return Primitive::PrimitiveKind(type);
+  static DataType::Type ToPhiType(DataType::Type type) {
+    return DataType::Kind(type);
   }
 
   bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
 
-  Primitive::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); }
-  void SetType(Primitive::Type new_type) {
+  DataType::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); }
+  void SetType(DataType::Type new_type) {
     // Make sure that only valid type changes occur. The following are allowed:
     //  (1) int  -> float/ref (primitive type propagation),
     //  (2) long -> double (primitive type propagation).
     DCHECK(GetType() == new_type ||
-           (GetType() == Primitive::kPrimInt && new_type == Primitive::kPrimFloat) ||
-           (GetType() == Primitive::kPrimInt && new_type == Primitive::kPrimNot) ||
-           (GetType() == Primitive::kPrimLong && new_type == Primitive::kPrimDouble));
+           (GetType() == DataType::Type::kInt32 && new_type == DataType::Type::kFloat32) ||
+           (GetType() == DataType::Type::kInt32 && new_type == DataType::Type::kReference) ||
+           (GetType() == DataType::Type::kInt64 && new_type == DataType::Type::kFloat64));
     SetPackedField<TypeField>(new_type);
   }
 
@@ -2644,12 +2645,12 @@
  private:
   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kFlagIsLive = kFieldType + kFieldTypeSize;
   static constexpr size_t kFlagCanBeNull = kFlagIsLive + 1;
   static constexpr size_t kNumberOfPhiPackedBits = kFlagCanBeNull + 1;
   static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-  using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
+  using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
 
   const uint32_t reg_number_;
 
@@ -2690,7 +2691,7 @@
 
 class HConstant : public HExpression<0> {
  public:
-  explicit HConstant(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+  explicit HConstant(DataType::Type type, uint32_t dex_pc = kNoDexPc)
       : HExpression(type, SideEffects::None(), dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
@@ -2728,7 +2729,8 @@
   DECLARE_INSTRUCTION(NullConstant);
 
  private:
-  explicit HNullConstant(uint32_t dex_pc = kNoDexPc) : HConstant(Primitive::kPrimNot, dex_pc) {}
+  explicit HNullConstant(uint32_t dex_pc = kNoDexPc)
+      : HConstant(DataType::Type::kReference, dex_pc) {}
 
   friend class HGraph;
   DISALLOW_COPY_AND_ASSIGN(HNullConstant);
@@ -2765,9 +2767,9 @@
 
  private:
   explicit HIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimInt, dex_pc), value_(value) {}
+      : HConstant(DataType::Type::kInt32, dex_pc), value_(value) {}
   explicit HIntConstant(bool value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimInt, dex_pc), value_(value ? 1 : 0) {}
+      : HConstant(DataType::Type::kInt32, dex_pc), value_(value ? 1 : 0) {}
 
   const int32_t value_;
 
@@ -2799,7 +2801,7 @@
 
  private:
   explicit HLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimLong, dex_pc), value_(value) {}
+      : HConstant(DataType::Type::kInt64, dex_pc), value_(value) {}
 
   const int64_t value_;
 
@@ -2848,9 +2850,9 @@
 
  private:
   explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {}
+      : HConstant(DataType::Type::kFloat32, dex_pc), value_(value) {}
   explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
+      : HConstant(DataType::Type::kFloat32, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
 
   const float value_;
 
@@ -2899,9 +2901,9 @@
 
  private:
   explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {}
+      : HConstant(DataType::Type::kFloat64, dex_pc), value_(value) {}
   explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
-      : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
+      : HConstant(DataType::Type::kFloat64, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
 
   const double value_;
 
@@ -3050,8 +3052,8 @@
 
   DeoptimizationKind GetDeoptimizationKind() const { return GetPackedField<DeoptimizeKindField>(); }
 
-  Primitive::Type GetType() const OVERRIDE {
-    return GuardsAnInput() ? GuardedInput()->GetType() : Primitive::kPrimVoid;
+  DataType::Type GetType() const OVERRIDE {
+    return GuardsAnInput() ? GuardedInput()->GetType() : DataType::Type::kVoid;
   }
 
   bool GuardsAnInput() const {
@@ -3097,7 +3099,7 @@
       : HVariableInputSizeInstruction(SideEffects::None(), dex_pc, arena, 0, kArenaAllocCHA) {
   }
 
-  Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimInt; }
+  DataType::Type GetType() const OVERRIDE { return DataType::Type::kInt32; }
 
   // We do all CHA guard elimination/motion in a single pass, after which there is no
   // further guard elimination/motion since a guard might have been used for justification
@@ -3116,7 +3118,7 @@
 // instructions that work with the dex cache.
 class HCurrentMethod FINAL : public HExpression<0> {
  public:
-  explicit HCurrentMethod(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+  explicit HCurrentMethod(DataType::Type type, uint32_t dex_pc = kNoDexPc)
       : HExpression(type, SideEffects::None(), dex_pc) {}
 
   DECLARE_INSTRUCTION(CurrentMethod);
@@ -3135,7 +3137,7 @@
     kLast = kIMTable
   };
   HClassTableGet(HInstruction* cls,
-                 Primitive::Type type,
+                 DataType::Type type,
                  TableKind kind,
                  size_t index,
                  uint32_t dex_pc)
@@ -3207,13 +3209,13 @@
 
 class HUnaryOperation : public HExpression<1> {
  public:
-  HUnaryOperation(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+  HUnaryOperation(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
       : HExpression(result_type, SideEffects::None(), dex_pc) {
     SetRawInputAt(0, input);
   }
 
   HInstruction* GetInput() const { return InputAt(0); }
-  Primitive::Type GetResultType() const { return GetType(); }
+  DataType::Type GetResultType() const { return GetType(); }
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -3239,7 +3241,7 @@
 
 class HBinaryOperation : public HExpression<2> {
  public:
-  HBinaryOperation(Primitive::Type result_type,
+  HBinaryOperation(DataType::Type result_type,
                    HInstruction* left,
                    HInstruction* right,
                    SideEffects side_effects = SideEffects::None(),
@@ -3251,7 +3253,7 @@
 
   HInstruction* GetLeft() const { return InputAt(0); }
   HInstruction* GetRight() const { return InputAt(1); }
-  Primitive::Type GetResultType() const { return GetType(); }
+  DataType::Type GetResultType() const { return GetType(); }
 
   virtual bool IsCommutative() const { return false; }
 
@@ -3341,7 +3343,7 @@
 class HCondition : public HBinaryOperation {
  public:
   HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
-      : HBinaryOperation(Primitive::kPrimBoolean, first, second, SideEffects::None(), dex_pc) {
+      : HBinaryOperation(DataType::Type::kBool, first, second, SideEffects::None(), dex_pc) {
     SetPackedField<ComparisonBiasField>(ComparisonBias::kNoBias);
   }
 
@@ -3366,7 +3368,7 @@
   }
 
   bool IsFPConditionTrueIfNaN() const {
-    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+    DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
     IfCondition if_cond = GetCondition();
     if (if_cond == kCondNE) {
       return true;
@@ -3377,7 +3379,7 @@
   }
 
   bool IsFPConditionFalseIfNaN() const {
-    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+    DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
     IfCondition if_cond = GetCondition();
     if (if_cond == kCondEQ) {
       return true;
@@ -3403,7 +3405,7 @@
 
   template <typename T>
   int32_t CompareFP(T x, T y) const {
-    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+    DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
     DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
     // Handle the bias.
     return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compare(x, y);
@@ -3820,20 +3822,20 @@
  public:
   // Note that `comparison_type` is the type of comparison performed
   // between the comparison's inputs, not the type of the instantiated
-  // HCompare instruction (which is always Primitive::kPrimInt).
-  HCompare(Primitive::Type comparison_type,
+  // HCompare instruction (which is always DataType::Type::kInt).
+  HCompare(DataType::Type comparison_type,
            HInstruction* first,
            HInstruction* second,
            ComparisonBias bias,
            uint32_t dex_pc)
-      : HBinaryOperation(Primitive::kPrimInt,
+      : HBinaryOperation(DataType::Type::kInt32,
                          first,
                          second,
                          SideEffectsForArchRuntimeCalls(comparison_type),
                          dex_pc) {
     SetPackedField<ComparisonBiasField>(bias);
-    DCHECK_EQ(comparison_type, Primitive::PrimitiveKind(first->GetType()));
-    DCHECK_EQ(comparison_type, Primitive::PrimitiveKind(second->GetType()));
+    DCHECK_EQ(comparison_type, DataType::Kind(first->GetType()));
+    DCHECK_EQ(comparison_type, DataType::Kind(second->GetType()));
   }
 
   template <typename T>
@@ -3841,7 +3843,7 @@
 
   template <typename T>
   int32_t ComputeFP(T x, T y) const {
-    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+    DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
     DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
     // Handle the bias.
     return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compute(x, y);
@@ -3874,11 +3876,11 @@
   // Does this compare instruction have a "gt bias" (vs an "lt bias")?
   // Only meaningful for floating-point comparisons.
   bool IsGtBias() const {
-    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+    DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
     return GetBias() == ComparisonBias::kGtBias;
   }
 
-  static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type ATTRIBUTE_UNUSED) {
+  static SideEffects SideEffectsForArchRuntimeCalls(DataType::Type type ATTRIBUTE_UNUSED) {
     // Comparisons do not require a runtime call in any back end.
     return SideEffects::None();
   }
@@ -3913,7 +3915,7 @@
                const DexFile& dex_file,
                bool finalizable,
                QuickEntrypointEnum entrypoint)
-      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
+      : HExpression(DataType::Type::kReference, SideEffects::CanTriggerGC(), dex_pc),
         type_index_(type_index),
         dex_file_(dex_file),
         entrypoint_(entrypoint) {
@@ -4001,7 +4003,7 @@
   // inputs at the end of their list of inputs.
   uint32_t GetNumberOfArguments() const { return number_of_arguments_; }
 
-  Primitive::Type GetType() const OVERRIDE { return GetPackedField<ReturnTypeField>(); }
+  DataType::Type GetType() const OVERRIDE { return GetPackedField<ReturnTypeField>(); }
 
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
 
@@ -4054,17 +4056,17 @@
   static constexpr size_t kFieldReturnType =
       kFieldInvokeType + kFieldInvokeTypeSize;
   static constexpr size_t kFieldReturnTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize;
   static constexpr size_t kNumberOfInvokePackedBits = kFlagCanThrow + 1;
   static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
-  using ReturnTypeField = BitField<Primitive::Type, kFieldReturnType, kFieldReturnTypeSize>;
+  using ReturnTypeField = BitField<DataType::Type, kFieldReturnType, kFieldReturnTypeSize>;
 
   HInvoke(ArenaAllocator* arena,
           uint32_t number_of_arguments,
           uint32_t number_of_other_inputs,
-          Primitive::Type return_type,
+          DataType::Type return_type,
           uint32_t dex_pc,
           uint32_t dex_method_index,
           ArtMethod* resolved_method,
@@ -4101,7 +4103,7 @@
  public:
   HInvokeUnresolved(ArenaAllocator* arena,
                     uint32_t number_of_arguments,
-                    Primitive::Type return_type,
+                    DataType::Type return_type,
                     uint32_t dex_pc,
                     uint32_t dex_method_index,
                     InvokeType invoke_type)
@@ -4125,7 +4127,7 @@
  public:
   HInvokePolymorphic(ArenaAllocator* arena,
                      uint32_t number_of_arguments,
-                     Primitive::Type return_type,
+                     DataType::Type return_type,
                      uint32_t dex_pc,
                      uint32_t dex_method_index)
       : HInvoke(arena,
@@ -4202,7 +4204,7 @@
 
   HInvokeStaticOrDirect(ArenaAllocator* arena,
                         uint32_t number_of_arguments,
-                        Primitive::Type return_type,
+                        DataType::Type return_type,
                         uint32_t dex_pc,
                         uint32_t method_index,
                         ArtMethod* resolved_method,
@@ -4280,7 +4282,7 @@
   }
 
   bool CanBeNull() const OVERRIDE {
-    return GetPackedField<ReturnTypeField>() == Primitive::kPrimNot && !IsStringInit();
+    return GetPackedField<ReturnTypeField>() == DataType::Type::kReference && !IsStringInit();
   }
 
   // Get the index of the special input, if any.
@@ -4397,7 +4399,7 @@
  public:
   HInvokeVirtual(ArenaAllocator* arena,
                  uint32_t number_of_arguments,
-                 Primitive::Type return_type,
+                 DataType::Type return_type,
                  uint32_t dex_pc,
                  uint32_t dex_method_index,
                  ArtMethod* resolved_method,
@@ -4445,7 +4447,7 @@
  public:
   HInvokeInterface(ArenaAllocator* arena,
                    uint32_t number_of_arguments,
-                   Primitive::Type return_type,
+                   DataType::Type return_type,
                    uint32_t dex_pc,
                    uint32_t dex_method_index,
                    ArtMethod* resolved_method,
@@ -4484,9 +4486,9 @@
 
 class HNeg FINAL : public HUnaryOperation {
  public:
-  HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+  HNeg(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
       : HUnaryOperation(result_type, input, dex_pc) {
-    DCHECK_EQ(result_type, Primitive::PrimitiveKind(input->GetType()));
+    DCHECK_EQ(result_type, DataType::Kind(input->GetType()));
   }
 
   template <typename T> static T Compute(T x) { return -x; }
@@ -4513,7 +4515,7 @@
 class HNewArray FINAL : public HExpression<2> {
  public:
   HNewArray(HInstruction* cls, HInstruction* length, uint32_t dex_pc)
-      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc) {
+      : HExpression(DataType::Type::kReference, SideEffects::CanTriggerGC(), dex_pc) {
     SetRawInputAt(0, cls);
     SetRawInputAt(1, length);
   }
@@ -4543,7 +4545,7 @@
 
 class HAdd FINAL : public HBinaryOperation {
  public:
-  HAdd(Primitive::Type result_type,
+  HAdd(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc = kNoDexPc)
@@ -4578,7 +4580,7 @@
 
 class HSub FINAL : public HBinaryOperation {
  public:
-  HSub(Primitive::Type result_type,
+  HSub(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc = kNoDexPc)
@@ -4611,7 +4613,7 @@
 
 class HMul FINAL : public HBinaryOperation {
  public:
-  HMul(Primitive::Type result_type,
+  HMul(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc = kNoDexPc)
@@ -4646,7 +4648,7 @@
 
 class HDiv FINAL : public HBinaryOperation {
  public:
-  HDiv(Primitive::Type result_type,
+  HDiv(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc)
@@ -4654,7 +4656,7 @@
 
   template <typename T>
   T ComputeIntegral(T x, T y) const {
-    DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType();
+    DCHECK(!DataType::IsFloatingPointType(GetType())) << GetType();
     // Our graph structure ensures we never have 0 for `y` during
     // constant folding.
     DCHECK_NE(y, 0);
@@ -4664,7 +4666,7 @@
 
   template <typename T>
   T ComputeFP(T x, T y) const {
-    DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
+    DCHECK(DataType::IsFloatingPointType(GetType())) << GetType();
     return x / y;
   }
 
@@ -4693,7 +4695,7 @@
 
 class HRem FINAL : public HBinaryOperation {
  public:
-  HRem(Primitive::Type result_type,
+  HRem(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc)
@@ -4701,7 +4703,7 @@
 
   template <typename T>
   T ComputeIntegral(T x, T y) const {
-    DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType();
+    DCHECK(!DataType::IsFloatingPointType(GetType())) << GetType();
     // Our graph structure ensures we never have 0 for `y` during
     // constant folding.
     DCHECK_NE(y, 0);
@@ -4711,7 +4713,7 @@
 
   template <typename T>
   T ComputeFP(T x, T y) const {
-    DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
+    DCHECK(DataType::IsFloatingPointType(GetType())) << GetType();
     return std::fmod(x, y);
   }
 
@@ -4747,7 +4749,7 @@
     SetRawInputAt(0, value);
   }
 
-  Primitive::Type GetType() const OVERRIDE { return InputAt(0)->GetType(); }
+  DataType::Type GetType() const OVERRIDE { return InputAt(0)->GetType(); }
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -4766,13 +4768,13 @@
 
 class HShl FINAL : public HBinaryOperation {
  public:
-  HShl(Primitive::Type result_type,
+  HShl(DataType::Type result_type,
        HInstruction* value,
        HInstruction* distance,
        uint32_t dex_pc = kNoDexPc)
       : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) {
-    DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType()));
-    DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType()));
+    DCHECK_EQ(result_type, DataType::Kind(value->GetType()));
+    DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType()));
   }
 
   template <typename T>
@@ -4812,13 +4814,13 @@
 
 class HShr FINAL : public HBinaryOperation {
  public:
-  HShr(Primitive::Type result_type,
+  HShr(DataType::Type result_type,
        HInstruction* value,
        HInstruction* distance,
        uint32_t dex_pc = kNoDexPc)
       : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) {
-    DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType()));
-    DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType()));
+    DCHECK_EQ(result_type, DataType::Kind(value->GetType()));
+    DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType()));
   }
 
   template <typename T>
@@ -4858,13 +4860,13 @@
 
 class HUShr FINAL : public HBinaryOperation {
  public:
-  HUShr(Primitive::Type result_type,
+  HUShr(DataType::Type result_type,
         HInstruction* value,
         HInstruction* distance,
         uint32_t dex_pc = kNoDexPc)
       : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) {
-    DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType()));
-    DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType()));
+    DCHECK_EQ(result_type, DataType::Kind(value->GetType()));
+    DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType()));
   }
 
   template <typename T>
@@ -4906,7 +4908,7 @@
 
 class HAnd FINAL : public HBinaryOperation {
  public:
-  HAnd(Primitive::Type result_type,
+  HAnd(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc = kNoDexPc)
@@ -4943,7 +4945,7 @@
 
 class HOr FINAL : public HBinaryOperation {
  public:
-  HOr(Primitive::Type result_type,
+  HOr(DataType::Type result_type,
       HInstruction* left,
       HInstruction* right,
       uint32_t dex_pc = kNoDexPc)
@@ -4980,7 +4982,7 @@
 
 class HXor FINAL : public HBinaryOperation {
  public:
-  HXor(Primitive::Type result_type,
+  HXor(DataType::Type result_type,
        HInstruction* left,
        HInstruction* right,
        uint32_t dex_pc = kNoDexPc)
@@ -5017,10 +5019,10 @@
 
 class HRor FINAL : public HBinaryOperation {
  public:
-  HRor(Primitive::Type result_type, HInstruction* value, HInstruction* distance)
+  HRor(DataType::Type result_type, HInstruction* value, HInstruction* distance)
     : HBinaryOperation(result_type, value, distance) {
-    DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType()));
-    DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType()));
+    DCHECK_EQ(result_type, DataType::Kind(value->GetType()));
+    DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType()));
   }
 
   template <typename T>
@@ -5073,7 +5075,7 @@
   HParameterValue(const DexFile& dex_file,
                   dex::TypeIndex type_index,
                   uint8_t index,
-                  Primitive::Type parameter_type,
+                  DataType::Type parameter_type,
                   bool is_this = false)
       : HExpression(parameter_type, SideEffects::None(), kNoDexPc),
         dex_file_(dex_file),
@@ -5112,7 +5114,7 @@
 
 class HNot FINAL : public HUnaryOperation {
  public:
-  HNot(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+  HNot(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
       : HUnaryOperation(result_type, input, dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
@@ -5146,7 +5148,7 @@
 class HBooleanNot FINAL : public HUnaryOperation {
  public:
   explicit HBooleanNot(HInstruction* input, uint32_t dex_pc = kNoDexPc)
-      : HUnaryOperation(Primitive::Type::kPrimBoolean, input, dex_pc) {}
+      : HUnaryOperation(DataType::Type::kBool, input, dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -5183,16 +5185,16 @@
 class HTypeConversion FINAL : public HExpression<1> {
  public:
   // Instantiate a type conversion of `input` to `result_type`.
-  HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc)
+  HTypeConversion(DataType::Type result_type, HInstruction* input, uint32_t dex_pc)
       : HExpression(result_type, SideEffects::None(), dex_pc) {
     SetRawInputAt(0, input);
     // Invariant: We should never generate a conversion to a Boolean value.
-    DCHECK_NE(Primitive::kPrimBoolean, result_type);
+    DCHECK_NE(DataType::Type::kBool, result_type);
   }
 
   HInstruction* GetInput() const { return InputAt(0); }
-  Primitive::Type GetInputType() const { return GetInput()->GetType(); }
-  Primitive::Type GetResultType() const { return GetType(); }
+  DataType::Type GetInputType() const { return GetInput()->GetType(); }
+  DataType::Type GetResultType() const { return GetType(); }
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -5244,7 +5246,7 @@
  public:
   FieldInfo(ArtField* field,
             MemberOffset field_offset,
-            Primitive::Type field_type,
+            DataType::Type field_type,
             bool is_volatile,
             uint32_t index,
             uint16_t declaring_class_def_index,
@@ -5259,7 +5261,7 @@
 
   ArtField* GetField() const { return field_; }
   MemberOffset GetFieldOffset() const { return field_offset_; }
-  Primitive::Type GetFieldType() const { return field_type_; }
+  DataType::Type GetFieldType() const { return field_type_; }
   uint32_t GetFieldIndex() const { return index_; }
   uint16_t GetDeclaringClassDefIndex() const { return declaring_class_def_index_;}
   const DexFile& GetDexFile() const { return dex_file_; }
@@ -5268,7 +5270,7 @@
  private:
   ArtField* const field_;
   const MemberOffset field_offset_;
-  const Primitive::Type field_type_;
+  const DataType::Type field_type_;
   const bool is_volatile_;
   const uint32_t index_;
   const uint16_t declaring_class_def_index_;
@@ -5279,7 +5281,7 @@
  public:
   HInstanceFieldGet(HInstruction* value,
                     ArtField* field,
-                    Primitive::Type field_type,
+                    DataType::Type field_type,
                     MemberOffset field_offset,
                     bool is_volatile,
                     uint32_t field_idx,
@@ -5314,7 +5316,7 @@
 
   const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
-  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  DataType::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   DECLARE_INSTRUCTION(InstanceFieldGet);
@@ -5330,7 +5332,7 @@
   HInstanceFieldSet(HInstruction* object,
                     HInstruction* value,
                     ArtField* field,
-                    Primitive::Type field_type,
+                    DataType::Type field_type,
                     MemberOffset field_offset,
                     bool is_volatile,
                     uint32_t field_idx,
@@ -5356,7 +5358,7 @@
 
   const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
-  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  DataType::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
   HInstruction* GetValue() const { return InputAt(1); }
   bool GetValueCanBeNull() const { return GetPackedFlag<kFlagValueCanBeNull>(); }
@@ -5379,7 +5381,7 @@
  public:
   HArrayGet(HInstruction* array,
             HInstruction* index,
-            Primitive::Type type,
+            DataType::Type type,
             uint32_t dex_pc,
             bool is_string_char_at = false)
       : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) {
@@ -5413,11 +5415,11 @@
       DCHECK_EQ(GetBlock(), other->GetBlock());
       DCHECK_EQ(GetArray(), other->GetArray());
       DCHECK_EQ(GetIndex(), other->GetIndex());
-      if (Primitive::IsIntOrLongType(GetType())) {
-        DCHECK(Primitive::IsFloatingPointType(other->GetType())) << other->GetType();
+      if (DataType::IsIntOrLongType(GetType())) {
+        DCHECK(DataType::IsFloatingPointType(other->GetType())) << other->GetType();
       } else {
-        DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
-        DCHECK(Primitive::IsIntOrLongType(other->GetType())) << other->GetType();
+        DCHECK(DataType::IsFloatingPointType(GetType())) << GetType();
+        DCHECK(DataType::IsIntOrLongType(other->GetType())) << other->GetType();
       }
     }
     return result;
@@ -5449,11 +5451,11 @@
   HArraySet(HInstruction* array,
             HInstruction* index,
             HInstruction* value,
-            Primitive::Type expected_component_type,
+            DataType::Type expected_component_type,
             uint32_t dex_pc)
       : HTemplateInstruction(SideEffects::None(), dex_pc) {
     SetPackedField<ExpectedComponentTypeField>(expected_component_type);
-    SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == Primitive::kPrimNot);
+    SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference);
     SetPackedFlag<kFlagValueCanBeNull>(true);
     SetPackedFlag<kFlagStaticTypeOfArrayIsObjectArray>(false);
     SetRawInputAt(0, array);
@@ -5498,29 +5500,30 @@
   HInstruction* GetIndex() const { return InputAt(1); }
   HInstruction* GetValue() const { return InputAt(2); }
 
-  Primitive::Type GetComponentType() const {
+  DataType::Type GetComponentType() const {
     // The Dex format does not type floating point index operations. Since the
     // `expected_component_type_` is set during building and can therefore not
     // be correct, we also check what is the value type. If it is a floating
     // point type, we must use that type.
-    Primitive::Type value_type = GetValue()->GetType();
-    return ((value_type == Primitive::kPrimFloat) || (value_type == Primitive::kPrimDouble))
+    DataType::Type value_type = GetValue()->GetType();
+    return ((value_type == DataType::Type::kFloat32) || (value_type == DataType::Type::kFloat64))
         ? value_type
         : GetRawExpectedComponentType();
   }
 
-  Primitive::Type GetRawExpectedComponentType() const {
+  DataType::Type GetRawExpectedComponentType() const {
     return GetPackedField<ExpectedComponentTypeField>();
   }
 
   void ComputeSideEffects() {
-    Primitive::Type type = GetComponentType();
+    DataType::Type type = GetComponentType();
     SetSideEffects(SideEffects::ArrayWriteOfType(type).Union(
         SideEffectsForArchRuntimeCalls(type)));
   }
 
-  static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type value_type) {
-    return (value_type == Primitive::kPrimNot) ? SideEffects::CanTriggerGC() : SideEffects::None();
+  static SideEffects SideEffectsForArchRuntimeCalls(DataType::Type value_type) {
+    return (value_type == DataType::Type::kReference) ? SideEffects::CanTriggerGC()
+                                                      : SideEffects::None();
   }
 
   DECLARE_INSTRUCTION(ArraySet);
@@ -5528,7 +5531,7 @@
  private:
   static constexpr size_t kFieldExpectedComponentType = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldExpectedComponentTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kFlagNeedsTypeCheck =
       kFieldExpectedComponentType + kFieldExpectedComponentTypeSize;
   static constexpr size_t kFlagValueCanBeNull = kFlagNeedsTypeCheck + 1;
@@ -5539,7 +5542,7 @@
       kFlagStaticTypeOfArrayIsObjectArray + 1;
   static_assert(kNumberOfArraySetPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using ExpectedComponentTypeField =
-      BitField<Primitive::Type, kFieldExpectedComponentType, kFieldExpectedComponentTypeSize>;
+      BitField<DataType::Type, kFieldExpectedComponentType, kFieldExpectedComponentTypeSize>;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -5547,7 +5550,7 @@
 class HArrayLength FINAL : public HExpression<1> {
  public:
   HArrayLength(HInstruction* array, uint32_t dex_pc, bool is_string_length = false)
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
+      : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) {
     SetPackedFlag<kFlagIsStringLength>(is_string_length);
     // Note that arrays do not change length, so the instruction does not
     // depend on any write.
@@ -5589,7 +5592,7 @@
                uint32_t dex_pc,
                bool string_char_at = false)
       : HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc) {
-    DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(index->GetType()));
+    DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(index->GetType()));
     SetPackedFlag<kFlagIsStringCharAt>(string_char_at);
     SetRawInputAt(0, index);
     SetRawInputAt(1, length);
@@ -5799,8 +5802,8 @@
         &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
   }
 
-  Primitive::Type GetType() const OVERRIDE {
-    return Primitive::kPrimNot;
+  DataType::Type GetType() const OVERRIDE {
+    return DataType::Type::kReference;
   }
 
   Handle<mirror::Class> GetClass() const {
@@ -5967,8 +5970,8 @@
         &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
   }
 
-  Primitive::Type GetType() const OVERRIDE {
-    return Primitive::kPrimNot;
+  DataType::Type GetType() const OVERRIDE {
+    return DataType::Type::kReference;
   }
 
   DECLARE_INSTRUCTION(LoadString);
@@ -6019,7 +6022,7 @@
  public:
   HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
       : HExpression(
-            Primitive::kPrimNot,
+            DataType::Type::kReference,
             SideEffects::AllChanges(),  // Assume write/read on all fields/arrays.
             dex_pc) {
     SetRawInputAt(0, constant);
@@ -6052,7 +6055,7 @@
  public:
   HStaticFieldGet(HInstruction* cls,
                   ArtField* field,
-                  Primitive::Type field_type,
+                  DataType::Type field_type,
                   MemberOffset field_offset,
                   bool is_volatile,
                   uint32_t field_idx,
@@ -6084,7 +6087,7 @@
 
   const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
-  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  DataType::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   DECLARE_INSTRUCTION(StaticFieldGet);
@@ -6100,7 +6103,7 @@
   HStaticFieldSet(HInstruction* cls,
                   HInstruction* value,
                   ArtField* field,
-                  Primitive::Type field_type,
+                  DataType::Type field_type,
                   MemberOffset field_offset,
                   bool is_volatile,
                   uint32_t field_idx,
@@ -6122,7 +6125,7 @@
 
   const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
-  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  DataType::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   HInstruction* GetValue() const { return InputAt(1); }
@@ -6145,7 +6148,7 @@
 class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> {
  public:
   HUnresolvedInstanceFieldGet(HInstruction* obj,
-                              Primitive::Type field_type,
+                              DataType::Type field_type,
                               uint32_t field_index,
                               uint32_t dex_pc)
       : HExpression(field_type, SideEffects::AllExceptGCDependency(), dex_pc),
@@ -6156,7 +6159,7 @@
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
-  Primitive::Type GetFieldType() const { return GetType(); }
+  DataType::Type GetFieldType() const { return GetType(); }
   uint32_t GetFieldIndex() const { return field_index_; }
 
   DECLARE_INSTRUCTION(UnresolvedInstanceFieldGet);
@@ -6171,13 +6174,13 @@
  public:
   HUnresolvedInstanceFieldSet(HInstruction* obj,
                               HInstruction* value,
-                              Primitive::Type field_type,
+                              DataType::Type field_type,
                               uint32_t field_index,
                               uint32_t dex_pc)
       : HTemplateInstruction(SideEffects::AllExceptGCDependency(), dex_pc),
         field_index_(field_index) {
     SetPackedField<FieldTypeField>(field_type);
-    DCHECK_EQ(Primitive::PrimitiveKind(field_type), Primitive::PrimitiveKind(value->GetType()));
+    DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType()));
     SetRawInputAt(0, obj);
     SetRawInputAt(1, value);
   }
@@ -6185,7 +6188,7 @@
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
-  Primitive::Type GetFieldType() const { return GetPackedField<FieldTypeField>(); }
+  DataType::Type GetFieldType() const { return GetPackedField<FieldTypeField>(); }
   uint32_t GetFieldIndex() const { return field_index_; }
 
   DECLARE_INSTRUCTION(UnresolvedInstanceFieldSet);
@@ -6193,12 +6196,12 @@
  private:
   static constexpr size_t kFieldFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldFieldTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kNumberOfUnresolvedStaticFieldSetPackedBits =
       kFieldFieldType + kFieldFieldTypeSize;
   static_assert(kNumberOfUnresolvedStaticFieldSetPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-  using FieldTypeField = BitField<Primitive::Type, kFieldFieldType, kFieldFieldTypeSize>;
+  using FieldTypeField = BitField<DataType::Type, kFieldFieldType, kFieldFieldTypeSize>;
 
   const uint32_t field_index_;
 
@@ -6207,7 +6210,7 @@
 
 class HUnresolvedStaticFieldGet FINAL : public HExpression<0> {
  public:
-  HUnresolvedStaticFieldGet(Primitive::Type field_type,
+  HUnresolvedStaticFieldGet(DataType::Type field_type,
                             uint32_t field_index,
                             uint32_t dex_pc)
       : HExpression(field_type, SideEffects::AllExceptGCDependency(), dex_pc),
@@ -6217,7 +6220,7 @@
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
-  Primitive::Type GetFieldType() const { return GetType(); }
+  DataType::Type GetFieldType() const { return GetType(); }
   uint32_t GetFieldIndex() const { return field_index_; }
 
   DECLARE_INSTRUCTION(UnresolvedStaticFieldGet);
@@ -6231,20 +6234,20 @@
 class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> {
  public:
   HUnresolvedStaticFieldSet(HInstruction* value,
-                            Primitive::Type field_type,
+                            DataType::Type field_type,
                             uint32_t field_index,
                             uint32_t dex_pc)
       : HTemplateInstruction(SideEffects::AllExceptGCDependency(), dex_pc),
         field_index_(field_index) {
     SetPackedField<FieldTypeField>(field_type);
-    DCHECK_EQ(Primitive::PrimitiveKind(field_type), Primitive::PrimitiveKind(value->GetType()));
+    DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType()));
     SetRawInputAt(0, value);
   }
 
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
-  Primitive::Type GetFieldType() const { return GetPackedField<FieldTypeField>(); }
+  DataType::Type GetFieldType() const { return GetPackedField<FieldTypeField>(); }
   uint32_t GetFieldIndex() const { return field_index_; }
 
   DECLARE_INSTRUCTION(UnresolvedStaticFieldSet);
@@ -6252,12 +6255,12 @@
  private:
   static constexpr size_t kFieldFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldFieldTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kNumberOfUnresolvedStaticFieldSetPackedBits =
       kFieldFieldType + kFieldFieldTypeSize;
   static_assert(kNumberOfUnresolvedStaticFieldSetPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-  using FieldTypeField = BitField<Primitive::Type, kFieldFieldType, kFieldFieldTypeSize>;
+  using FieldTypeField = BitField<DataType::Type, kFieldFieldType, kFieldFieldTypeSize>;
 
   const uint32_t field_index_;
 
@@ -6268,7 +6271,7 @@
 class HLoadException FINAL : public HExpression<0> {
  public:
   explicit HLoadException(uint32_t dex_pc = kNoDexPc)
-      : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc) {}
+      : HExpression(DataType::Type::kReference, SideEffects::None(), dex_pc) {}
 
   bool CanBeNull() const OVERRIDE { return false; }
 
@@ -6334,7 +6337,7 @@
               HLoadClass* constant,
               TypeCheckKind check_kind,
               uint32_t dex_pc)
-      : HExpression(Primitive::kPrimBoolean,
+      : HExpression(DataType::Type::kBool,
                     SideEffectsForArchRuntimeCalls(check_kind),
                     dex_pc) {
     SetPackedField<TypeCheckKindField>(check_kind);
@@ -6385,11 +6388,11 @@
 class HBoundType FINAL : public HExpression<1> {
  public:
   explicit HBoundType(HInstruction* input, uint32_t dex_pc = kNoDexPc)
-      : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc),
+      : HExpression(DataType::Type::kReference, SideEffects::None(), dex_pc),
         upper_bound_(ReferenceTypeInfo::CreateInvalid()) {
     SetPackedFlag<kFlagUpperCanBeNull>(true);
     SetPackedFlag<kFlagCanBeNull>(true);
-    DCHECK_EQ(input->GetType(), Primitive::kPrimNot);
+    DCHECK_EQ(input->GetType(), DataType::Type::kReference);
     SetRawInputAt(0, input);
   }
 
@@ -6760,7 +6763,7 @@
  public:
   MoveOperands(Location source,
                Location destination,
-               Primitive::Type type,
+               DataType::Type type,
                HInstruction* instruction)
       : source_(source), destination_(destination), type_(type), instruction_(instruction) {}
 
@@ -6810,10 +6813,10 @@
     return source_.IsInvalid();
   }
 
-  Primitive::Type GetType() const { return type_; }
+  DataType::Type GetType() const { return type_; }
 
   bool Is64BitMove() const {
-    return Primitive::Is64BitType(type_);
+    return DataType::Is64BitType(type_);
   }
 
   HInstruction* GetInstruction() const { return instruction_; }
@@ -6822,7 +6825,7 @@
   Location source_;
   Location destination_;
   // The type this move is for.
-  Primitive::Type type_;
+  DataType::Type type_;
   // The instruction this move is assocatied with. Null when this move is
   // for moving an input in the expected locations of user (including a phi user).
   // This is only used in debug mode, to ensure we do not connect interval siblings
@@ -6844,7 +6847,7 @@
 
   void AddMove(Location source,
                Location destination,
-               Primitive::Type type,
+               DataType::Type type,
                HInstruction* instruction) {
     DCHECK(source.IsValid());
     DCHECK(destination.IsValid());
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index 8e439d9..80e652e 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -24,7 +24,7 @@
  public:
   // Treat the value as an int32_t, but it is really a 32 bit native pointer.
   HMipsComputeBaseMethodAddress()
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc) {}
+      : HExpression(DataType::Type::kInt32, SideEffects::None(), kNoDexPc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
diff --git a/compiler/optimizing/nodes_shared.cc b/compiler/optimizing/nodes_shared.cc
index f6d33f0..f982523 100644
--- a/compiler/optimizing/nodes_shared.cc
+++ b/compiler/optimizing/nodes_shared.cc
@@ -42,20 +42,20 @@
     *shift_amount = instruction->AsUShr()->GetRight()->AsIntConstant()->GetValue();
   } else {
     DCHECK(instruction->IsTypeConversion());
-    Primitive::Type result_type = instruction->AsTypeConversion()->GetResultType();
-    Primitive::Type input_type = instruction->AsTypeConversion()->GetInputType();
-    int result_size = Primitive::ComponentSize(result_type);
-    int input_size = Primitive::ComponentSize(input_type);
+    DataType::Type result_type = instruction->AsTypeConversion()->GetResultType();
+    DataType::Type input_type = instruction->AsTypeConversion()->GetInputType();
+    int result_size = DataType::Size(result_type);
+    int input_size = DataType::Size(input_type);
     int min_size = std::min(result_size, input_size);
-    if (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimLong) {
+    if (result_type == DataType::Type::kInt32 && input_type == DataType::Type::kInt64) {
       // There is actually nothing to do. On ARM the high register from the
       // pair will be ignored. On ARM64 the register will be used as a W
       // register, discarding the top bits. This is represented by the
       // default encoding 'LSL 0'.
       *op_kind = kLSL;
       *shift_amount = 0;
-    } else if (result_type == Primitive::kPrimChar ||
-               (input_type == Primitive::kPrimChar && input_size < result_size)) {
+    } else if (result_type == DataType::Type::kUint16 ||
+               (input_type == DataType::Type::kUint16 && input_size < result_size)) {
       *op_kind = kUXTH;
     } else {
       switch (min_size) {
diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h
index 075a816..14cbf85 100644
--- a/compiler/optimizing/nodes_shared.h
+++ b/compiler/optimizing/nodes_shared.h
@@ -26,7 +26,7 @@
 
 class HMultiplyAccumulate FINAL : public HExpression<3> {
  public:
-  HMultiplyAccumulate(Primitive::Type type,
+  HMultiplyAccumulate(DataType::Type type,
                       InstructionKind op,
                       HInstruction* accumulator,
                       HInstruction* mul_left,
@@ -60,11 +60,11 @@
 
 class HBitwiseNegatedRight FINAL : public HBinaryOperation {
  public:
-  HBitwiseNegatedRight(Primitive::Type result_type,
-                            InstructionKind op,
-                            HInstruction* left,
-                            HInstruction* right,
-                            uint32_t dex_pc = kNoDexPc)
+  HBitwiseNegatedRight(DataType::Type result_type,
+                       InstructionKind op,
+                       HInstruction* left,
+                       HInstruction* right,
+                       uint32_t dex_pc = kNoDexPc)
     : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc),
       op_kind_(op) {
     DCHECK(op == HInstruction::kAnd || op == HInstruction::kOr || op == HInstruction::kXor) << op;
@@ -122,14 +122,14 @@
 // This instruction computes an intermediate address pointing in the 'middle' of an object. The
 // result pointer cannot be handled by GC, so extra care is taken to make sure that this value is
 // never used across anything that can trigger GC.
-// The result of this instruction is not a pointer in the sense of `Primitive::kPrimNot`. So we
-// represent it by the type `Primitive::kPrimInt`.
+// The result of this instruction is not a pointer in the sense of `DataType::Type::kreference`.
+// So we represent it by the type `DataType::Type::kInt`.
 class HIntermediateAddress FINAL : public HExpression<2> {
  public:
   HIntermediateAddress(HInstruction* base_address, HInstruction* offset, uint32_t dex_pc)
-      : HExpression(Primitive::kPrimInt, SideEffects::DependsOnGC(), dex_pc) {
-        DCHECK_EQ(Primitive::ComponentSize(Primitive::kPrimInt),
-                  Primitive::ComponentSize(Primitive::kPrimNot))
+      : HExpression(DataType::Type::kInt32, SideEffects::DependsOnGC(), dex_pc) {
+        DCHECK_EQ(DataType::Size(DataType::Type::kInt32),
+                  DataType::Size(DataType::Type::kReference))
             << "kPrimInt and kPrimNot have different sizes.";
     SetRawInputAt(0, base_address);
     SetRawInputAt(1, offset);
@@ -171,7 +171,7 @@
  public:
   HIntermediateAddressIndex(
       HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
+      : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) {
     SetRawInputAt(0, index);
     SetRawInputAt(1, offset);
     SetRawInputAt(2, shift);
@@ -222,7 +222,7 @@
                          uint32_t dex_pc = kNoDexPc)
       : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
         instr_kind_(instr->GetKind()), op_kind_(op),
-        shift_amount_(shift & (instr->GetType() == Primitive::kPrimInt
+        shift_amount_(shift & (instr->GetType() == DataType::Type::kInt32
             ? kMaxIntShiftDistance
             : kMaxLongShiftDistance)) {
     DCHECK(!instr->HasSideEffects());
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index f3a78a0..ada6177 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -36,7 +36,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
   entry->AddInstruction(new (&allocator) HGoto());
 
@@ -79,9 +79,9 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* parameter2 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
   entry->AddInstruction(new (&allocator) HExit());
@@ -107,7 +107,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   ASSERT_FALSE(parameter->HasUses());
@@ -128,7 +128,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* with_environment = new (&allocator) HNullCheck(parameter1, 0);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(with_environment);
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 886d75e..0aac260 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -65,10 +65,10 @@
  public:
   // A SIMD operation looks like a FPU location.
   // TODO: we could introduce SIMD types in HIR.
-  static constexpr Primitive::Type kSIMDType = Primitive::kPrimDouble;
+  static constexpr DataType::Type kSIMDType = DataType::Type::kFloat64;
 
   HVecOperation(ArenaAllocator* arena,
-                Primitive::Type packed_type,
+                DataType::Type packed_type,
                 SideEffects side_effects,
                 size_t number_of_inputs,
                 size_t vector_length,
@@ -90,16 +90,16 @@
 
   // Returns the number of bytes in a full vector.
   size_t GetVectorNumberOfBytes() const {
-    return vector_length_ * Primitive::ComponentSize(GetPackedType());
+    return vector_length_ * DataType::Size(GetPackedType());
   }
 
   // Returns the type of the vector operation.
-  Primitive::Type GetType() const OVERRIDE {
+  DataType::Type GetType() const OVERRIDE {
     return kSIMDType;
   }
 
   // Returns the true component type packed in a vector.
-  Primitive::Type GetPackedType() const {
+  DataType::Type GetPackedType() const {
     return GetPackedField<TypeField>();
   }
 
@@ -122,10 +122,10 @@
   // Additional packed bits.
   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
+      MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
   static constexpr size_t kNumberOfVectorOpPackedBits = kFieldType + kFieldTypeSize;
   static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-  using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
+  using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
 
  private:
   const size_t vector_length_;
@@ -138,7 +138,7 @@
  public:
   HVecUnaryOperation(ArenaAllocator* arena,
                      HInstruction* input,
-                     Primitive::Type packed_type,
+                     DataType::Type packed_type,
                      size_t vector_length,
                      uint32_t dex_pc)
       : HVecOperation(arena,
@@ -164,7 +164,7 @@
   HVecBinaryOperation(ArenaAllocator* arena,
                       HInstruction* left,
                       HInstruction* right,
-                      Primitive::Type packed_type,
+                      DataType::Type packed_type,
                       size_t vector_length,
                       uint32_t dex_pc)
       : HVecOperation(arena,
@@ -192,13 +192,13 @@
 class HVecMemoryOperation : public HVecOperation {
  public:
   HVecMemoryOperation(ArenaAllocator* arena,
-                      Primitive::Type packed_type,
+                      DataType::Type packed_type,
                       SideEffects side_effects,
                       size_t number_of_inputs,
                       size_t vector_length,
                       uint32_t dex_pc)
       : HVecOperation(arena, packed_type, side_effects, number_of_inputs, vector_length, dex_pc),
-        alignment_(Primitive::ComponentSize(packed_type), 0) {
+        alignment_(DataType::Size(packed_type), 0) {
     DCHECK_GE(number_of_inputs, 2u);
   }
 
@@ -224,21 +224,21 @@
 };
 
 // Packed type consistency checker ("same vector length" integral types may mix freely).
-inline static bool HasConsistentPackedTypes(HInstruction* input, Primitive::Type type) {
+inline static bool HasConsistentPackedTypes(HInstruction* input, DataType::Type type) {
   if (input->IsPhi()) {
     return input->GetType() == HVecOperation::kSIMDType;  // carries SIMD
   }
   DCHECK(input->IsVecOperation());
-  Primitive::Type input_type = input->AsVecOperation()->GetPackedType();
+  DataType::Type input_type = input->AsVecOperation()->GetPackedType();
   switch (input_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-      return type == Primitive::kPrimBoolean ||
-             type == Primitive::kPrimByte;
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      return type == Primitive::kPrimChar ||
-             type == Primitive::kPrimShort;
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+      return type == DataType::Type::kBool ||
+             type == DataType::Type::kInt8;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      return type == DataType::Type::kUint16 ||
+             type == DataType::Type::kInt16;
     default:
       return type == input_type;
   }
@@ -254,7 +254,7 @@
  public:
   HVecReplicateScalar(ArenaAllocator* arena,
                       HInstruction* scalar,
-                      Primitive::Type packed_type,
+                      DataType::Type packed_type,
                       size_t vector_length,
                       uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, scalar, packed_type, vector_length, dex_pc) {
@@ -279,7 +279,7 @@
  public:
   HVecExtractScalar(ArenaAllocator* arena,
                     HInstruction* input,
-                    Primitive::Type packed_type,
+                    DataType::Type packed_type,
                     size_t vector_length,
                     size_t index,
                     uint32_t dex_pc = kNoDexPc)
@@ -290,7 +290,7 @@
   }
 
   // Yields a single component in the vector.
-  Primitive::Type GetType() const OVERRIDE {
+  DataType::Type GetType() const OVERRIDE {
     return GetPackedType();
   }
 
@@ -317,7 +317,7 @@
 
   HVecReduce(ArenaAllocator* arena,
              HInstruction* input,
-             Primitive::Type packed_type,
+             DataType::Type packed_type,
              size_t vector_length,
              ReductionKind kind,
              uint32_t dex_pc = kNoDexPc)
@@ -350,7 +350,7 @@
  public:
   HVecCnv(ArenaAllocator* arena,
           HInstruction* input,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
@@ -358,8 +358,8 @@
     DCHECK_NE(GetInputType(), GetResultType());  // actual convert
   }
 
-  Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
-  Primitive::Type GetResultType() const { return GetPackedType(); }
+  DataType::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
+  DataType::Type GetResultType() const { return GetPackedType(); }
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -375,7 +375,7 @@
  public:
   HVecNeg(ArenaAllocator* arena,
           HInstruction* input,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
@@ -396,7 +396,7 @@
  public:
   HVecAbs(ArenaAllocator* arena,
           HInstruction* input,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
@@ -418,7 +418,7 @@
  public:
   HVecNot(ArenaAllocator* arena,
           HInstruction* input,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
@@ -444,7 +444,7 @@
   HVecAdd(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -461,15 +461,15 @@
 };
 
 // Performs halving add on every component in the two vectors, viz.
-// rounded [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
-// or      [ x1, .. , xn ] hadd  [ y1, .. , yn ] = [ (x1 + y1)     >> 1, .. , (xn + yn )    >> 1 ]
+// rounded   [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
+// truncated [ x1, .. , xn ] hadd  [ y1, .. , yn ] = [ (x1 + y1)     >> 1, .. , (xn + yn )    >> 1 ]
 // for signed operands x, y (sign extension) or unsigned operands x, y (zero extension).
 class HVecHalvingAdd FINAL : public HVecBinaryOperation {
  public:
   HVecHalvingAdd(ArenaAllocator* arena,
                  HInstruction* left,
                  HInstruction* right,
-                 Primitive::Type packed_type,
+                 DataType::Type packed_type,
                  size_t vector_length,
                  bool is_unsigned,
                  bool is_rounded,
@@ -513,7 +513,7 @@
   HVecSub(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -536,7 +536,7 @@
   HVecMul(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -559,7 +559,7 @@
   HVecDiv(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -582,7 +582,7 @@
   HVecMin(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           bool is_unsigned,
           uint32_t dex_pc = kNoDexPc)
@@ -620,7 +620,7 @@
   HVecMax(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           bool is_unsigned,
           uint32_t dex_pc = kNoDexPc)
@@ -658,7 +658,7 @@
   HVecAnd(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -680,7 +680,7 @@
   HVecAndNot(ArenaAllocator* arena,
              HInstruction* left,
              HInstruction* right,
-             Primitive::Type packed_type,
+             DataType::Type packed_type,
              size_t vector_length,
              uint32_t dex_pc = kNoDexPc)
          : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -702,7 +702,7 @@
   HVecOr(ArenaAllocator* arena,
          HInstruction* left,
          HInstruction* right,
-         Primitive::Type packed_type,
+         DataType::Type packed_type,
          size_t vector_length,
          uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -724,7 +724,7 @@
   HVecXor(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -746,7 +746,7 @@
   HVecShl(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -768,7 +768,7 @@
   HVecShr(ArenaAllocator* arena,
           HInstruction* left,
           HInstruction* right,
-          Primitive::Type packed_type,
+          DataType::Type packed_type,
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -790,7 +790,7 @@
   HVecUShr(ArenaAllocator* arena,
            HInstruction* left,
            HInstruction* right,
-           Primitive::Type packed_type,
+           DataType::Type packed_type,
            size_t vector_length,
            uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
@@ -810,13 +810,13 @@
 //
 
 // Assigns the given scalar elements to a vector,
-// viz. set( array(x1, .., xn) ) = [ x1, .. ,           xn ] if n == m,
-//      set( array(x1, .., xm) ) = [ x1, .. , xm, 0, .., 0 ] if m <  n.
+// viz. set( array(x1, .. , xn) ) = [ x1, .. ,            xn ] if n == m,
+//      set( array(x1, .. , xm) ) = [ x1, .. , xm, 0, .. , 0 ] if m <  n.
 class HVecSetScalars FINAL : public HVecOperation {
  public:
   HVecSetScalars(ArenaAllocator* arena,
-                 HInstruction** scalars,  // array
-                 Primitive::Type packed_type,
+                 HInstruction* scalars[],
+                 DataType::Type packed_type,
                  size_t vector_length,
                  size_t number_of_scalars,
                  uint32_t dex_pc = kNoDexPc)
@@ -827,7 +827,7 @@
                       vector_length,
                       dex_pc) {
     for (size_t i = 0; i < number_of_scalars; i++) {
-      DCHECK(!scalars[i]->IsVecOperation());
+      DCHECK(!scalars[i]->IsVecOperation() || scalars[i]->IsVecExtractScalar());
       SetRawInputAt(0, scalars[i]);
     }
   }
@@ -842,9 +842,8 @@
   DISALLOW_COPY_AND_ASSIGN(HVecSetScalars);
 };
 
-// Multiplies every component in the two vectors, adds the result vector to the accumulator vector.
-// viz. [ acc1, .., accn ] + [ x1, .. , xn ] * [ y1, .. , yn ] =
-//     [ acc1 + x1 * y1, .. , accn + xn * yn ].
+// Multiplies every component in the two vectors, adds the result vector to the accumulator vector,
+// viz. [ a1, .. , an ] + [ x1, .. , xn ] * [ y1, .. , yn ] = [ a1 + x1 * y1, .. , an + xn * yn ].
 class HVecMultiplyAccumulate FINAL : public HVecOperation {
  public:
   HVecMultiplyAccumulate(ArenaAllocator* arena,
@@ -852,7 +851,7 @@
                          HInstruction* accumulator,
                          HInstruction* mul_left,
                          HInstruction* mul_right,
-                         Primitive::Type packed_type,
+                         DataType::Type packed_type,
                          size_t vector_length,
                          uint32_t dex_pc = kNoDexPc)
       : HVecOperation(arena,
@@ -866,15 +865,11 @@
     DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
     DCHECK(HasConsistentPackedTypes(mul_left, packed_type));
     DCHECK(HasConsistentPackedTypes(mul_right, packed_type));
-    SetRawInputAt(kInputAccumulatorIndex, accumulator);
-    SetRawInputAt(kInputMulLeftIndex, mul_left);
-    SetRawInputAt(kInputMulRightIndex, mul_right);
+    SetRawInputAt(0, accumulator);
+    SetRawInputAt(1, mul_left);
+    SetRawInputAt(2, mul_right);
   }
 
-  static constexpr int kInputAccumulatorIndex = 0;
-  static constexpr int kInputMulLeftIndex = 1;
-  static constexpr int kInputMulRightIndex = 2;
-
   bool CanBeMoved() const OVERRIDE { return true; }
 
   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
@@ -894,6 +889,42 @@
   DISALLOW_COPY_AND_ASSIGN(HVecMultiplyAccumulate);
 };
 
+// Takes the absolute difference of two vectors, and adds the results to
+// same-precision or wider-precision components in the accumulator,
+// viz. SAD([ a1, .. , am ], [ x1, .. , xn ], [ y1, .. , yn ] =
+//          [ a1 + sum abs(xi-yi), .. , am + sum abs(xj-yj) ],
+//      for m <= n and non-overlapping sums.
+class HVecSADAccumulate FINAL : public HVecOperation {
+ public:
+  HVecSADAccumulate(ArenaAllocator* arena,
+                    HInstruction* accumulator,
+                    HInstruction* sad_left,
+                    HInstruction* sad_right,
+                    DataType::Type packed_type,
+                    size_t vector_length,
+                    uint32_t dex_pc = kNoDexPc)
+      : HVecOperation(arena,
+                      packed_type,
+                      SideEffects::None(),
+                      /* number_of_inputs */ 3,
+                      vector_length,
+                      dex_pc) {
+    DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
+    DCHECK(sad_left->IsVecOperation());
+    DCHECK(sad_right->IsVecOperation());
+    DCHECK_EQ(sad_left->AsVecOperation()->GetPackedType(),
+              sad_right->AsVecOperation()->GetPackedType());
+    SetRawInputAt(0, accumulator);
+    SetRawInputAt(1, sad_left);
+    SetRawInputAt(2, sad_right);
+  }
+
+  DECLARE_INSTRUCTION(VecSADAccumulate);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HVecSADAccumulate);
+};
+
 // Loads a vector from memory, viz. load(mem, 1)
 // yield the vector [ mem(1), .. , mem(n) ].
 class HVecLoad FINAL : public HVecMemoryOperation {
@@ -901,7 +932,7 @@
   HVecLoad(ArenaAllocator* arena,
            HInstruction* base,
            HInstruction* index,
-           Primitive::Type packed_type,
+           DataType::Type packed_type,
            size_t vector_length,
            bool is_string_char_at,
            uint32_t dex_pc = kNoDexPc)
@@ -945,7 +976,7 @@
             HInstruction* base,
             HInstruction* index,
             HInstruction* value,
-            Primitive::Type packed_type,
+            DataType::Type packed_type,
             size_t vector_length,
             uint32_t dex_pc = kNoDexPc)
       : HVecMemoryOperation(arena,
diff --git a/compiler/optimizing/nodes_vector_test.cc b/compiler/optimizing/nodes_vector_test.cc
index 5a56a2c..3acdb20 100644
--- a/compiler/optimizing/nodes_vector_test.cc
+++ b/compiler/optimizing/nodes_vector_test.cc
@@ -45,7 +45,7 @@
     parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                    dex::TypeIndex(0),
                                                    0,
-                                                   Primitive::kPrimInt);
+                                                   DataType::Type::kInt32);
     entry_block_->AddInstruction(parameter_);
   }
 
@@ -119,15 +119,15 @@
 
 TEST_F(NodesVectorTest, VectorOperationProperties) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
   HVecOperation* v1 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
   HVecOperation* v2 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 2);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 2);
   HVecOperation* v3 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimShort, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt16, 4);
   HVecOperation* v4 = new (&allocator_)
-      HVecStore(&allocator_, parameter_, parameter_, v0, Primitive::kPrimInt, 4);
+      HVecStore(&allocator_, parameter_, parameter_, v0, DataType::Type::kInt32, 4);
 
   EXPECT_TRUE(v0->Equals(v0));
   EXPECT_TRUE(v1->Equals(v1));
@@ -149,17 +149,17 @@
   EXPECT_EQ(4u, v3->GetVectorLength());
   EXPECT_EQ(4u, v4->GetVectorLength());
 
-  EXPECT_EQ(Primitive::kPrimDouble, v0->GetType());
-  EXPECT_EQ(Primitive::kPrimDouble, v1->GetType());
-  EXPECT_EQ(Primitive::kPrimDouble, v2->GetType());
-  EXPECT_EQ(Primitive::kPrimDouble, v3->GetType());
-  EXPECT_EQ(Primitive::kPrimDouble, v4->GetType());
+  EXPECT_EQ(DataType::Type::kFloat64, v0->GetType());
+  EXPECT_EQ(DataType::Type::kFloat64, v1->GetType());
+  EXPECT_EQ(DataType::Type::kFloat64, v2->GetType());
+  EXPECT_EQ(DataType::Type::kFloat64, v3->GetType());
+  EXPECT_EQ(DataType::Type::kFloat64, v4->GetType());
 
-  EXPECT_EQ(Primitive::kPrimInt, v0->GetPackedType());
-  EXPECT_EQ(Primitive::kPrimInt, v1->GetPackedType());
-  EXPECT_EQ(Primitive::kPrimInt, v2->GetPackedType());
-  EXPECT_EQ(Primitive::kPrimShort, v3->GetPackedType());
-  EXPECT_EQ(Primitive::kPrimInt, v4->GetPackedType());
+  EXPECT_EQ(DataType::Type::kInt32, v0->GetPackedType());
+  EXPECT_EQ(DataType::Type::kInt32, v1->GetPackedType());
+  EXPECT_EQ(DataType::Type::kInt32, v2->GetPackedType());
+  EXPECT_EQ(DataType::Type::kInt16, v3->GetPackedType());
+  EXPECT_EQ(DataType::Type::kInt32, v4->GetPackedType());
 
   EXPECT_EQ(16u, v0->GetVectorNumberOfBytes());
   EXPECT_EQ(16u, v1->GetVectorNumberOfBytes());
@@ -175,12 +175,12 @@
 }
 
 TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) {
-  HVecLoad* v0 = new (&allocator_)
-      HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ false);
-  HVecLoad* v1 = new (&allocator_)
-      HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ false);
-  HVecLoad* v2 = new (&allocator_)
-      HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ true);
+  HVecLoad* v0 = new (&allocator_) HVecLoad(
+      &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ false);
+  HVecLoad* v1 = new (&allocator_) HVecLoad(
+      &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ false);
+  HVecLoad* v2 = new (&allocator_) HVecLoad(
+      &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ true);
 
   EXPECT_TRUE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
@@ -210,14 +210,14 @@
 
 TEST_F(NodesVectorTest, VectorSignMattersOnMin) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
 
   HVecMin* v1 = new (&allocator_)
-      HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true);
+      HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true);
   HVecMin* v2 = new (&allocator_)
-      HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false);
+      HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false);
   HVecMin* v3 = new (&allocator_)
-      HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true);
+      HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true);
 
   EXPECT_FALSE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
@@ -238,14 +238,14 @@
 
 TEST_F(NodesVectorTest, VectorSignMattersOnMax) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
 
   HVecMax* v1 = new (&allocator_)
-      HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true);
+      HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true);
   HVecMax* v2 = new (&allocator_)
-      HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false);
+      HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false);
   HVecMax* v3 = new (&allocator_)
-      HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true);
+      HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true);
 
   EXPECT_FALSE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
@@ -266,18 +266,18 @@
 
 TEST_F(NodesVectorTest, VectorAttributesMatterOnHalvingAdd) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
 
   HVecHalvingAdd* v1 = new (&allocator_) HVecHalvingAdd(
-      &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true, /*is_rounded*/ true);
+      &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, /*is_rounded*/ true);
   HVecHalvingAdd* v2 = new (&allocator_) HVecHalvingAdd(
-      &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true, /*is_rounded*/ false);
+      &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, /*is_rounded*/ false);
   HVecHalvingAdd* v3 = new (&allocator_) HVecHalvingAdd(
-      &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false, /*is_rounded*/ true);
+      &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, /*is_rounded*/ true);
   HVecHalvingAdd* v4 = new (&allocator_) HVecHalvingAdd(
-      &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false, /*is_rounded*/ false);
+      &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, /*is_rounded*/ false);
   HVecHalvingAdd* v5 = new (&allocator_) HVecHalvingAdd(
-      &allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true, /*is_rounded*/ true);
+      &allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true, /*is_rounded*/ true);
 
   EXPECT_FALSE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
@@ -306,14 +306,14 @@
 
 TEST_F(NodesVectorTest, VectorOperationMattersOnMultiplyAccumulate) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
 
-  HVecMultiplyAccumulate* v1 = new (&allocator_)
-      HVecMultiplyAccumulate(&allocator_, HInstruction::kAdd, v0, v0, v0, Primitive::kPrimInt, 4);
-  HVecMultiplyAccumulate* v2 = new (&allocator_)
-      HVecMultiplyAccumulate(&allocator_, HInstruction::kSub, v0, v0, v0, Primitive::kPrimInt, 4);
-  HVecMultiplyAccumulate* v3 = new (&allocator_)
-      HVecMultiplyAccumulate(&allocator_, HInstruction::kAdd, v0, v0, v0, Primitive::kPrimInt, 2);
+  HVecMultiplyAccumulate* v1 = new (&allocator_) HVecMultiplyAccumulate(
+      &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 4);
+  HVecMultiplyAccumulate* v2 = new (&allocator_) HVecMultiplyAccumulate(
+      &allocator_, HInstruction::kSub, v0, v0, v0, DataType::Type::kInt32, 4);
+  HVecMultiplyAccumulate* v3 = new (&allocator_) HVecMultiplyAccumulate(
+      &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 2);
 
   EXPECT_FALSE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
@@ -334,14 +334,14 @@
 
 TEST_F(NodesVectorTest, VectorKindMattersOnReduce) {
   HVecOperation* v0 = new (&allocator_)
-      HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4);
+      HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
 
   HVecReduce* v1 = new (&allocator_) HVecReduce(
-      &allocator_, v0, Primitive::kPrimInt, 4, HVecReduce::kSum);
+      &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kSum);
   HVecReduce* v2 = new (&allocator_) HVecReduce(
-      &allocator_, v0, Primitive::kPrimInt, 4, HVecReduce::kMin);
+      &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMin);
   HVecReduce* v3 = new (&allocator_) HVecReduce(
-      &allocator_, v0, Primitive::kPrimInt, 4, HVecReduce::kMax);
+      &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMax);
 
   EXPECT_FALSE(v0->CanBeMoved());
   EXPECT_TRUE(v1->CanBeMoved());
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
index 75893c3..22e92ea 100644
--- a/compiler/optimizing/nodes_x86.h
+++ b/compiler/optimizing/nodes_x86.h
@@ -24,7 +24,7 @@
  public:
   // Treat the value as an int32_t, but it is really a 32 bit native pointer.
   HX86ComputeBaseMethodAddress()
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc) {}
+      : HExpression(DataType::Type::kInt32, SideEffects::None(), kNoDexPc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -61,12 +61,12 @@
 // Version of HNeg with access to the constant table for FP types.
 class HX86FPNeg FINAL : public HExpression<2> {
  public:
-  HX86FPNeg(Primitive::Type result_type,
+  HX86FPNeg(DataType::Type result_type,
             HInstruction* input,
             HX86ComputeBaseMethodAddress* method_base,
             uint32_t dex_pc)
       : HExpression(result_type, SideEffects::None(), dex_pc) {
-    DCHECK(Primitive::IsFloatingPointType(result_type));
+    DCHECK(DataType::IsFloatingPointType(result_type));
     SetRawInputAt(0, input);
     SetRawInputAt(1, method_base);
   }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 2305cef..10b3fe1 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -77,6 +77,7 @@
 #include "jit/jit_logger.h"
 #include "jni/quick/jni_compiler.h"
 #include "licm.h"
+#include "linker/linker_patch.h"
 #include "load_store_analysis.h"
 #include "load_store_elimination.h"
 #include "loop_optimization.h"
@@ -849,13 +850,13 @@
   RunArchOptimizations(driver->GetInstructionSet(), graph, codegen, pass_observer);
 }
 
-static ArenaVector<LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) {
-  ArenaVector<LinkerPatch> linker_patches(codegen->GetGraph()->GetArena()->Adapter());
+static ArenaVector<linker::LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) {
+  ArenaVector<linker::LinkerPatch> linker_patches(codegen->GetGraph()->GetArena()->Adapter());
   codegen->EmitLinkerPatches(&linker_patches);
 
   // Sort patches by literal offset. Required for .oat_patches encoding.
   std::sort(linker_patches.begin(), linker_patches.end(),
-            [](const LinkerPatch& lhs, const LinkerPatch& rhs) {
+            [](const linker::LinkerPatch& lhs, const linker::LinkerPatch& rhs) {
     return lhs.LiteralOffset() < rhs.LiteralOffset();
   });
 
@@ -867,7 +868,7 @@
                                          CodeGenerator* codegen,
                                          CompilerDriver* compiler_driver,
                                          const DexFile::CodeItem* code_item) const {
-  ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
+  ArenaVector<linker::LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
   ArenaVector<uint8_t> stack_map(arena->Adapter(kArenaAllocStackMaps));
   ArenaVector<uint8_t> method_info(arena->Adapter(kArenaAllocStackMaps));
   size_t stack_map_size = 0;
@@ -892,7 +893,7 @@
       ArrayRef<const uint8_t>(method_info),
       ArrayRef<const uint8_t>(stack_map),
       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
-      ArrayRef<const LinkerPatch>(linker_patches));
+      ArrayRef<const linker::LinkerPatch>(linker_patches));
 
   return compiled_method;
 }
@@ -1005,8 +1006,6 @@
     HGraphBuilder builder(graph,
                           &dex_compilation_unit,
                           &dex_compilation_unit,
-                          &dex_file,
-                          *code_item,
                           compiler_driver,
                           codegen.get(),
                           compilation_stats_.get(),
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 08493fa..33f1a4a 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -50,7 +50,8 @@
                             ArenaAllocator* allocator,
                             int reg = -1,
                             HInstruction* defined_by = nullptr) {
-  LiveInterval* interval = LiveInterval::MakeInterval(allocator, Primitive::kPrimInt, defined_by);
+  LiveInterval* interval =
+      LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by);
   if (defined_by != nullptr) {
     defined_by->SetLiveInterval(interval);
   }
@@ -88,7 +89,7 @@
 // Create a control-flow graph from Dex instructions.
 inline HGraph* CreateCFG(ArenaAllocator* allocator,
                          const uint16_t* data,
-                         Primitive::Type return_type = Primitive::kPrimInt) {
+                         DataType::Type return_type = DataType::Type::kInt32) {
   const DexFile::CodeItem* item =
     reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = CreateGraph(allocator);
diff --git a/compiler/optimizing/parallel_move_resolver.cc b/compiler/optimizing/parallel_move_resolver.cc
index be470cc..2036b4a 100644
--- a/compiler/optimizing/parallel_move_resolver.cc
+++ b/compiler/optimizing/parallel_move_resolver.cc
@@ -457,7 +457,7 @@
     DCHECK_NE(kind, Location::kConstant);
     Location scratch = AllocateScratchLocationFor(kind);
     // We only care about the move size.
-    Primitive::Type type = move->Is64BitMove() ? Primitive::kPrimLong : Primitive::kPrimInt;
+    DataType::Type type = move->Is64BitMove() ? DataType::Type::kInt64 : DataType::Type::kInt32;
     // Perform (C -> scratch)
     move->SetDestination(scratch);
     EmitMove(index);
@@ -521,7 +521,8 @@
 }
 
 void ParallelMoveResolverNoSwap::AddPendingMove(Location source,
-    Location destination, Primitive::Type type) {
+                                                Location destination,
+                                                DataType::Type type) {
   pending_moves_.push_back(new (allocator_) MoveOperands(source, destination, type, nullptr));
 }
 
diff --git a/compiler/optimizing/parallel_move_resolver.h b/compiler/optimizing/parallel_move_resolver.h
index 4278861..e6e069f 100644
--- a/compiler/optimizing/parallel_move_resolver.h
+++ b/compiler/optimizing/parallel_move_resolver.h
@@ -19,8 +19,8 @@
 
 #include "base/arena_containers.h"
 #include "base/value_object.h"
+#include "data_type.h"
 #include "locations.h"
-#include "primitive.h"
 
 namespace art {
 
@@ -177,7 +177,7 @@
 
   void UpdateMoveSource(Location from, Location to);
 
-  void AddPendingMove(Location source, Location destination, Primitive::Type type);
+  void AddPendingMove(Location source, Location destination, DataType::Type type);
 
   void DeletePendingMove(MoveOperands* move);
 
diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc
index 50620f0..cb87cab 100644
--- a/compiler/optimizing/parallel_move_test.cc
+++ b/compiler/optimizing/parallel_move_test.cc
@@ -158,7 +158,7 @@
     moves->AddMove(
         Location::RegisterLocation(operands[i][0]),
         Location::RegisterLocation(operands[i][1]),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
   }
   return moves;
@@ -264,12 +264,12 @@
   moves->AddMove(
       Location::ConstantLocation(new (&allocator) HIntConstant(0)),
       Location::RegisterLocation(0),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   moves->AddMove(
       Location::RegisterLocation(1),
       Location::RegisterLocation(2),
-      Primitive::kPrimInt,
+      DataType::Type::kInt32,
       nullptr);
   resolver.EmitNativeCode(moves);
   ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str());
@@ -285,12 +285,12 @@
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(4),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str());
@@ -302,12 +302,12 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(4),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str());
@@ -319,12 +319,12 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(0),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -339,17 +339,17 @@
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(7),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(7),
         Location::RegisterLocation(1),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -365,17 +365,17 @@
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(7),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(7),
         Location::RegisterLocation(1),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -391,17 +391,17 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(7),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(7),
         Location::RegisterLocation(1),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -416,12 +416,12 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(2, 3),
         Location::RegisterPairLocation(0, 1),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -436,12 +436,12 @@
     moves->AddMove(
         Location::RegisterPairLocation(2, 3),
         Location::RegisterPairLocation(0, 1),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -473,17 +473,17 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(0),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(3),
         Location::RegisterLocation(1),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -499,17 +499,17 @@
     moves->AddMove(
         Location::RegisterLocation(2),
         Location::RegisterLocation(0),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(3),
         Location::RegisterLocation(1),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -527,17 +527,17 @@
     moves->AddMove(
         Location::RegisterLocation(10),
         Location::RegisterLocation(5),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(4, 5),
         Location::DoubleStackSlot(32),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::DoubleStackSlot(32),
         Location::RegisterPairLocation(10, 11),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -560,17 +560,17 @@
     moves->AddMove(
         Location::RegisterLocation(0),
         Location::RegisterLocation(1),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(1),
         Location::StackSlot(48),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::StackSlot(48),
         Location::RegisterLocation(0),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -587,17 +587,17 @@
     moves->AddMove(
         Location::RegisterPairLocation(0, 1),
         Location::RegisterPairLocation(2, 3),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(2, 3),
         Location::DoubleStackSlot(32),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::DoubleStackSlot(32),
         Location::RegisterPairLocation(0, 1),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
@@ -619,17 +619,17 @@
     moves->AddMove(
         Location::RegisterLocation(0),
         Location::RegisterLocation(3),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     moves->AddMove(
         Location::RegisterPairLocation(2, 3),
         Location::RegisterPairLocation(0, 1),
-        Primitive::kPrimLong,
+        DataType::Type::kInt64,
         nullptr);
     moves->AddMove(
         Location::RegisterLocation(7),
         Location::RegisterLocation(2),
-        Primitive::kPrimInt,
+        DataType::Type::kInt32,
         nullptr);
     resolver.EmitNativeCode(moves);
     if (TestFixture::has_swap) {
diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc
index 9877e10..a114e78 100644
--- a/compiler/optimizing/pc_relative_fixups_x86.cc
+++ b/compiler/optimizing/pc_relative_fixups_x86.cc
@@ -63,7 +63,7 @@
 
   void VisitReturn(HReturn* ret) OVERRIDE {
     HConstant* value = ret->InputAt(0)->AsConstant();
-    if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
+    if ((value != nullptr && DataType::IsFloatingPointType(value->GetType()))) {
       ReplaceInput(ret, value, 0, true);
     }
   }
@@ -102,7 +102,7 @@
 
   void BinaryFP(HBinaryOperation* bin) {
     HConstant* rhs = bin->InputAt(1)->AsConstant();
-    if (rhs != nullptr && Primitive::IsFloatingPointType(rhs->GetType())) {
+    if (rhs != nullptr && DataType::IsFloatingPointType(rhs->GetType())) {
       ReplaceInput(bin, rhs, 1, false);
     }
   }
@@ -132,7 +132,7 @@
   }
 
   void VisitNeg(HNeg* neg) OVERRIDE {
-    if (Primitive::IsFloatingPointType(neg->GetType())) {
+    if (DataType::IsFloatingPointType(neg->GetType())) {
       // We need to replace the HNeg with a HX86FPNeg in order to address the constant area.
       HX86ComputeBaseMethodAddress* method_address = GetPCRelativeBasePointer(neg);
       HGraph* graph = GetGraph();
@@ -225,7 +225,7 @@
     HInputsRef inputs = invoke->GetInputs();
     for (size_t i = 0; i < inputs.size(); i++) {
       HConstant* input = inputs[i]->AsConstant();
-      if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
+      if (input != nullptr && DataType::IsFloatingPointType(input->GetType())) {
         ReplaceInput(invoke, input, i, true);
       }
     }
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 2c856cd..b52de36 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -77,7 +77,7 @@
   // BoundType (as value input of this ArraySet) with a NullConstant.
   // If so, this ArraySet no longer needs a type check.
   if (value->IsNullConstant()) {
-    DCHECK_EQ(value->GetType(), Primitive::kPrimNot);
+    DCHECK_EQ(value->GetType(), DataType::Type::kReference);
     if (instruction->NeedsTypeCheck()) {
       instruction->ClearNeedsTypeCheck();
     }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 93613a5..f5064c3 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -133,7 +133,7 @@
     for (HBasicBlock* block : graph_->GetReversePostOrder()) {
       for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
         HInstruction* instr = iti.Current();
-        if (instr->GetType() == Primitive::kPrimNot) {
+        if (instr->GetType() == DataType::Type::kReference) {
           DCHECK(instr->GetReferenceTypeInfo().IsValid())
               << "Invalid RTI for instruction: " << instr->DebugName();
           if (instr->IsBoundType()) {
@@ -555,7 +555,7 @@
                                                                    dex::TypeIndex type_idx,
                                                                    const DexFile& dex_file,
                                                                    bool is_exact) {
-  DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
+  DCHECK_EQ(instr->GetType(), DataType::Type::kReference);
 
   ScopedObjectAccess soa(Thread::Current());
   ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
@@ -576,7 +576,7 @@
 
 void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
   // We check if the existing type is valid: the inliner may have set it.
-  if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
+  if (instr->GetType() == DataType::Type::kReference && !instr->GetReferenceTypeInfo().IsValid()) {
     UpdateReferenceTypeInfo(instr,
                             instr->GetTypeIndex(),
                             instr->GetDexFile(),
@@ -586,7 +586,7 @@
 
 void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
                                                                      const FieldInfo& info) {
-  if (instr->GetType() != Primitive::kPrimNot) {
+  if (instr->GetType() != DataType::Type::kReference) {
     return;
   }
 
@@ -612,7 +612,7 @@
 void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
     HUnresolvedInstanceFieldGet* instr) {
   // TODO: Use descriptor to get the actual type.
-  if (instr->GetFieldType() == Primitive::kPrimNot) {
+  if (instr->GetFieldType() == DataType::Type::kReference) {
     instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
   }
 }
@@ -620,7 +620,7 @@
 void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
     HUnresolvedStaticFieldGet* instr) {
   // TODO: Use descriptor to get the actual type.
-  if (instr->GetFieldType() == Primitive::kPrimNot) {
+  if (instr->GetFieldType() == DataType::Type::kReference) {
     instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
   }
 }
@@ -729,7 +729,7 @@
 }
 
 void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
-  if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
+  if (phi->IsDead() || phi->GetType() != DataType::Type::kReference) {
     return;
   }
 
@@ -813,7 +813,7 @@
 }
 
 void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
-  DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
+  DCHECK_EQ(DataType::Type::kReference, instr->GetType());
 
   ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
   if (!parent_rti.IsValid()) {
@@ -857,7 +857,7 @@
 }
 
 void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
-  if (instr->GetType() != Primitive::kPrimNot) {
+  if (instr->GetType() != DataType::Type::kReference) {
     return;
   }
 
@@ -868,7 +868,7 @@
 }
 
 void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
-  if (instr->GetType() != Primitive::kPrimNot) {
+  if (instr->GetType() != DataType::Type::kReference) {
     return;
   }
 
@@ -989,7 +989,7 @@
 }
 
 void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
-  DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
+  DCHECK_EQ(instruction->GetType(), DataType::Type::kReference)
       << instruction->DebugName() << ":" << instruction->GetType();
   worklist_.push_back(instruction);
 }
@@ -1000,7 +1000,7 @@
     if ((user->IsPhi() && user->AsPhi()->IsLive())
        || user->IsBoundType()
        || user->IsNullCheck()
-       || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
+       || (user->IsArrayGet() && (user->GetType() == DataType::Type::kReference))) {
       AddToWorklist(user);
     }
   }
diff --git a/compiler/optimizing/register_allocation_resolver.cc b/compiler/optimizing/register_allocation_resolver.cc
index ce3a496..f0057c3 100644
--- a/compiler/optimizing/register_allocation_resolver.cc
+++ b/compiler/optimizing/register_allocation_resolver.cc
@@ -100,24 +100,24 @@
       // [art method            ].
       size_t slot = current->GetSpillSlot();
       switch (current->GetType()) {
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           slot += long_spill_slots;
           FALLTHROUGH_INTENDED;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           slot += float_spill_slots;
           FALLTHROUGH_INTENDED;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           slot += int_spill_slots;
           FALLTHROUGH_INTENDED;
-        case Primitive::kPrimNot:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
-        case Primitive::kPrimByte:
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimShort:
+        case DataType::Type::kReference:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt8:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt16:
           slot += reserved_out_slots;
           break;
-        case Primitive::kPrimVoid:
+        case DataType::Type::kVoid:
           LOG(FATAL) << "Unexpected type for interval " << current->GetType();
       }
       current->SetSpillSlot(slot * kVRegSize);
@@ -205,12 +205,12 @@
     size_t temp_index = liveness_.GetTempIndex(temp);
     LocationSummary* locations = at->GetLocations();
     switch (temp->GetType()) {
-      case Primitive::kPrimInt:
+      case DataType::Type::kInt32:
         locations->SetTempAt(temp_index, Location::RegisterLocation(temp->GetRegister()));
         break;
 
-      case Primitive::kPrimDouble:
-        if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+      case DataType::Type::kFloat64:
+        if (codegen_->NeedsTwoRegisters(DataType::Type::kFloat64)) {
           Location location = Location::FpuRegisterPairLocation(
               temp->GetRegister(), temp->GetHighInterval()->GetRegister());
           locations->SetTempAt(temp_index, location);
@@ -383,7 +383,7 @@
          safepoint_position = safepoint_position->GetNext()) {
       DCHECK(current->CoversSlow(safepoint_position->GetPosition()));
 
-      if (current->GetType() == Primitive::kPrimNot) {
+      if (current->GetType() == DataType::Type::kReference) {
         DCHECK(interval->GetDefinedBy()->IsActualObject())
             << interval->GetDefinedBy()->DebugName()
             << '(' << interval->GetDefinedBy()->GetId() << ')'
@@ -507,13 +507,13 @@
                                          Location source,
                                          Location destination,
                                          HInstruction* instruction,
-                                         Primitive::Type type) const {
-  if (type == Primitive::kPrimLong
+                                         DataType::Type type) const {
+  if (type == DataType::Type::kInt64
       && codegen_->ShouldSplitLongMoves()
       // The parallel move resolver knows how to deal with long constants.
       && !source.IsConstant()) {
-    move->AddMove(source.ToLow(), destination.ToLow(), Primitive::kPrimInt, instruction);
-    move->AddMove(source.ToHigh(), destination.ToHigh(), Primitive::kPrimInt, nullptr);
+    move->AddMove(source.ToLow(), destination.ToLow(), DataType::Type::kInt32, instruction);
+    move->AddMove(source.ToHigh(), destination.ToHigh(), DataType::Type::kInt32, nullptr);
   } else {
     move->AddMove(source, destination, type, instruction);
   }
diff --git a/compiler/optimizing/register_allocation_resolver.h b/compiler/optimizing/register_allocation_resolver.h
index d48b1a0..4a148e0 100644
--- a/compiler/optimizing/register_allocation_resolver.h
+++ b/compiler/optimizing/register_allocation_resolver.h
@@ -20,7 +20,7 @@
 #include "base/arena_containers.h"
 #include "base/array_ref.h"
 #include "base/value_object.h"
-#include "primitive.h"
+#include "data_type.h"
 
 namespace art {
 
@@ -88,7 +88,7 @@
                Location source,
                Location destination,
                HInstruction* instruction,
-               Primitive::Type type) const;
+               DataType::Type type) const;
 
   ArenaAllocator* const allocator_;
   CodeGenerator* const codegen_;
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index 7e1fff8..4375d68 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -21,7 +21,6 @@
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "base/macros.h"
-#include "primitive.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/register_allocator_graph_color.cc b/compiler/optimizing/register_allocator_graph_color.cc
index 5e22772..4ff7315 100644
--- a/compiler/optimizing/register_allocator_graph_color.cc
+++ b/compiler/optimizing/register_allocator_graph_color.cc
@@ -540,7 +540,7 @@
 };
 
 static bool IsCoreInterval(LiveInterval* interval) {
-  return !Primitive::IsFloatingPointType(interval->GetType());
+  return !DataType::IsFloatingPointType(interval->GetType());
 }
 
 static size_t ComputeReservedArtMethodSlots(const CodeGenerator& codegen) {
@@ -573,7 +573,7 @@
   // This includes globally blocked registers, such as the stack pointer.
   physical_core_nodes_.resize(codegen_->GetNumberOfCoreRegisters(), nullptr);
   for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
-    LiveInterval* interval = LiveInterval::MakeFixedInterval(allocator_, i, Primitive::kPrimInt);
+    LiveInterval* interval = LiveInterval::MakeFixedInterval(allocator_, i, DataType::Type::kInt32);
     physical_core_nodes_[i] =
         new (allocator_) InterferenceNode(allocator_, interval, liveness);
     physical_core_nodes_[i]->stage = NodeStage::kPrecolored;
@@ -585,7 +585,8 @@
   // Initialize physical floating point register live intervals and blocked registers.
   physical_fp_nodes_.resize(codegen_->GetNumberOfFloatingPointRegisters(), nullptr);
   for (size_t i = 0; i < codegen_->GetNumberOfFloatingPointRegisters(); ++i) {
-    LiveInterval* interval = LiveInterval::MakeFixedInterval(allocator_, i, Primitive::kPrimFloat);
+    LiveInterval* interval =
+        LiveInterval::MakeFixedInterval(allocator_, i, DataType::Type::kFloat32);
     physical_fp_nodes_[i] =
         new (allocator_) InterferenceNode(allocator_, interval, liveness);
     physical_fp_nodes_[i]->stage = NodeStage::kPrecolored;
@@ -936,7 +937,7 @@
       switch (temp.GetPolicy()) {
         case Location::kRequiresRegister: {
           LiveInterval* interval =
-              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
+              LiveInterval::MakeTempInterval(allocator_, DataType::Type::kInt32);
           interval->AddTempUse(instruction, i);
           core_intervals_.push_back(interval);
           temp_intervals_.push_back(interval);
@@ -945,11 +946,11 @@
 
         case Location::kRequiresFpuRegister: {
           LiveInterval* interval =
-              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
+              LiveInterval::MakeTempInterval(allocator_, DataType::Type::kFloat64);
           interval->AddTempUse(instruction, i);
           fp_intervals_.push_back(interval);
           temp_intervals_.push_back(interval);
-          if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+          if (codegen_->NeedsTwoRegisters(DataType::Type::kFloat64)) {
             interval->AddHighInterval(/*is_temp*/ true);
             temp_intervals_.push_back(interval->GetHighInterval());
           }
@@ -1927,24 +1928,24 @@
       // We need to find a spill slot for this interval. Place it in the correct
       // worklist to be processed later.
       switch (node->GetInterval()->GetType()) {
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           double_intervals.push_back(parent);
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           long_intervals.push_back(parent);
           break;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           float_intervals.push_back(parent);
           break;
-        case Primitive::kPrimNot:
-        case Primitive::kPrimInt:
-        case Primitive::kPrimChar:
-        case Primitive::kPrimByte:
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimShort:
+        case DataType::Type::kReference:
+        case DataType::Type::kInt32:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt8:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt16:
           int_intervals.push_back(parent);
           break;
-        case Primitive::kPrimVoid:
+        case DataType::Type::kVoid:
           LOG(FATAL) << "Unexpected type for interval " << node->GetInterval()->GetType();
           UNREACHABLE();
       }
diff --git a/compiler/optimizing/register_allocator_graph_color.h b/compiler/optimizing/register_allocator_graph_color.h
index 548687f..3f6d674 100644
--- a/compiler/optimizing/register_allocator_graph_color.h
+++ b/compiler/optimizing/register_allocator_graph_color.h
@@ -21,7 +21,6 @@
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "base/macros.h"
-#include "primitive.h"
 #include "register_allocator.h"
 
 namespace art {
diff --git a/compiler/optimizing/register_allocator_linear_scan.cc b/compiler/optimizing/register_allocator_linear_scan.cc
index ab8d540..2012cd5 100644
--- a/compiler/optimizing/register_allocator_linear_scan.cc
+++ b/compiler/optimizing/register_allocator_linear_scan.cc
@@ -83,8 +83,8 @@
 
 static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
   if (interval == nullptr) return false;
-  bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
-      && (interval->GetType() != Primitive::kPrimFloat);
+  bool is_core_register = (interval->GetType() != DataType::Type::kFloat64)
+      && (interval->GetType() != DataType::Type::kFloat32);
   return processing_core_registers == is_core_register;
 }
 
@@ -132,9 +132,9 @@
   LiveInterval* interval = location.IsRegister()
       ? physical_core_register_intervals_[reg]
       : physical_fp_register_intervals_[reg];
-  Primitive::Type type = location.IsRegister()
-      ? Primitive::kPrimInt
-      : Primitive::kPrimFloat;
+  DataType::Type type = location.IsRegister()
+      ? DataType::Type::kInt32
+      : DataType::Type::kFloat32;
   if (interval == nullptr) {
     interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
     if (location.IsRegister()) {
@@ -237,7 +237,7 @@
       switch (temp.GetPolicy()) {
         case Location::kRequiresRegister: {
           LiveInterval* interval =
-              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
+              LiveInterval::MakeTempInterval(allocator_, DataType::Type::kInt32);
           temp_intervals_.push_back(interval);
           interval->AddTempUse(instruction, i);
           unhandled_core_intervals_.push_back(interval);
@@ -246,10 +246,10 @@
 
         case Location::kRequiresFpuRegister: {
           LiveInterval* interval =
-              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
+              LiveInterval::MakeTempInterval(allocator_, DataType::Type::kFloat64);
           temp_intervals_.push_back(interval);
           interval->AddTempUse(instruction, i);
-          if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+          if (codegen_->NeedsTwoRegisters(DataType::Type::kFloat64)) {
             interval->AddHighInterval(/* is_temp */ true);
             LiveInterval* high = interval->GetHighInterval();
             temp_intervals_.push_back(high);
@@ -266,8 +266,8 @@
     }
   }
 
-  bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
-      && (instruction->GetType() != Primitive::kPrimFloat);
+  bool core_register = (instruction->GetType() != DataType::Type::kFloat64)
+      && (instruction->GetType() != DataType::Type::kFloat32);
 
   if (locations->NeedsSafepoint()) {
     if (codegen_->IsLeafMethod()) {
@@ -1104,24 +1104,24 @@
 
   ArenaVector<size_t>* spill_slots = nullptr;
   switch (interval->GetType()) {
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       spill_slots = &double_spill_slots_;
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       spill_slots = &long_spill_slots_;
       break;
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       spill_slots = &float_spill_slots_;
       break;
-    case Primitive::kPrimNot:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimShort:
+    case DataType::Type::kReference:
+    case DataType::Type::kInt32:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt8:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt16:
       spill_slots = &int_spill_slots_;
       break;
-    case Primitive::kPrimVoid:
+    case DataType::Type::kVoid:
       LOG(FATAL) << "Unexpected type for interval " << interval->GetType();
   }
 
diff --git a/compiler/optimizing/register_allocator_linear_scan.h b/compiler/optimizing/register_allocator_linear_scan.h
index b3834f4..9c650a4 100644
--- a/compiler/optimizing/register_allocator_linear_scan.h
+++ b/compiler/optimizing/register_allocator_linear_scan.h
@@ -20,7 +20,6 @@
 #include "arch/instruction_set.h"
 #include "base/arena_containers.h"
 #include "base/macros.h"
-#include "primitive.h"
 #include "register_allocator.h"
 
 namespace art {
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index bcdd7f9..59987e2 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -461,15 +461,15 @@
   // Add three temps holding the same register, and starting at different positions.
   // Put the one that should be picked in the middle of the inactive list to ensure
   // we do not depend on an order.
-  LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
+  LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
   interval->AddRange(40, 50);
   register_allocator.inactive_.push_back(interval);
 
-  interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
+  interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
   interval->AddRange(20, 30);
   register_allocator.inactive_.push_back(interval);
 
-  interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
+  interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
   interval->AddRange(60, 70);
   register_allocator.inactive_.push_back(interval);
 
@@ -496,7 +496,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -505,7 +505,7 @@
 
   HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
                                                          nullptr,
-                                                         Primitive::kPrimBoolean,
+                                                         DataType::Type::kBool,
                                                          MemberOffset(22),
                                                          false,
                                                          kUnknownFieldIndex,
@@ -528,11 +528,11 @@
   then->AddInstruction(new (allocator) HGoto());
   else_->AddInstruction(new (allocator) HGoto());
 
-  *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  *phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
   join->AddPhi(*phi);
   *input1 = new (allocator) HInstanceFieldGet(parameter,
                                               nullptr,
-                                              Primitive::kPrimInt,
+                                              DataType::Type::kInt32,
                                               MemberOffset(42),
                                               false,
                                               kUnknownFieldIndex,
@@ -541,7 +541,7 @@
                                               0);
   *input2 = new (allocator) HInstanceFieldGet(parameter,
                                               nullptr,
-                                              Primitive::kPrimInt,
+                                              DataType::Type::kInt32,
                                               MemberOffset(42),
                                               false,
                                               kUnknownFieldIndex,
@@ -658,7 +658,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -667,7 +667,7 @@
 
   *field = new (allocator) HInstanceFieldGet(parameter,
                                              nullptr,
-                                             Primitive::kPrimInt,
+                                             DataType::Type::kInt32,
                                              MemberOffset(42),
                                              false,
                                              kUnknownFieldIndex,
@@ -742,7 +742,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   entry->AddInstruction(parameter);
 
   HInstruction* constant1 = graph->GetIntConstant(1);
@@ -752,9 +752,9 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
 
-  *first_sub = new (allocator) HSub(Primitive::kPrimInt, parameter, constant1);
+  *first_sub = new (allocator) HSub(DataType::Type::kInt32, parameter, constant1);
   block->AddInstruction(*first_sub);
-  *second_sub = new (allocator) HSub(Primitive::kPrimInt, *first_sub, constant2);
+  *second_sub = new (allocator) HSub(DataType::Type::kInt32, *first_sub, constant2);
   block->AddInstruction(*second_sub);
 
   block->AddInstruction(new (allocator) HExit());
@@ -821,9 +821,9 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* first = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   HInstruction* second = new (allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   entry->AddInstruction(first);
   entry->AddInstruction(second);
 
@@ -831,7 +831,8 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
 
-  *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0);  // don't care about dex_pc.
+  *div =
+      new (allocator) HDiv(DataType::Type::kInt32, first, second, 0);  // don't care about dex_pc.
   block->AddInstruction(*div);
 
   block->AddInstruction(new (allocator) HExit());
@@ -883,13 +884,13 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* one = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   HInstruction* two = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   HInstruction* three = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   HInstruction* four = new (&allocator) HParameterValue(
-      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   entry->AddInstruction(one);
   entry->AddInstruction(two);
   entry->AddInstruction(three);
@@ -902,7 +903,7 @@
 
   // We create a synthesized user requesting a register, to avoid just spilling the
   // intervals.
-  HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt);
+  HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, DataType::Type::kInt32);
   user->AddInput(one);
   user->SetBlock(block);
   LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc
index 38cd51b..5212e86 100644
--- a/compiler/optimizing/scheduler.cc
+++ b/compiler/optimizing/scheduler.cc
@@ -16,9 +16,11 @@
 
 #include <string>
 
-#include "prepare_for_register_allocation.h"
 #include "scheduler.h"
 
+#include "data_type-inl.h"
+#include "prepare_for_register_allocation.h"
+
 #ifdef ART_ENABLE_CODEGEN_arm64
 #include "scheduler_arm64.h"
 #endif
@@ -399,17 +401,7 @@
 }
 
 static const std::string InstructionTypeId(const HInstruction* instruction) {
-  std::string id;
-  Primitive::Type type = instruction->GetType();
-  if (type == Primitive::kPrimNot) {
-    id.append("l");
-  } else {
-    id.append(Primitive::Descriptor(instruction->GetType()));
-  }
-  // Use lower-case to be closer to the `HGraphVisualizer` output.
-  id[0] = std::tolower(id[0]);
-  id.append(std::to_string(instruction->GetId()));
-  return id;
+  return DataType::TypeId(instruction->GetType()) + std::to_string(instruction->GetId());
 }
 
 // Ideally we would reuse the graph visualizer code, but it is not available
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index 66756a5..110db47 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -31,15 +31,15 @@
 
 void SchedulingLatencyVisitorARM::HandleBinaryOperationLantencies(HBinaryOperation* instr) {
   switch (instr->GetResultType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       // HAdd and HSub long operations translate to ADDS+ADC or SUBS+SBC pairs,
       // so a bubble (kArmNopLatency) is added to represent the internal carry flag
       // dependency inside these pairs.
       last_visited_internal_latency_ = kArmIntegerOpLatency + kArmNopLatency;
       last_visited_latency_ = kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       last_visited_latency_ = kArmFloatingPointOpLatency;
       break;
     default:
@@ -58,12 +58,12 @@
 
 void SchedulingLatencyVisitorARM::VisitMul(HMul* instr) {
   switch (instr->GetResultType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       last_visited_internal_latency_ = 3 * kArmMulIntegerLatency;
       last_visited_latency_ = kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       last_visited_latency_ = kArmMulFloatingPointLatency;
       break;
     default:
@@ -74,12 +74,12 @@
 
 void SchedulingLatencyVisitorARM::HandleBitwiseOperationLantencies(HBinaryOperation* instr) {
   switch (instr->GetResultType()) {
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       last_visited_internal_latency_ = kArmIntegerOpLatency;
       last_visited_latency_ = kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       last_visited_latency_ = kArmFloatingPointOpLatency;
       break;
     default:
@@ -102,10 +102,10 @@
 
 void SchedulingLatencyVisitorARM::VisitRor(HRor* instr) {
   switch (instr->GetResultType()) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       last_visited_latency_ = kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       // HandleLongRotate
       HInstruction* rhs = instr->GetRight();
       if (rhs->IsConstant()) {
@@ -130,16 +130,16 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleShiftLatencies(HBinaryOperation* instr) {
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   HInstruction* rhs = instr->GetRight();
   switch (type) {
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       if (!rhs->IsConstant()) {
         last_visited_internal_latency_ = kArmIntegerOpLatency;
       }
       last_visited_latency_ = kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (!rhs->IsConstant()) {
         last_visited_internal_latency_ = 8 * kArmIntegerOpLatency;
       } else {
@@ -204,7 +204,7 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateLongTestConstant(HCondition* condition) {
-  DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(condition->GetLeft()->GetType(), DataType::Type::kInt64);
 
   IfCondition cond = condition->GetCondition();
 
@@ -270,7 +270,7 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateLongTest(HCondition* condition) {
-  DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(condition->GetLeft()->GetType(), DataType::Type::kInt64);
 
   IfCondition cond = condition->GetCondition();
 
@@ -301,13 +301,13 @@
 
 // The GenerateTest series of function all counted as internal latency.
 void SchedulingLatencyVisitorARM::HandleGenerateTest(HCondition* condition) {
-  const Primitive::Type type = condition->GetLeft()->GetType();
+  const DataType::Type type = condition->GetLeft()->GetType();
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     condition->InputAt(1)->IsConstant()
         ? HandleGenerateLongTestConstant(condition)
         : HandleGenerateLongTest(condition);
-  } else if (Primitive::IsFloatingPointType(type)) {
+  } else if (DataType::IsFloatingPointType(type)) {
     // GenerateVcmp + Vmrs
     last_visited_internal_latency_ += 2 * kArmFloatingPointOpLatency;
   } else {
@@ -317,7 +317,7 @@
 }
 
 bool SchedulingLatencyVisitorARM::CanGenerateTest(HCondition* condition) {
-  if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
+  if (condition->GetLeft()->GetType() == DataType::Type::kInt64) {
     HInstruction* right = condition->InputAt(1);
 
     if (right->IsConstant()) {
@@ -353,7 +353,7 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateEqualLong(HCondition* cond) {
-  DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(cond->GetLeft()->GetType(), DataType::Type::kInt64);
 
   IfCondition condition = cond->GetCondition();
 
@@ -374,7 +374,7 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateConditionLong(HCondition* cond) {
-  DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(cond->GetLeft()->GetType(), DataType::Type::kInt64);
 
   IfCondition condition = cond->GetCondition();
   HInstruction* right = cond->InputAt(1);
@@ -424,11 +424,11 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateConditionIntegralOrNonPrimitive(HCondition* cond) {
-  const Primitive::Type type = cond->GetLeft()->GetType();
+  const DataType::Type type = cond->GetLeft()->GetType();
 
-  DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+  DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
 
-  if (type == Primitive::kPrimLong) {
+  if (type == DataType::Type::kInt64) {
     HandleGenerateConditionLong(cond);
     return;
   }
@@ -482,19 +482,19 @@
     return;
   }
 
-  const Primitive::Type type = cond->GetLeft()->GetType();
+  const DataType::Type type = cond->GetLeft()->GetType();
 
-  if (Primitive::IsFloatingPointType(type)) {
+  if (DataType::IsFloatingPointType(type)) {
     HandleGenerateConditionGeneric(cond);
     return;
   }
 
-  DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
+  DCHECK(DataType::IsIntegralType(type) || type == DataType::Type::kReference) << type;
 
   const IfCondition condition = cond->GetCondition();
 
-  if (type == Primitive::kPrimBoolean &&
-      cond->GetRight()->GetType() == Primitive::kPrimBoolean &&
+  if (type == DataType::Type::kBool &&
+      cond->GetRight()->GetType() == DataType::Type::kBool &&
       (condition == kCondEQ || condition == kCondNE)) {
     if (condition == kCondEQ) {
       last_visited_internal_latency_ = kArmIntegerOpLatency;
@@ -511,20 +511,20 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitCompare(HCompare* instr) {
-  Primitive::Type type = instr->InputAt(0)->GetType();
+  DataType::Type type = instr->InputAt(0)->GetType();
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
       last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
       break;
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       last_visited_internal_latency_ = 2 * kArmIntegerOpLatency + 3 * kArmBranchLatency;
       break;
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat32:
+    case DataType::Type::kFloat64:
       last_visited_internal_latency_ = kArmIntegerOpLatency + 2 * kArmFloatingPointOpLatency;
       break;
     default:
@@ -535,7 +535,7 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
-  if (instruction->GetResultType() == Primitive::kPrimInt) {
+  if (instruction->GetResultType() == DataType::Type::kInt32) {
     last_visited_latency_ = kArmIntegerOpLatency;
   } else {
     last_visited_internal_latency_ = kArmIntegerOpLatency;
@@ -566,7 +566,7 @@
 }
 
 void SchedulingLatencyVisitorARM::HandleGenerateLongDataProc(HDataProcWithShifterOp* instruction) {
-  DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+  DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64);
   DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
 
   const uint32_t shift_value = instruction->GetShiftAmount();
@@ -595,10 +595,10 @@
 void SchedulingLatencyVisitorARM::VisitDataProcWithShifterOp(HDataProcWithShifterOp* instruction) {
   const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
 
-  if (instruction->GetType() == Primitive::kPrimInt) {
+  if (instruction->GetType() == DataType::Type::kInt32) {
     HandleGenerateDataProcInstruction();
   } else {
-    DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+    DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64);
     if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
       HandleGenerateDataProc(instruction);
     } else {
@@ -624,7 +624,7 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitArrayGet(HArrayGet* instruction) {
-  Primitive::Type type = instruction->GetType();
+  DataType::Type type = instruction->GetType();
   const bool maybe_compressed_char_at =
       mirror::kUseStringCompression && instruction->IsStringCharAt();
   HInstruction* array_instr = instruction->GetArray();
@@ -632,11 +632,11 @@
   HInstruction* index = instruction->InputAt(1);
 
   switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       if (maybe_compressed_char_at) {
         last_visited_internal_latency_ += kArmMemoryLoadLatency;
       }
@@ -664,7 +664,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         last_visited_latency_ = kArmLoadWithBakerReadBarrierLatency;
       } else {
@@ -681,7 +681,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -691,7 +691,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -701,7 +701,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -727,16 +727,16 @@
 
 void SchedulingLatencyVisitorARM::VisitArraySet(HArraySet* instruction) {
   HInstruction* index = instruction->InputAt(1);
-  Primitive::Type value_type = instruction->GetComponentType();
+  DataType::Type value_type = instruction->GetComponentType();
   HInstruction* array_instr = instruction->GetArray();
   bool has_intermediate_address = array_instr->IsIntermediateAddress();
 
   switch (value_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt: {
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryStoreLatency;
       } else {
@@ -749,7 +749,7 @@
       break;
     }
 
-    case Primitive::kPrimNot: {
+    case DataType::Type::kReference: {
       if (instruction->InputAt(2)->IsNullConstant()) {
         if (index->IsConstant()) {
           last_visited_latency_ = kArmMemoryStoreLatency;
@@ -765,7 +765,7 @@
       break;
     }
 
-    case Primitive::kPrimLong: {
+    case DataType::Type::kInt64: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -775,7 +775,7 @@
       break;
     }
 
-    case Primitive::kPrimFloat: {
+    case DataType::Type::kFloat32: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -785,7 +785,7 @@
       break;
     }
 
-    case Primitive::kPrimDouble: {
+    case DataType::Type::kFloat64: {
       if (index->IsConstant()) {
         last_visited_latency_ = kArmMemoryLoadLatency;
       } else {
@@ -823,9 +823,9 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitDiv(HDiv* instruction) {
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       HInstruction* rhs = instruction->GetRight();
       if (rhs->IsConstant()) {
         int32_t imm = Int32ConstantFrom(rhs->AsConstant());
@@ -835,10 +835,10 @@
       }
       break;
     }
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       last_visited_latency_ = kArmDivFloatLatency;
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       last_visited_latency_ = kArmDivDoubleLatency;
       break;
     default:
@@ -886,9 +886,9 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitRem(HRem* instruction) {
-  Primitive::Type type = instruction->GetResultType();
+  DataType::Type type = instruction->GetResultType();
   switch (type) {
-    case Primitive::kPrimInt: {
+    case DataType::Type::kInt32: {
       HInstruction* rhs = instruction->GetRight();
       if (rhs->IsConstant()) {
         int32_t imm = Int32ConstantFrom(rhs->AsConstant());
@@ -911,19 +911,19 @@
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   DCHECK(codegen_ != nullptr);
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt32:
       last_visited_latency_ = kArmMemoryLoadLatency;
       break;
 
-    case Primitive::kPrimNot:
+    case DataType::Type::kReference:
       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
         last_visited_internal_latency_ = kArmMemoryLoadLatency + kArmIntegerOpLatency;
         last_visited_latency_ = kArmMemoryLoadLatency;
@@ -932,7 +932,7 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (is_volatile && !atomic_ldrd_strd) {
         last_visited_internal_latency_ = kArmMemoryLoadLatency + kArmIntegerOpLatency;
         last_visited_latency_ = kArmMemoryLoadLatency;
@@ -941,11 +941,11 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       last_visited_latency_ = kArmMemoryLoadLatency;
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       if (is_volatile && !atomic_ldrd_strd) {
         last_visited_internal_latency_ =
             kArmMemoryLoadLatency + kArmIntegerOpLatency + kArmMemoryLoadLatency;
@@ -970,16 +970,16 @@
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   DCHECK(codegen_ != nullptr);
   bool is_volatile = field_info.IsVolatile();
-  Primitive::Type field_type = field_info.GetFieldType();
+  DataType::Type field_type = field_info.GetFieldType();
   bool needs_write_barrier =
       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
 
   switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
+    case DataType::Type::kBool:
+    case DataType::Type::kInt8:
+    case DataType::Type::kInt16:
+    case DataType::Type::kUint16:
       if (is_volatile) {
         last_visited_internal_latency_ = kArmMemoryBarrierLatency + kArmMemoryStoreLatency;
         last_visited_latency_ = kArmMemoryBarrierLatency;
@@ -988,15 +988,15 @@
       }
       break;
 
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
+    case DataType::Type::kInt32:
+    case DataType::Type::kReference:
       if (kPoisonHeapReferences && needs_write_barrier) {
         last_visited_internal_latency_ += kArmIntegerOpLatency * 2;
       }
       last_visited_latency_ = kArmMemoryStoreLatency;
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       if (is_volatile && !atomic_ldrd_strd) {
         last_visited_internal_latency_ =
             kArmIntegerOpLatency + kArmMemoryLoadLatency + kArmMemoryStoreLatency;
@@ -1006,11 +1006,11 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       last_visited_latency_ = kArmMemoryStoreLatency;
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       if (is_volatile && !atomic_ldrd_strd) {
         last_visited_internal_latency_ = kArmIntegerOpLatency +
             kArmIntegerOpLatency + kArmMemoryLoadLatency + kArmMemoryStoreLatency;
@@ -1043,23 +1043,23 @@
 }
 
 void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
-  Primitive::Type result_type = instr->GetResultType();
-  Primitive::Type input_type = instr->GetInputType();
+  DataType::Type result_type = instr->GetResultType();
+  DataType::Type input_type = instr->GetInputType();
 
   switch (result_type) {
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
       last_visited_latency_ = kArmIntegerOpLatency;  // SBFX or UBFX
       break;
 
-    case Primitive::kPrimInt:
+    case DataType::Type::kInt32:
       switch (input_type) {
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           last_visited_latency_ = kArmIntegerOpLatency;  // MOV
           break;
-        case Primitive::kPrimFloat:
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat32:
+        case DataType::Type::kFloat64:
           last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
@@ -1069,19 +1069,19 @@
       }
       break;
 
-    case Primitive::kPrimLong:
+    case DataType::Type::kInt64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimByte:
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           // MOV and extension
           last_visited_internal_latency_ = kArmIntegerOpLatency;
           last_visited_latency_ = kArmIntegerOpLatency;
           break;
-        case Primitive::kPrimFloat:
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat32:
+        case DataType::Type::kFloat64:
           // invokes runtime
           last_visited_internal_latency_ = kArmCallInternalLatency;
           break;
@@ -1092,21 +1092,21 @@
       }
       break;
 
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimByte:
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           // invokes runtime
           last_visited_internal_latency_ = kArmCallInternalLatency;
           break;
-        case Primitive::kPrimDouble:
+        case DataType::Type::kFloat64:
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
         default:
@@ -1115,21 +1115,21 @@
       }
       break;
 
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       switch (input_type) {
-        case Primitive::kPrimBoolean:
-        case Primitive::kPrimByte:
-        case Primitive::kPrimChar:
-        case Primitive::kPrimShort:
-        case Primitive::kPrimInt:
+        case DataType::Type::kBool:
+        case DataType::Type::kInt8:
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16:
+        case DataType::Type::kInt32:
           last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
-        case Primitive::kPrimLong:
+        case DataType::Type::kInt64:
           last_visited_internal_latency_ = 5 * kArmFloatingPointOpLatency;
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
-        case Primitive::kPrimFloat:
+        case DataType::Type::kFloat32:
           last_visited_latency_ = kArmFloatingPointOpLatency;
           break;
         default:
diff --git a/compiler/optimizing/scheduler_arm64.cc b/compiler/optimizing/scheduler_arm64.cc
index 1d9d28a..7bcf4e7 100644
--- a/compiler/optimizing/scheduler_arm64.cc
+++ b/compiler/optimizing/scheduler_arm64.cc
@@ -24,7 +24,7 @@
 namespace arm64 {
 
 void SchedulingLatencyVisitorARM64::VisitBinaryOperation(HBinaryOperation* instr) {
-  last_visited_latency_ = Primitive::IsFloatingPointType(instr->GetResultType())
+  last_visited_latency_ = DataType::IsFloatingPointType(instr->GetResultType())
       ? kArm64FloatingPointOpLatency
       : kArm64IntegerOpLatency;
 }
@@ -80,12 +80,12 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitDiv(HDiv* instr) {
-  Primitive::Type type = instr->GetResultType();
+  DataType::Type type = instr->GetResultType();
   switch (type) {
-    case Primitive::kPrimFloat:
+    case DataType::Type::kFloat32:
       last_visited_latency_ = kArm64DivFloatLatency;
       break;
-    case Primitive::kPrimDouble:
+    case DataType::Type::kFloat64:
       last_visited_latency_ = kArm64DivDoubleLatency;
       break;
     default:
@@ -133,7 +133,7 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitMul(HMul* instr) {
-  last_visited_latency_ = Primitive::IsFloatingPointType(instr->GetResultType())
+  last_visited_latency_ = DataType::IsFloatingPointType(instr->GetResultType())
       ? kArm64MulFloatingPointLatency
       : kArm64MulIntegerLatency;
 }
@@ -153,7 +153,7 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitRem(HRem* instruction) {
-  if (Primitive::IsFloatingPointType(instruction->GetResultType())) {
+  if (DataType::IsFloatingPointType(instruction->GetResultType())) {
     last_visited_internal_latency_ = kArm64CallInternalLatency;
     last_visited_latency_ = kArm64CallLatency;
   } else {
@@ -194,8 +194,8 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitTypeConversion(HTypeConversion* instr) {
-  if (Primitive::IsFloatingPointType(instr->GetResultType()) ||
-      Primitive::IsFloatingPointType(instr->GetInputType())) {
+  if (DataType::IsFloatingPointType(instr->GetResultType()) ||
+      DataType::IsFloatingPointType(instr->GetInputType())) {
     last_visited_latency_ = kArm64TypeConversionFloatingPointIntegerLatency;
   } else {
     last_visited_latency_ = kArm64IntegerOpLatency;
@@ -203,7 +203,7 @@
 }
 
 void SchedulingLatencyVisitorARM64::HandleSimpleArithmeticSIMD(HVecOperation *instr) {
-  if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
+  if (DataType::IsFloatingPointType(instr->GetPackedType())) {
     last_visited_latency_ = kArm64SIMDFloatingPointOpLatency;
   } else {
     last_visited_latency_ = kArm64SIMDIntegerOpLatency;
@@ -236,7 +236,7 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitVecNot(HVecNot* instr) {
-  if (instr->GetPackedType() == Primitive::kPrimBoolean) {
+  if (instr->GetPackedType() == DataType::Type::kBool) {
     last_visited_internal_latency_ = kArm64SIMDIntegerOpLatency;
   }
   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
@@ -255,7 +255,7 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitVecMul(HVecMul* instr) {
-  if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
+  if (DataType::IsFloatingPointType(instr->GetPackedType())) {
     last_visited_latency_ = kArm64SIMDMulFloatingPointLatency;
   } else {
     last_visited_latency_ = kArm64SIMDMulIntegerLatency;
@@ -263,10 +263,10 @@
 }
 
 void SchedulingLatencyVisitorARM64::VisitVecDiv(HVecDiv* instr) {
-  if (instr->GetPackedType() == Primitive::kPrimFloat) {
+  if (instr->GetPackedType() == DataType::Type::kFloat32) {
     last_visited_latency_ = kArm64SIMDDivFloatLatency;
   } else {
-    DCHECK(instr->GetPackedType() == Primitive::kPrimDouble);
+    DCHECK(instr->GetPackedType() == DataType::Type::kFloat64);
     last_visited_latency_ = kArm64SIMDDivDoubleLatency;
   }
 }
@@ -327,9 +327,9 @@
 
 void SchedulingLatencyVisitorARM64::VisitVecLoad(HVecLoad* instr) {
   last_visited_internal_latency_ = 0;
-  size_t size = Primitive::ComponentSize(instr->GetPackedType());
+  size_t size = DataType::Size(instr->GetPackedType());
 
-  if (instr->GetPackedType() == Primitive::kPrimChar
+  if (instr->GetPackedType() == DataType::Type::kUint16
       && mirror::kUseStringCompression
       && instr->IsStringCharAt()) {
     // Set latencies for the uncompressed case.
@@ -344,7 +344,7 @@
 
 void SchedulingLatencyVisitorARM64::VisitVecStore(HVecStore* instr) {
   last_visited_internal_latency_ = 0;
-  size_t size = Primitive::ComponentSize(instr->GetPackedType());
+  size_t size = DataType::Size(instr->GetPackedType());
   HandleVecAddress(instr, size);
   last_visited_latency_ = kArm64SIMDMemoryStoreLatency;
 }
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index cdb6666..0e6e0c5 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -103,18 +103,20 @@
     HInstruction* array = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                             dex::TypeIndex(0),
                                                             0,
-                                                            Primitive::kPrimNot);
+                                                            DataType::Type::kReference);
     HInstruction* c1 = graph_->GetIntConstant(1);
     HInstruction* c2 = graph_->GetIntConstant(10);
-    HInstruction* add1 = new (&allocator_) HAdd(Primitive::kPrimInt, c1, c2);
-    HInstruction* add2 = new (&allocator_) HAdd(Primitive::kPrimInt, add1, c2);
-    HInstruction* mul = new (&allocator_) HMul(Primitive::kPrimInt, add1, add2);
+    HInstruction* add1 = new (&allocator_) HAdd(DataType::Type::kInt32, c1, c2);
+    HInstruction* add2 = new (&allocator_) HAdd(DataType::Type::kInt32, add1, c2);
+    HInstruction* mul = new (&allocator_) HMul(DataType::Type::kInt32, add1, add2);
     HInstruction* div_check = new (&allocator_) HDivZeroCheck(add2, 0);
-    HInstruction* div = new (&allocator_) HDiv(Primitive::kPrimInt, add1, div_check, 0);
-    HInstruction* array_get1 = new (&allocator_) HArrayGet(array, add1, Primitive::kPrimInt, 0);
-    HInstruction* array_set1 = new (&allocator_) HArraySet(array, add1, add2, Primitive::kPrimInt, 0);
-    HInstruction* array_get2 = new (&allocator_) HArrayGet(array, add1, Primitive::kPrimInt, 0);
-    HInstruction* array_set2 = new (&allocator_) HArraySet(array, add1, add2, Primitive::kPrimInt, 0);
+    HInstruction* div = new (&allocator_) HDiv(DataType::Type::kInt32, add1, div_check, 0);
+    HInstruction* array_get1 = new (&allocator_) HArrayGet(array, add1, DataType::Type::kInt32, 0);
+    HInstruction* array_set1 =
+        new (&allocator_) HArraySet(array, add1, add2, DataType::Type::kInt32, 0);
+    HInstruction* array_get2 = new (&allocator_) HArrayGet(array, add1, DataType::Type::kInt32, 0);
+    HInstruction* array_set2 =
+        new (&allocator_) HArraySet(array, add1, add2, DataType::Type::kInt32, 0);
 
     DCHECK(div_check->CanThrow());
 
@@ -204,37 +206,41 @@
     HInstruction* arr = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                           dex::TypeIndex(0),
                                                           0,
-                                                          Primitive::kPrimNot);
+                                                          DataType::Type::kReference);
     HInstruction* i = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                         dex::TypeIndex(1),
                                                         1,
-                                                        Primitive::kPrimInt);
+                                                        DataType::Type::kInt32);
     HInstruction* j = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                         dex::TypeIndex(1),
                                                         1,
-                                                        Primitive::kPrimInt);
+                                                        DataType::Type::kInt32);
     HInstruction* object = new (&allocator_) HParameterValue(graph_->GetDexFile(),
                                                              dex::TypeIndex(0),
                                                              0,
-                                                             Primitive::kPrimNot);
+                                                             DataType::Type::kReference);
     HInstruction* c0 = graph_->GetIntConstant(0);
     HInstruction* c1 = graph_->GetIntConstant(1);
-    HInstruction* add0 = new (&allocator_) HAdd(Primitive::kPrimInt, i, c0);
-    HInstruction* add1 = new (&allocator_) HAdd(Primitive::kPrimInt, i, c1);
-    HInstruction* sub0 = new (&allocator_) HSub(Primitive::kPrimInt, i, c0);
-    HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, i, c1);
-    HInstruction* arr_set_0 = new (&allocator_) HArraySet(arr, c0, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_1 = new (&allocator_) HArraySet(arr, c1, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_i = new (&allocator_) HArraySet(arr, i, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_add0 = new (&allocator_) HArraySet(arr, add0, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_add1 = new (&allocator_) HArraySet(arr, add1, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_sub0 = new (&allocator_) HArraySet(arr, sub0, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_sub1 = new (&allocator_) HArraySet(arr, sub1, c0, Primitive::kPrimInt, 0);
-    HInstruction* arr_set_j = new (&allocator_) HArraySet(arr, j, c0, Primitive::kPrimInt, 0);
+    HInstruction* add0 = new (&allocator_) HAdd(DataType::Type::kInt32, i, c0);
+    HInstruction* add1 = new (&allocator_) HAdd(DataType::Type::kInt32, i, c1);
+    HInstruction* sub0 = new (&allocator_) HSub(DataType::Type::kInt32, i, c0);
+    HInstruction* sub1 = new (&allocator_) HSub(DataType::Type::kInt32, i, c1);
+    HInstruction* arr_set_0 = new (&allocator_) HArraySet(arr, c0, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_1 = new (&allocator_) HArraySet(arr, c1, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_i = new (&allocator_) HArraySet(arr, i, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_add0 =
+        new (&allocator_) HArraySet(arr, add0, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_add1 =
+        new (&allocator_) HArraySet(arr, add1, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_sub0 =
+        new (&allocator_) HArraySet(arr, sub0, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_sub1 =
+        new (&allocator_) HArraySet(arr, sub1, c0, DataType::Type::kInt32, 0);
+    HInstruction* arr_set_j = new (&allocator_) HArraySet(arr, j, c0, DataType::Type::kInt32, 0);
     HInstanceFieldSet* set_field10 = new (&allocator_) HInstanceFieldSet(object,
                                                                          c1,
                                                                          nullptr,
-                                                                         Primitive::kPrimInt,
+                                                                         DataType::Type::kInt32,
                                                                          MemberOffset(10),
                                                                          false,
                                                                          kUnknownFieldIndex,
diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc
index e220d32..827b591 100644
--- a/compiler/optimizing/select_generator.cc
+++ b/compiler/optimizing/select_generator.cc
@@ -140,11 +140,11 @@
                                                        false_value,
                                                        if_instruction->GetDexPc());
     if (both_successors_return) {
-      if (true_value->GetType() == Primitive::kPrimNot) {
-        DCHECK(false_value->GetType() == Primitive::kPrimNot);
+      if (true_value->GetType() == DataType::Type::kReference) {
+        DCHECK(false_value->GetType() == DataType::Type::kReference);
         ReferenceTypePropagation::FixUpInstructionType(select, handle_scope_);
       }
-    } else if (phi->GetType() == Primitive::kPrimNot) {
+    } else if (phi->GetType() == DataType::Type::kReference) {
       select->SetReferenceTypeInfo(phi->GetReferenceTypeInfo());
     }
     block->InsertInstructionBefore(select, if_instruction);
diff --git a/compiler/optimizing/side_effects_test.cc b/compiler/optimizing/side_effects_test.cc
index b01bc1c..ac5eb15 100644
--- a/compiler/optimizing/side_effects_test.cc
+++ b/compiler/optimizing/side_effects_test.cc
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
+#include "data_type.h"
 #include "nodes.h"
-#include "primitive.h"
 
 namespace art {
 
@@ -89,18 +90,18 @@
 }
 
 TEST(SideEffectsTest, DependencesAndNoDependences) {
-  // Apply test to each individual primitive type.
-  for (Primitive::Type type = Primitive::kPrimNot;
-      type < Primitive::kPrimVoid;
-      type = Primitive::Type(type + 1)) {
-    // Same primitive type and access type: proper write/read dep.
+  // Apply test to each individual data type.
+  for (DataType::Type type = DataType::Type::kReference;
+       type < DataType::Type::kVoid;
+       type = static_cast<DataType::Type>(static_cast<uint8_t>(type) + 1u)) {
+    // Same data type and access type: proper write/read dep.
     testWriteAndReadDependence(
         SideEffects::FieldWriteOfType(type, false),
         SideEffects::FieldReadOfType(type, false));
     testWriteAndReadDependence(
         SideEffects::ArrayWriteOfType(type),
         SideEffects::ArrayReadOfType(type));
-    // Same primitive type but different access type: no write/read dep.
+    // Same data type but different access type: no write/read dep.
     testNoWriteAndReadDependence(
         SideEffects::FieldWriteOfType(type, false),
         SideEffects::ArrayReadOfType(type));
@@ -111,31 +112,31 @@
 }
 
 TEST(SideEffectsTest, NoDependences) {
-  // Different primitive type, same access type: no write/read dep.
+  // Different data type, same access type: no write/read dep.
   testNoWriteAndReadDependence(
-      SideEffects::FieldWriteOfType(Primitive::kPrimInt, false),
-      SideEffects::FieldReadOfType(Primitive::kPrimDouble, false));
+      SideEffects::FieldWriteOfType(DataType::Type::kInt32, false),
+      SideEffects::FieldReadOfType(DataType::Type::kFloat64, false));
   testNoWriteAndReadDependence(
-      SideEffects::ArrayWriteOfType(Primitive::kPrimInt),
-      SideEffects::ArrayReadOfType(Primitive::kPrimDouble));
+      SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat64));
   // Everything different: no write/read dep.
   testNoWriteAndReadDependence(
-      SideEffects::FieldWriteOfType(Primitive::kPrimInt, false),
-      SideEffects::ArrayReadOfType(Primitive::kPrimDouble));
+      SideEffects::FieldWriteOfType(DataType::Type::kInt32, false),
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat64));
   testNoWriteAndReadDependence(
-      SideEffects::ArrayWriteOfType(Primitive::kPrimInt),
-      SideEffects::FieldReadOfType(Primitive::kPrimDouble, false));
+      SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+      SideEffects::FieldReadOfType(DataType::Type::kFloat64, false));
 }
 
 TEST(SideEffectsTest, VolatileDependences) {
   SideEffects volatile_write =
-      SideEffects::FieldWriteOfType(Primitive::kPrimInt, /* is_volatile */ true);
+      SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ true);
   SideEffects any_write =
-      SideEffects::FieldWriteOfType(Primitive::kPrimInt, /* is_volatile */ false);
+      SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ false);
   SideEffects volatile_read =
-      SideEffects::FieldReadOfType(Primitive::kPrimByte, /* is_volatile */ true);
+      SideEffects::FieldReadOfType(DataType::Type::kInt8, /* is_volatile */ true);
   SideEffects any_read =
-      SideEffects::FieldReadOfType(Primitive::kPrimByte, /* is_volatile */ false);
+      SideEffects::FieldReadOfType(DataType::Type::kInt8, /* is_volatile */ false);
 
   EXPECT_FALSE(volatile_write.MayDependOn(any_read));
   EXPECT_TRUE(any_read.MayDependOn(volatile_write));
@@ -151,26 +152,26 @@
 TEST(SideEffectsTest, SameWidthTypesNoAlias) {
   // Type I/F.
   testNoWriteAndReadDependence(
-      SideEffects::FieldWriteOfType(Primitive::kPrimInt, /* is_volatile */ false),
-      SideEffects::FieldReadOfType(Primitive::kPrimFloat, /* is_volatile */ false));
+      SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ false),
+      SideEffects::FieldReadOfType(DataType::Type::kFloat32, /* is_volatile */ false));
   testNoWriteAndReadDependence(
-      SideEffects::ArrayWriteOfType(Primitive::kPrimInt),
-      SideEffects::ArrayReadOfType(Primitive::kPrimFloat));
+      SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat32));
   // Type L/D.
   testNoWriteAndReadDependence(
-      SideEffects::FieldWriteOfType(Primitive::kPrimLong, /* is_volatile */ false),
-      SideEffects::FieldReadOfType(Primitive::kPrimDouble, /* is_volatile */ false));
+      SideEffects::FieldWriteOfType(DataType::Type::kInt64, /* is_volatile */ false),
+      SideEffects::FieldReadOfType(DataType::Type::kFloat64, /* is_volatile */ false));
   testNoWriteAndReadDependence(
-      SideEffects::ArrayWriteOfType(Primitive::kPrimLong),
-      SideEffects::ArrayReadOfType(Primitive::kPrimDouble));
+      SideEffects::ArrayWriteOfType(DataType::Type::kInt64),
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat64));
 }
 
 TEST(SideEffectsTest, AllWritesAndReads) {
   SideEffects s = SideEffects::None();
   // Keep taking the union of different writes and reads.
-  for (Primitive::Type type = Primitive::kPrimNot;
-        type < Primitive::kPrimVoid;
-        type = Primitive::Type(type + 1)) {
+  for (DataType::Type type = DataType::Type::kReference;
+       type < DataType::Type::kVoid;
+       type = static_cast<DataType::Type>(static_cast<uint8_t>(type) + 1u)) {
     s = s.Union(SideEffects::FieldWriteOfType(type, /* is_volatile */ false));
     s = s.Union(SideEffects::ArrayWriteOfType(type));
     s = s.Union(SideEffects::FieldReadOfType(type, /* is_volatile */ false));
@@ -214,41 +215,41 @@
       SideEffects::AllReads().ToString().c_str());
   EXPECT_STREQ(
       "||||||L|",
-      SideEffects::FieldWriteOfType(Primitive::kPrimNot, false).ToString().c_str());
+      SideEffects::FieldWriteOfType(DataType::Type::kReference, false).ToString().c_str());
   EXPECT_STREQ(
       "||DFJISCBZL|DFJISCBZL||DFJISCBZL|DFJISCBZL|",
-      SideEffects::FieldWriteOfType(Primitive::kPrimNot, true).ToString().c_str());
+      SideEffects::FieldWriteOfType(DataType::Type::kReference, true).ToString().c_str());
   EXPECT_STREQ(
       "|||||Z||",
-      SideEffects::ArrayWriteOfType(Primitive::kPrimBoolean).ToString().c_str());
+      SideEffects::ArrayWriteOfType(DataType::Type::kBool).ToString().c_str());
   EXPECT_STREQ(
       "|||||C||",
-      SideEffects::ArrayWriteOfType(Primitive::kPrimChar).ToString().c_str());
+      SideEffects::ArrayWriteOfType(DataType::Type::kUint16).ToString().c_str());
   EXPECT_STREQ(
       "|||||S||",
-      SideEffects::ArrayWriteOfType(Primitive::kPrimShort).ToString().c_str());
+      SideEffects::ArrayWriteOfType(DataType::Type::kInt16).ToString().c_str());
   EXPECT_STREQ(
       "|||B||||",
-      SideEffects::FieldReadOfType(Primitive::kPrimByte, false).ToString().c_str());
+      SideEffects::FieldReadOfType(DataType::Type::kInt8, false).ToString().c_str());
   EXPECT_STREQ(
       "||D|||||",
-      SideEffects::ArrayReadOfType(Primitive::kPrimDouble).ToString().c_str());
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat64).ToString().c_str());
   EXPECT_STREQ(
       "||J|||||",
-      SideEffects::ArrayReadOfType(Primitive::kPrimLong).ToString().c_str());
+      SideEffects::ArrayReadOfType(DataType::Type::kInt64).ToString().c_str());
   EXPECT_STREQ(
       "||F|||||",
-      SideEffects::ArrayReadOfType(Primitive::kPrimFloat).ToString().c_str());
+      SideEffects::ArrayReadOfType(DataType::Type::kFloat32).ToString().c_str());
   EXPECT_STREQ(
       "||I|||||",
-      SideEffects::ArrayReadOfType(Primitive::kPrimInt).ToString().c_str());
+      SideEffects::ArrayReadOfType(DataType::Type::kInt32).ToString().c_str());
   SideEffects s = SideEffects::None();
-  s = s.Union(SideEffects::FieldWriteOfType(Primitive::kPrimChar, /* is_volatile */ false));
-  s = s.Union(SideEffects::FieldWriteOfType(Primitive::kPrimLong, /* is_volatile */ false));
-  s = s.Union(SideEffects::ArrayWriteOfType(Primitive::kPrimShort));
-  s = s.Union(SideEffects::FieldReadOfType(Primitive::kPrimInt, /* is_volatile */ false));
-  s = s.Union(SideEffects::ArrayReadOfType(Primitive::kPrimFloat));
-  s = s.Union(SideEffects::ArrayReadOfType(Primitive::kPrimDouble));
+  s = s.Union(SideEffects::FieldWriteOfType(DataType::Type::kUint16, /* is_volatile */ false));
+  s = s.Union(SideEffects::FieldWriteOfType(DataType::Type::kInt64, /* is_volatile */ false));
+  s = s.Union(SideEffects::ArrayWriteOfType(DataType::Type::kInt16));
+  s = s.Union(SideEffects::FieldReadOfType(DataType::Type::kInt32, /* is_volatile */ false));
+  s = s.Union(SideEffects::ArrayReadOfType(DataType::Type::kFloat32));
+  s = s.Union(SideEffects::ArrayReadOfType(DataType::Type::kFloat64));
   EXPECT_STREQ("||DF|I||S|JC|", s.ToString().c_str());
 }
 
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 50ab11b..77b7a22 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -17,6 +17,7 @@
 #include "ssa_builder.h"
 
 #include "bytecode_utils.h"
+#include "data_type-inl.h"
 #include "mirror/class-inl.h"
 #include "nodes.h"
 #include "reference_type_propagation.h"
@@ -37,10 +38,11 @@
       HInstruction* right = equality_instr->InputAt(1);
       HInstruction* int_operand = nullptr;
 
-      if ((left->GetType() == Primitive::kPrimNot) && (right->GetType() == Primitive::kPrimInt)) {
+      if ((left->GetType() == DataType::Type::kReference) &&
+          (right->GetType() == DataType::Type::kInt32)) {
         int_operand = right;
-      } else if ((right->GetType() == Primitive::kPrimNot)
-                 && (left->GetType() == Primitive::kPrimInt)) {
+      } else if ((right->GetType() == DataType::Type::kReference) &&
+                 (left->GetType() == DataType::Type::kInt32)) {
         int_operand = left;
       } else {
         continue;
@@ -122,7 +124,7 @@
 // Find a candidate primitive type for `phi` by merging the type of its inputs.
 // Return false if conflict is identified.
 static bool TypePhiFromInputs(HPhi* phi) {
-  Primitive::Type common_type = phi->GetType();
+  DataType::Type common_type = phi->GetType();
 
   for (HInstruction* input : phi->GetInputs()) {
     if (input->IsPhi() && input->AsPhi()->IsDead()) {
@@ -131,26 +133,29 @@
       return false;
     }
 
-    Primitive::Type input_type = HPhi::ToPhiType(input->GetType());
+    DataType::Type input_type = HPhi::ToPhiType(input->GetType());
     if (common_type == input_type) {
       // No change in type.
-    } else if (Primitive::Is64BitType(common_type) != Primitive::Is64BitType(input_type)) {
+    } else if (DataType::Is64BitType(common_type) != DataType::Is64BitType(input_type)) {
       // Types are of different sizes, e.g. int vs. long. Must be a conflict.
       return false;
-    } else if (Primitive::IsIntegralType(common_type)) {
+    } else if (DataType::IsIntegralType(common_type)) {
       // Previous inputs were integral, this one is not but is of the same size.
       // This does not imply conflict since some bytecode instruction types are
       // ambiguous. TypeInputsOfPhi will either type them or detect a conflict.
-      DCHECK(Primitive::IsFloatingPointType(input_type) || input_type == Primitive::kPrimNot);
+      DCHECK(DataType::IsFloatingPointType(input_type) ||
+             input_type == DataType::Type::kReference);
       common_type = input_type;
-    } else if (Primitive::IsIntegralType(input_type)) {
+    } else if (DataType::IsIntegralType(input_type)) {
       // Input is integral, common type is not. Same as in the previous case, if
       // there is a conflict, it will be detected during TypeInputsOfPhi.
-      DCHECK(Primitive::IsFloatingPointType(common_type) || common_type == Primitive::kPrimNot);
+      DCHECK(DataType::IsFloatingPointType(common_type) ||
+             common_type == DataType::Type::kReference);
     } else {
       // Combining float and reference types. Clearly a conflict.
-      DCHECK((common_type == Primitive::kPrimFloat && input_type == Primitive::kPrimNot) ||
-             (common_type == Primitive::kPrimNot && input_type == Primitive::kPrimFloat));
+      DCHECK(
+          (common_type == DataType::Type::kFloat32 && input_type == DataType::Type::kReference) ||
+          (common_type == DataType::Type::kReference && input_type == DataType::Type::kFloat32));
       return false;
     }
   }
@@ -163,8 +168,8 @@
 
 // Replace inputs of `phi` to match its type. Return false if conflict is identified.
 bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist) {
-  Primitive::Type common_type = phi->GetType();
-  if (Primitive::IsIntegralType(common_type)) {
+  DataType::Type common_type = phi->GetType();
+  if (DataType::IsIntegralType(common_type)) {
     // We do not need to retype ambiguous inputs because they are always constructed
     // with the integral type candidate.
     if (kIsDebugBuild) {
@@ -175,14 +180,15 @@
     // Inputs did not need to be replaced, hence no conflict. Report success.
     return true;
   } else {
-    DCHECK(common_type == Primitive::kPrimNot || Primitive::IsFloatingPointType(common_type));
+    DCHECK(common_type == DataType::Type::kReference ||
+           DataType::IsFloatingPointType(common_type));
     HInputsRef inputs = phi->GetInputs();
     for (size_t i = 0; i < inputs.size(); ++i) {
       HInstruction* input = inputs[i];
       if (input->GetType() != common_type) {
         // Input type does not match phi's type. Try to retype the input or
         // generate a suitably typed equivalent.
-        HInstruction* equivalent = (common_type == Primitive::kPrimNot)
+        HInstruction* equivalent = (common_type == DataType::Type::kReference)
             ? GetReferenceTypeEquivalent(input)
             : GetFloatOrDoubleEquivalent(input, common_type);
         if (equivalent == nullptr) {
@@ -209,7 +215,7 @@
 // it was changed by the algorithm or not.
 bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist) {
   DCHECK(phi->IsLive());
-  Primitive::Type original_type = phi->GetType();
+  DataType::Type original_type = phi->GetType();
 
   // Try to type the phi in two stages:
   // (1) find a candidate type for the phi by merging types of all its inputs,
@@ -270,8 +276,8 @@
 }
 
 static HArrayGet* FindFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
-  Primitive::Type type = aget->GetType();
-  DCHECK(Primitive::IsIntOrLongType(type));
+  DataType::Type type = aget->GetType();
+  DCHECK(DataType::IsIntOrLongType(type));
   HInstruction* next = aget->GetNext();
   if (next != nullptr && next->IsArrayGet()) {
     HArrayGet* next_aget = next->AsArrayGet();
@@ -283,24 +289,25 @@
 }
 
 static HArrayGet* CreateFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
-  Primitive::Type type = aget->GetType();
-  DCHECK(Primitive::IsIntOrLongType(type));
+  DataType::Type type = aget->GetType();
+  DCHECK(DataType::IsIntOrLongType(type));
   DCHECK(FindFloatOrDoubleEquivalentOfArrayGet(aget) == nullptr);
 
   HArrayGet* equivalent = new (aget->GetBlock()->GetGraph()->GetArena()) HArrayGet(
       aget->GetArray(),
       aget->GetIndex(),
-      type == Primitive::kPrimInt ? Primitive::kPrimFloat : Primitive::kPrimDouble,
+      type == DataType::Type::kInt32 ? DataType::Type::kFloat32 : DataType::Type::kFloat64,
       aget->GetDexPc());
   aget->GetBlock()->InsertInstructionAfter(equivalent, aget);
   return equivalent;
 }
 
-static Primitive::Type GetPrimitiveArrayComponentType(HInstruction* array)
+static DataType::Type GetPrimitiveArrayComponentType(HInstruction* array)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ReferenceTypeInfo array_type = array->GetReferenceTypeInfo();
   DCHECK(array_type.IsPrimitiveArrayClass());
-  return array_type.GetTypeHandle()->GetComponentType()->GetPrimitiveType();
+  return DataTypeFromPrimitive(
+      array_type.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
 }
 
 bool SsaBuilder::FixAmbiguousArrayOps() {
@@ -325,10 +332,10 @@
       }
 
       HArrayGet* aget_float = FindFloatOrDoubleEquivalentOfArrayGet(aget_int);
-      Primitive::Type array_type = GetPrimitiveArrayComponentType(array);
-      DCHECK_EQ(Primitive::Is64BitType(aget_int->GetType()), Primitive::Is64BitType(array_type));
+      DataType::Type array_type = GetPrimitiveArrayComponentType(array);
+      DCHECK_EQ(DataType::Is64BitType(aget_int->GetType()), DataType::Is64BitType(array_type));
 
-      if (Primitive::IsIntOrLongType(array_type)) {
+      if (DataType::IsIntOrLongType(array_type)) {
         if (aget_float != nullptr) {
           // There is a float/double equivalent. We must replace it and re-run
           // primitive type propagation on all dependent instructions.
@@ -337,7 +344,7 @@
           AddDependentInstructionsToWorklist(aget_int, &worklist);
         }
       } else {
-        DCHECK(Primitive::IsFloatingPointType(array_type));
+        DCHECK(DataType::IsFloatingPointType(array_type));
         if (aget_float == nullptr) {
           // This is a float/double ArrayGet but there were no typed uses which
           // would create the typed equivalent. Create it now.
@@ -365,13 +372,13 @@
       }
 
       HInstruction* value = aset->GetValue();
-      Primitive::Type value_type = value->GetType();
-      Primitive::Type array_type = GetPrimitiveArrayComponentType(array);
-      DCHECK_EQ(Primitive::Is64BitType(value_type), Primitive::Is64BitType(array_type));
+      DataType::Type value_type = value->GetType();
+      DataType::Type array_type = GetPrimitiveArrayComponentType(array);
+      DCHECK_EQ(DataType::Is64BitType(value_type), DataType::Is64BitType(array_type));
 
-      if (Primitive::IsFloatingPointType(array_type)) {
-        if (!Primitive::IsFloatingPointType(value_type)) {
-          DCHECK(Primitive::IsIntegralType(value_type));
+      if (DataType::IsFloatingPointType(array_type)) {
+        if (!DataType::IsFloatingPointType(value_type)) {
+          DCHECK(DataType::IsIntegralType(value_type));
           // Array elements are floating-point but the value has not been replaced
           // with its floating-point equivalent. The replacement must always
           // succeed in code validated by the verifier.
@@ -390,8 +397,8 @@
       } else {
         // Array elements are integral and the value assigned to it initially
         // was integral too. Nothing to do.
-        DCHECK(Primitive::IsIntegralType(array_type));
-        DCHECK(Primitive::IsIntegralType(value_type));
+        DCHECK(DataType::IsIntegralType(array_type));
+        DCHECK(DataType::IsIntegralType(value_type));
       }
     }
   }
@@ -599,7 +606,7 @@
  * floating point registers and core registers), we need to create a copy of the
  * phi with a floating point / reference type.
  */
-HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, DataType::Type type) {
   DCHECK(phi->IsLive()) << "Cannot get equivalent of a dead phi since it would create a live one.";
 
   // We place the floating point /reference phi next to this phi.
@@ -637,9 +644,9 @@
 }
 
 HArrayGet* SsaBuilder::GetFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
-  DCHECK(Primitive::IsIntegralType(aget->GetType()));
+  DCHECK(DataType::IsIntegralType(aget->GetType()));
 
-  if (!Primitive::IsIntOrLongType(aget->GetType())) {
+  if (!DataType::IsIntOrLongType(aget->GetType())) {
     // Cannot type boolean, char, byte, short to float/double.
     return nullptr;
   }
@@ -650,7 +657,7 @@
     // int/long. Requesting a float/double equivalent should lead to a conflict.
     if (kIsDebugBuild) {
       ScopedObjectAccess soa(Thread::Current());
-      DCHECK(Primitive::IsIntOrLongType(GetPrimitiveArrayComponentType(aget->GetArray())));
+      DCHECK(DataType::IsIntOrLongType(GetPrimitiveArrayComponentType(aget->GetArray())));
     }
     return nullptr;
   } else {
@@ -661,7 +668,7 @@
   }
 }
 
-HInstruction* SsaBuilder::GetFloatOrDoubleEquivalent(HInstruction* value, Primitive::Type type) {
+HInstruction* SsaBuilder::GetFloatOrDoubleEquivalent(HInstruction* value, DataType::Type type) {
   if (value->IsArrayGet()) {
     return GetFloatOrDoubleEquivalentOfArrayGet(value->AsArrayGet());
   } else if (value->IsLongConstant()) {
@@ -679,7 +686,7 @@
   if (value->IsIntConstant() && value->AsIntConstant()->GetValue() == 0) {
     return graph_->GetNullConstant();
   } else if (value->IsPhi()) {
-    return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), Primitive::kPrimNot);
+    return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), DataType::Type::kReference);
   } else {
     return nullptr;
   }
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 978f113..1819ee5 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -64,20 +64,20 @@
 
   GraphAnalysisResult BuildSsa();
 
-  HInstruction* GetFloatOrDoubleEquivalent(HInstruction* instruction, Primitive::Type type);
+  HInstruction* GetFloatOrDoubleEquivalent(HInstruction* instruction, DataType::Type type);
   HInstruction* GetReferenceTypeEquivalent(HInstruction* instruction);
 
   void MaybeAddAmbiguousArrayGet(HArrayGet* aget) {
-    Primitive::Type type = aget->GetType();
-    DCHECK(!Primitive::IsFloatingPointType(type));
-    if (Primitive::IsIntOrLongType(type)) {
+    DataType::Type type = aget->GetType();
+    DCHECK(!DataType::IsFloatingPointType(type));
+    if (DataType::IsIntOrLongType(type)) {
       ambiguous_agets_.push_back(aget);
     }
   }
 
   void MaybeAddAmbiguousArraySet(HArraySet* aset) {
-    Primitive::Type type = aset->GetValue()->GetType();
-    if (Primitive::IsIntOrLongType(type)) {
+    DataType::Type type = aset->GetValue()->GetType();
+    if (DataType::IsIntOrLongType(type)) {
       ambiguous_asets_.push_back(aset);
     }
   }
@@ -111,7 +111,7 @@
 
   HFloatConstant* GetFloatEquivalent(HIntConstant* constant);
   HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant);
-  HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type);
+  HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, DataType::Type type);
   HArrayGet* GetFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget);
 
   void RemoveRedundantUninitializedStrings();
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 185303b..f1f1be2 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -474,11 +474,13 @@
   // For a SIMD operation, compute the number of needed spill slots.
   // TODO: do through vector type?
   HInstruction* definition = GetParent()->GetDefinedBy();
-  if (definition != nullptr && definition->IsVecOperation()) {
+  if (definition != nullptr &&
+      definition->IsVecOperation() &&
+      !definition->IsVecExtractScalar()) {
     return definition->AsVecOperation()->GetVectorNumberOfBytes() / kVRegSize;
   }
   // Return number of needed spill slots based on type.
-  return (type_ == Primitive::kPrimLong || type_ == Primitive::kPrimDouble) ? 2 : 1;
+  return (type_ == DataType::Type::kInt64 || type_ == DataType::Type::kFloat64) ? 2 : 1;
 }
 
 Location LiveInterval::ToLocation() const {
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index a668157..ec4ab31 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -262,16 +262,16 @@
 class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
  public:
   static LiveInterval* MakeInterval(ArenaAllocator* allocator,
-                                    Primitive::Type type,
+                                    DataType::Type type,
                                     HInstruction* instruction = nullptr) {
     return new (allocator) LiveInterval(allocator, type, instruction);
   }
 
-  static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) {
+  static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, DataType::Type type) {
     return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
   }
 
-  static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) {
+  static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, DataType::Type type) {
     return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true);
   }
 
@@ -608,7 +608,7 @@
     return parent_->env_uses_;
   }
 
-  Primitive::Type GetType() const {
+  DataType::Type GetType() const {
     return type_;
   }
 
@@ -783,7 +783,7 @@
   size_t NumberOfSpillSlotsNeeded() const;
 
   bool IsFloatingPoint() const {
-    return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
+    return type_ == DataType::Type::kFloat32 || type_ == DataType::Type::kFloat64;
   }
 
   // Converts the location of the interval to a `Location` object.
@@ -970,7 +970,7 @@
 
  private:
   LiveInterval(ArenaAllocator* allocator,
-               Primitive::Type type,
+               DataType::Type type,
                HInstruction* defined_by = nullptr,
                bool is_fixed = false,
                int reg = kNoRegister,
@@ -1102,7 +1102,7 @@
   EnvUsePositionList env_uses_;
 
   // The instruction type this interval corresponds to.
-  const Primitive::Type type_;
+  const DataType::Type type_;
 
   // Live interval that is the result of a split.
   LiveInterval* next_sibling_;
@@ -1262,7 +1262,7 @@
     // the exception handler to its location at the top of the catch block.
     if (env_holder->CanThrowIntoCatchBlock()) return true;
     if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true;
-    return instruction->GetType() == Primitive::kPrimNot;
+    return instruction->GetType() == DataType::Type::kReference;
   }
 
   void CheckNoLiveInIrreducibleLoop(const HBasicBlock& block) const {
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index b46060a..e89bf6d 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -70,7 +70,7 @@
 
 TEST_F(SsaLivenessAnalysisTest, TestReturnArg) {
   HInstruction* arg = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
   entry_->AddInstruction(arg);
 
   HBasicBlock* block = CreateSuccessor(entry_);
@@ -90,15 +90,15 @@
 
 TEST_F(SsaLivenessAnalysisTest, TestAput) {
   HInstruction* array = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* index = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
   HInstruction* value = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(2), 2, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(2), 2, DataType::Type::kInt32);
   HInstruction* extra_arg1 = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(3), 3, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32);
   HInstruction* extra_arg2 = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(4), 4, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference);
   ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 },
                                   allocator_.Adapter());
   for (HInstruction* insn : args) {
@@ -127,7 +127,7 @@
   bounds_check_env->CopyFrom(args);
   bounds_check->SetRawEnvironment(bounds_check_env);
   HInstruction* array_set =
-      new (&allocator_) HArraySet(array, index, value, Primitive::kPrimInt, /* dex_pc */ 0);
+      new (&allocator_) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0);
   block->AddInstruction(array_set);
 
   graph_->BuildDominatorTree();
@@ -160,15 +160,15 @@
 
 TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) {
   HInstruction* array = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
   HInstruction* index = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
   HInstruction* value = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(2), 2, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(2), 2, DataType::Type::kInt32);
   HInstruction* extra_arg1 = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(3), 3, Primitive::kPrimInt);
+      graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32);
   HInstruction* extra_arg2 = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), dex::TypeIndex(4), 4, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference);
   ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 },
                                   allocator_.Adapter());
   for (HInstruction* insn : args) {
@@ -201,7 +201,7 @@
   deoptimize_env->CopyFrom(args);
   deoptimize->SetRawEnvironment(deoptimize_env);
   HInstruction* array_set =
-      new (&allocator_) HArraySet(array, index, value, Primitive::kPrimInt, /* dex_pc */ 0);
+      new (&allocator_) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0);
   block->AddInstruction(array_set);
 
   graph_->BuildDominatorTree();
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index f69f417..ac998db 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -89,7 +89,7 @@
   // Test that phis had their type set.
   for (HBasicBlock* block : graph->GetBlocks()) {
     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      ASSERT_NE(it.Current()->GetType(), Primitive::kPrimVoid);
+      ASSERT_NE(it.Current()->GetType(), DataType::Type::kVoid);
     }
   }
 
diff --git a/compiler/optimizing/x86_memory_gen.cc b/compiler/optimizing/x86_memory_gen.cc
index 4e25683..0271850 100644
--- a/compiler/optimizing/x86_memory_gen.cc
+++ b/compiler/optimizing/x86_memory_gen.cc
@@ -41,7 +41,7 @@
     }
 
     HInstruction* array = array_len->InputAt(0);
-    DCHECK_EQ(array->GetType(), Primitive::kPrimNot);
+    DCHECK_EQ(array->GetType(), DataType::Type::kReference);
 
     // Don't apply this optimization when the array is nullptr.
     if (array->IsConstant() || (array->IsNullCheck() && array->InputAt(0)->IsConstant())) {
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 12954a4..227954e 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -114,6 +114,24 @@
         fmt);
   }
 
+  std::string Repeatww(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
+    return RepeatTemplatedRegisters<Reg, Reg>(f,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
+        fmt);
+  }
+
+  std::string Repeatbb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
+    return RepeatTemplatedRegisters<Reg, Reg>(f,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
+        fmt);
+  }
+
   std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
     return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
         GetRegisters(),
@@ -147,10 +165,18 @@
     return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
   }
 
-  std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
+  std::string RepeatrI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
     return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
   }
 
+  std::string RepeatwI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
+    return RepeatRegisterImm<RegisterView::kUseTertiaryName>(f, imm_bytes, fmt);
+  }
+
+  std::string RepeatbI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
+    return RepeatRegisterImm<RegisterView::kUseQuaternaryName>(f, imm_bytes, fmt);
+  }
+
   template <typename Reg1, typename Reg2, typename ImmType>
   std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
                                               int imm_bits,
@@ -909,6 +935,63 @@
         fmt);
   }
 
+  // Repeats over secondary registers and addresses provided by fixture.
+  std::string RepeatrA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
+    return RepeatrA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatrA(void (Ass::*f)(Reg, const Addr&),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedRegMem<Reg, Addr>(
+        f,
+        GetRegisters(),
+        a,
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        &AssemblerTest::GetAddrName,
+        fmt);
+  }
+
+  // Repeats over tertiary registers and addresses provided by fixture.
+  std::string RepeatwA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
+    return RepeatwA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatwA(void (Ass::*f)(Reg, const Addr&),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedRegMem<Reg, Addr>(
+        f,
+        GetRegisters(),
+        a,
+        &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
+        &AssemblerTest::GetAddrName,
+        fmt);
+  }
+
+  // Repeats over quaternary registers and addresses provided by fixture.
+  std::string RepeatbA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
+    return RepeatbA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatbA(void (Ass::*f)(Reg, const Addr&),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedRegMem<Reg, Addr>(
+        f,
+        GetRegisters(),
+        a,
+        &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
+        &AssemblerTest::GetAddrName,
+        fmt);
+  }
+
   // Repeats over fp-registers and addresses provided by fixture.
   std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), const std::string& fmt) {
     return RepeatFA(f, GetAddresses(), fmt);
@@ -947,6 +1030,63 @@
         fmt);
   }
 
+  // Repeats over addresses and secondary registers provided by fixture.
+  std::string RepeatAr(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
+    return RepeatAr(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAr(void (Ass::*f)(const Addr&, Reg),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemReg<Addr, Reg>(
+        f,
+        a,
+        GetRegisters(),
+        &AssemblerTest::GetAddrName,
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        fmt);
+  }
+
+  // Repeats over addresses and tertiary registers provided by fixture.
+  std::string RepeatAw(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
+    return RepeatAw(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAw(void (Ass::*f)(const Addr&, Reg),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemReg<Addr, Reg>(
+        f,
+        a,
+        GetRegisters(),
+        &AssemblerTest::GetAddrName,
+        &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
+        fmt);
+  }
+
+  // Repeats over addresses and quaternary registers provided by fixture.
+  std::string RepeatAb(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
+    return RepeatAb(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAb(void (Ass::*f)(const Addr&, Reg),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemReg<Addr, Reg>(
+        f,
+        a,
+        GetRegisters(),
+        &AssemblerTest::GetAddrName,
+        &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
+        fmt);
+  }
+
   // Repeats over addresses and fp-registers provided by fixture.
   std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), const std::string& fmt) {
     return RepeatAF(f, GetAddresses(), fmt);
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 3162a32..9fcede5 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -35,25 +35,25 @@
 std::ostream& operator<<(std::ostream& os, const Address& addr) {
   switch (addr.mod()) {
     case 0:
-      if (addr.rm() == ESP && addr.index() != ESP) {
-        return os << "(%" << addr.base() << ",%"
-                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      if (addr.rm() != ESP || addr.index() == ESP) {
+        return os << "(%" << addr.rm() << ")";
+      } else if (addr.base() == EBP) {
+        return os << static_cast<int>(addr.disp32()) << "(,%" << addr.index()
+                  << "," << (1 << addr.scale()) << ")";
       }
-      return os << "(%" << addr.rm() << ")";
+      return os << "(%" << addr.base() << ",%" << addr.index() << "," << (1 << addr.scale()) << ")";
     case 1:
-      if (addr.rm() == ESP && addr.index() != ESP) {
-        return os << static_cast<int>(addr.disp8())
-                  << "(%" << addr.base() << ",%"
-                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      if (addr.rm() != ESP || addr.index() == ESP) {
+        return os << static_cast<int>(addr.disp8()) << "(%" << addr.rm() << ")";
       }
-      return os << static_cast<int>(addr.disp8()) << "(%" << addr.rm() << ")";
+      return os << static_cast<int>(addr.disp8()) << "(%" << addr.base() << ",%"
+                << addr.index() << "," << (1 << addr.scale()) << ")";
     case 2:
-      if (addr.rm() == ESP && addr.index() != ESP) {
-        return os << static_cast<int>(addr.disp32())
-                  << "(%" << addr.base() << ",%"
-                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      if (addr.rm() != ESP || addr.index() == ESP) {
+        return os << static_cast<int>(addr.disp32()) << "(%" << addr.rm() << ")";
       }
-      return os << static_cast<int>(addr.disp32()) << "(%" << addr.rm() << ")";
+      return os << static_cast<int>(addr.disp32()) << "(%" << addr.base() << ",%"
+                << addr.index() << "," << (1 << addr.scale()) << ")";
     default:
       return os << "<address?>";
   }
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index c28ed3b..cccde37 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -148,21 +148,14 @@
 };
 
 //
-// Test repeat drivers used in the tests.
+// Test some repeat drivers used in the tests.
 //
 
 TEST_F(AssemblerX86Test, RepeatRR) {
-  EXPECT_EQ("%eax %eax\n%eax %ebx\n%eax %ecx\n%eax %edx\n%eax %ebp\n%eax %esp\n%eax %esi\n"
-            "%eax %edi\n%ebx %eax\n%ebx %ebx\n%ebx %ecx\n%ebx %edx\n%ebx %ebp\n%ebx %esp\n"
-            "%ebx %esi\n%ebx %edi\n%ecx %eax\n%ecx %ebx\n%ecx %ecx\n%ecx %edx\n%ecx %ebp\n"
-            "%ecx %esp\n%ecx %esi\n%ecx %edi\n%edx %eax\n%edx %ebx\n%edx %ecx\n%edx %edx\n"
-            "%edx %ebp\n%edx %esp\n%edx %esi\n%edx %edi\n%ebp %eax\n%ebp %ebx\n%ebp %ecx\n"
-            "%ebp %edx\n%ebp %ebp\n%ebp %esp\n%ebp %esi\n%ebp %edi\n%esp %eax\n%esp %ebx\n"
-            "%esp %ecx\n%esp %edx\n%esp %ebp\n%esp %esp\n%esp %esi\n%esp %edi\n%esi %eax\n"
-            "%esi %ebx\n%esi %ecx\n%esi %edx\n%esi %ebp\n%esi %esp\n%esi %esi\n%esi %edi\n"
-            "%edi %eax\n%edi %ebx\n%edi %ecx\n%edi %edx\n%edi %ebp\n%edi %esp\n%edi %esi\n"
-            "%edi %edi\n",
-            RepeatRR(/*f*/ nullptr, "%{reg1} %{reg2}"));
+  EXPECT_NE(RepeatRR(/*f*/ nullptr, "%{reg1} %{reg2}")
+            .find("%eax %eax\n%eax %ebx\n%eax %ecx\n%eax %edx\n%eax %ebp\n%eax %esp\n%eax %esi\n"
+                  "%eax %edi\n%ebx %eax\n%ebx %ebx\n%ebx %ecx\n%ebx %edx\n%ebx %ebp\n%ebx %esp\n"),
+            std::string::npos);
 }
 
 TEST_F(AssemblerX86Test, RepeatRI) {
@@ -173,18 +166,10 @@
 }
 
 TEST_F(AssemblerX86Test, RepeatFF) {
-  EXPECT_EQ("%XMM0 %XMM0\n%XMM0 %XMM1\n%XMM0 %XMM2\n%XMM0 %XMM3\n%XMM0 %XMM4\n%XMM0 %XMM5\n"
-            "%XMM0 %XMM6\n%XMM0 %XMM7\n%XMM1 %XMM0\n%XMM1 %XMM1\n%XMM1 %XMM2\n%XMM1 %XMM3\n"
-            "%XMM1 %XMM4\n%XMM1 %XMM5\n%XMM1 %XMM6\n%XMM1 %XMM7\n%XMM2 %XMM0\n%XMM2 %XMM1\n"
-            "%XMM2 %XMM2\n%XMM2 %XMM3\n%XMM2 %XMM4\n%XMM2 %XMM5\n%XMM2 %XMM6\n%XMM2 %XMM7\n"
-            "%XMM3 %XMM0\n%XMM3 %XMM1\n%XMM3 %XMM2\n%XMM3 %XMM3\n%XMM3 %XMM4\n%XMM3 %XMM5\n"
-            "%XMM3 %XMM6\n%XMM3 %XMM7\n%XMM4 %XMM0\n%XMM4 %XMM1\n%XMM4 %XMM2\n%XMM4 %XMM3\n"
-            "%XMM4 %XMM4\n%XMM4 %XMM5\n%XMM4 %XMM6\n%XMM4 %XMM7\n%XMM5 %XMM0\n%XMM5 %XMM1\n"
-            "%XMM5 %XMM2\n%XMM5 %XMM3\n%XMM5 %XMM4\n%XMM5 %XMM5\n%XMM5 %XMM6\n%XMM5 %XMM7\n"
-            "%XMM6 %XMM0\n%XMM6 %XMM1\n%XMM6 %XMM2\n%XMM6 %XMM3\n%XMM6 %XMM4\n%XMM6 %XMM5\n"
-            "%XMM6 %XMM6\n%XMM6 %XMM7\n%XMM7 %XMM0\n%XMM7 %XMM1\n%XMM7 %XMM2\n%XMM7 %XMM3\n"
-            "%XMM7 %XMM4\n%XMM7 %XMM5\n%XMM7 %XMM6\n%XMM7 %XMM7\n",
-            RepeatFF(/*f*/ nullptr, "%{reg1} %{reg2}"));
+  EXPECT_NE(RepeatFF(/*f*/ nullptr, "%{reg1} %{reg2}")
+            .find("%XMM0 %XMM0\n%XMM0 %XMM1\n%XMM0 %XMM2\n%XMM0 %XMM3\n%XMM0 %XMM4\n%XMM0 %XMM5\n"
+                  "%XMM0 %XMM6\n%XMM0 %XMM7\n%XMM1 %XMM0\n%XMM1 %XMM1\n%XMM1 %XMM2\n%XMM1 %XMM3\n"),
+            std::string::npos);
 }
 
 TEST_F(AssemblerX86Test, RepeatFFI) {
@@ -235,6 +220,36 @@
 // Actual x86 instruction assembler tests.
 //
 
+TEST_F(AssemblerX86Test, PoplAllAddresses) {
+  // Make sure all addressing modes combinations are tested at least once.
+  std::vector<x86::Address> all_addresses;
+  for (x86::Register* base : GetRegisters()) {
+    // Base only.
+    all_addresses.push_back(x86::Address(*base, -1));
+    all_addresses.push_back(x86::Address(*base, 0));
+    all_addresses.push_back(x86::Address(*base, 1));
+    all_addresses.push_back(x86::Address(*base, 123456789));
+    for (x86::Register* index : GetRegisters()) {
+      if (*index == x86::ESP) {
+        // Index cannot be ESP.
+        continue;
+      } else if (*base == *index) {
+       // Index only.
+       all_addresses.push_back(x86::Address(*index, x86::TIMES_1, -1));
+       all_addresses.push_back(x86::Address(*index, x86::TIMES_2, 0));
+       all_addresses.push_back(x86::Address(*index, x86::TIMES_4, 1));
+       all_addresses.push_back(x86::Address(*index, x86::TIMES_8, 123456789));
+      }
+      // Base and index.
+      all_addresses.push_back(x86::Address(*base, *index, x86::TIMES_1, -1));
+      all_addresses.push_back(x86::Address(*base, *index, x86::TIMES_2, 0));
+      all_addresses.push_back(x86::Address(*base, *index, x86::TIMES_4, 1));
+      all_addresses.push_back(x86::Address(*base, *index, x86::TIMES_8, 123456789));
+    }
+  }
+  DriverStr(RepeatA(&x86::X86Assembler::popl, all_addresses, "popl {mem}"), "popq");
+}
+
 TEST_F(AssemblerX86Test, Movl) {
   DriverStr(RepeatRR(&x86::X86Assembler::movl, "movl %{reg2}, %{reg1}"), "movl");
 }
@@ -370,7 +385,7 @@
 }
 
 TEST_F(AssemblerX86Test, RorlImm) {
-  DriverStr(RepeatRI(&x86::X86Assembler::rorl, 1U, "rorl ${imm}, %{reg}"), "rorli");
+  DriverStr(RepeatRI(&x86::X86Assembler::rorl, /*imm_bytes*/ 1U, "rorl ${imm}, %{reg}"), "rorli");
 }
 
 // Roll only allows CL as the shift count.
@@ -390,7 +405,7 @@
 }
 
 TEST_F(AssemblerX86Test, RollImm) {
-  DriverStr(RepeatRI(&x86::X86Assembler::roll, 1U, "roll ${imm}, %{reg}"), "rolli");
+  DriverStr(RepeatRI(&x86::X86Assembler::roll, /*imm_bytes*/ 1U, "roll ${imm}, %{reg}"), "rolli");
 }
 
 TEST_F(AssemblerX86Test, Cvtdq2ps) {
@@ -418,12 +433,12 @@
 }
 
 TEST_F(AssemblerX86Test, RoundSS) {
-  DriverStr(RepeatFFI(&x86::X86Assembler::roundss, 1U,
+  DriverStr(RepeatFFI(&x86::X86Assembler::roundss, /*imm_bytes*/ 1U,
                       "roundss ${imm}, %{reg2}, %{reg1}"), "roundss");
 }
 
 TEST_F(AssemblerX86Test, RoundSD) {
-  DriverStr(RepeatFFI(&x86::X86Assembler::roundsd, 1U,
+  DriverStr(RepeatFFI(&x86::X86Assembler::roundsd, /*imm_bytes*/ 1U,
                       "roundsd ${imm}, %{reg2}, %{reg1}"), "roundsd");
 }
 
@@ -896,7 +911,15 @@
 }
 
 TEST_F(AssemblerX86Test, Cmpb) {
-  DriverStr(RepeatAI(&x86::X86Assembler::cmpb, /*imm_bytes*/ 1U, "cmpb ${imm}, {mem}"), "cmpb");
+  DriverStr(RepeatAI(&x86::X86Assembler::cmpb,
+                     /*imm_bytes*/ 1U,
+                     "cmpb ${imm}, {mem}"), "cmpb");
+}
+
+TEST_F(AssemblerX86Test, Cmpw) {
+  DriverStr(RepeatAI(&x86::X86Assembler::cmpw,
+                     /*imm_bytes*/ 1U,
+                     "cmpw ${imm}, {mem}"), "cmpw");  // TODO: only imm8?
 }
 
 }  // namespace art
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 3bff67d..51f61ca 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -36,6 +36,34 @@
   return os << "ST" << static_cast<int>(reg);
 }
 
+std::ostream& operator<<(std::ostream& os, const Address& addr) {
+  switch (addr.mod()) {
+    case 0:
+      if (addr.rm() != RSP || addr.cpu_index().AsRegister() == RSP) {
+        return os << "(%" << addr.cpu_rm() << ")";
+      } else if (addr.base() == RBP) {
+        return os << static_cast<int>(addr.disp32()) << "(,%" << addr.cpu_index()
+                  << "," << (1 << addr.scale()) << ")";
+      }
+      return os << "(%" << addr.cpu_base() << ",%"
+                << addr.cpu_index() << "," << (1 << addr.scale()) << ")";
+    case 1:
+      if (addr.rm() != RSP || addr.cpu_index().AsRegister() == RSP) {
+        return os << static_cast<int>(addr.disp8()) << "(%" << addr.cpu_rm() << ")";
+      }
+      return os << static_cast<int>(addr.disp8()) << "(%" << addr.cpu_base() << ",%"
+                << addr.cpu_index() << "," << (1 << addr.scale()) << ")";
+    case 2:
+      if (addr.rm() != RSP || addr.cpu_index().AsRegister() == RSP) {
+        return os << static_cast<int>(addr.disp32()) << "(%" << addr.cpu_rm() << ")";
+      }
+      return os << static_cast<int>(addr.disp32()) << "(%" << addr.cpu_base() << ",%"
+                << addr.cpu_index() << "," << (1 << addr.scale()) << ")";
+    default:
+      return os << "<address?>";
+  }
+}
+
 void X86_64Assembler::call(CpuRegister reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(reg);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index fc0839b5a8..1130444 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -80,6 +80,21 @@
     return static_cast<Register>(encoding_at(1) & 7);
   }
 
+  CpuRegister cpu_rm() const {
+    int ext = (rex_ & 1) != 0 ? x86_64::R8 : x86_64::RAX;
+    return static_cast<CpuRegister>(rm() + ext);
+  }
+
+  CpuRegister cpu_index() const {
+    int ext = (rex_ & 2) != 0 ? x86_64::R8 : x86_64::RAX;
+    return static_cast<CpuRegister>(index() + ext);
+  }
+
+  CpuRegister cpu_base() const {
+    int ext = (rex_ & 1) != 0 ? x86_64::R8 : x86_64::RAX;
+    return static_cast<CpuRegister>(base() + ext);
+  }
+
   uint8_t rex() const {
     return rex_;
   }
@@ -268,6 +283,7 @@
   Address() {}
 };
 
+std::ostream& operator<<(std::ostream& os, const Address& addr);
 
 /**
  * Class to handle constant area values.
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 3e6110d..aff8871 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -153,6 +153,55 @@
   }
 
   void SetUpHelpers() OVERRIDE {
+    if (addresses_singleton_.size() == 0) {
+      // One addressing mode to test the repeat drivers.
+      addresses_singleton_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RAX),
+                          x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_1, -1));
+    }
+
+    if (addresses_.size() == 0) {
+      // Several addressing modes.
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
+                          x86_64::CpuRegister(x86_64::RAX), x86_64::TIMES_1, 15));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
+                          x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_2, 16));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
+                          x86_64::CpuRegister(x86_64::RCX), x86_64::TIMES_4, 17));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
+                          x86_64::CpuRegister(x86_64::RDX), x86_64::TIMES_8, 18));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), -1));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RBX), 0));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RSI), 1));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RDI), 987654321));
+      // Several addressing modes with the special ESP.
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RSP),
+                          x86_64::CpuRegister(x86_64::RAX), x86_64::TIMES_1, 15));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RSP),
+                          x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_2, 16));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RSP),
+                          x86_64::CpuRegister(x86_64::RCX), x86_64::TIMES_4, 17));
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::RSP),
+                          x86_64::CpuRegister(x86_64::RDX), x86_64::TIMES_8, 18));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), -1));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 0));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 1));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 987654321));
+      // Several addressing modes with the higher registers.
+      addresses_.push_back(
+          x86_64::Address(x86_64::CpuRegister(x86_64::R8),
+                          x86_64::CpuRegister(x86_64::R15), x86_64::TIMES_2, -1));
+      addresses_.push_back(x86_64::Address(x86_64::CpuRegister(x86_64::R15), 123456789));
+    }
+
     if (registers_.size() == 0) {
       registers_.push_back(new x86_64::CpuRegister(x86_64::RAX));
       registers_.push_back(new x86_64::CpuRegister(x86_64::RBX));
@@ -248,8 +297,7 @@
   }
 
   std::vector<x86_64::Address> GetAddresses() {
-    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
-    UNREACHABLE();
+    return addresses_;
   }
 
   std::vector<x86_64::CpuRegister*> GetRegisters() OVERRIDE {
@@ -279,29 +327,31 @@
     return quaternary_register_names_[reg];
   }
 
+  std::vector<x86_64::Address> addresses_singleton_;
+
  private:
+  std::vector<x86_64::Address> addresses_;
   std::vector<x86_64::CpuRegister*> registers_;
   std::map<x86_64::CpuRegister, std::string, X86_64CpuRegisterCompare> secondary_register_names_;
   std::map<x86_64::CpuRegister, std::string, X86_64CpuRegisterCompare> tertiary_register_names_;
   std::map<x86_64::CpuRegister, std::string, X86_64CpuRegisterCompare> quaternary_register_names_;
-
   std::vector<x86_64::XmmRegister*> fp_registers_;
 };
 
 //
-// Test repeat drivers used in the tests.
+// Test some repeat drivers used in the tests.
 //
 
 TEST_F(AssemblerX86_64Test, RepeatI4) {
-  EXPECT_EQ("%0\n%-1\n%18\n%4660\n%-4660\n%305419896\n%-305419896\n",
-            RepeatI(/*f*/ nullptr, /*imm_bytes*/ 4U, "%{imm}"));
+  EXPECT_EQ("$0\n$-1\n$18\n$4660\n$-4660\n$305419896\n$-305419896\n",
+            RepeatI(/*f*/ nullptr, /*imm_bytes*/ 4U, "${imm}"));
 }
 
 TEST_F(AssemblerX86_64Test, RepeatI8) {
-  EXPECT_EQ("%0\n%-1\n%18\n%4660\n%-4660\n%305419896\n%-305419896\n"
-            "%20015998343868\n%-20015998343868\n%1311768467463790320\n"
-            "%-1311768467463790320\n",
-            RepeatI(/*f*/ nullptr, /*imm_bytes*/ 8U, "%{imm}"));
+  EXPECT_EQ("$0\n$-1\n$18\n$4660\n$-4660\n$305419896\n$-305419896\n"
+            "$20015998343868\n$-20015998343868\n$1311768467463790320\n"
+            "$-1311768467463790320\n",
+            RepeatI(/*f*/ nullptr, /*imm_bytes*/ 8U, "${imm}"));
 }
 
 TEST_F(AssemblerX86_64Test, Repeatr) {
@@ -310,10 +360,10 @@
             Repeatr(/*f*/ nullptr, "%{reg}"));
 }
 
-TEST_F(AssemblerX86_64Test, Repeatri) {
-  EXPECT_NE(Repeatri(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} %{imm}").
-            find("%eax %0\n%eax %-1\n%eax %18\n%ebx %0\n%ebx %-1\n%ebx %18\n"
-                 "%ecx %0\n%ecx %-1\n%ecx %18\n%edx %0\n%edx %-1\n%edx %18\n"),
+TEST_F(AssemblerX86_64Test, RepeatrI) {
+  EXPECT_NE(RepeatrI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} ${imm}").
+            find("%eax $0\n%eax $-1\n%eax $18\n%ebx $0\n%ebx $-1\n%ebx $18\n"
+                 "%ecx $0\n%ecx $-1\n%ecx $18\n%edx $0\n%edx $-1\n%edx $18\n"),
             std::string::npos);
 }
 
@@ -334,10 +384,7 @@
 TEST_F(AssemblerX86_64Test, RepeatrF) {
   EXPECT_NE(RepeatrF(/*f*/ nullptr, "%{reg1} %{reg2}")
             .find("%eax %xmm0\n%eax %xmm1\n%eax %xmm2\n%eax %xmm3\n"
-                  "%eax %xmm4\n%eax %xmm5\n%eax %xmm6\n%eax %xmm7\n"
-                  "%eax %xmm8\n%eax %xmm9\n%eax %xmm10\n%eax %xmm11\n"
-                  "%eax %xmm12\n%eax %xmm13\n%eax %xmm14\n%eax %xmm15\n"
-                  "%ebx %xmm0\n%ebx %xmm1\n%ebx %xmm2\n%ebx %xmm3\n%ebx %xmm4\n"),
+                  "%eax %xmm4\n%eax %xmm5\n%eax %xmm6\n%eax %xmm7\n"),
             std::string::npos);
 }
 
@@ -348,59 +395,103 @@
 }
 
 TEST_F(AssemblerX86_64Test, RepeatRI) {
-  EXPECT_EQ("%rax %0\n%rax %-1\n%rax %18\n%rbx %0\n%rbx %-1\n%rbx %18\n"
-            "%rcx %0\n%rcx %-1\n%rcx %18\n%rdx %0\n%rdx %-1\n%rdx %18\n"
-            "%rbp %0\n%rbp %-1\n%rbp %18\n%rsp %0\n%rsp %-1\n%rsp %18\n"
-            "%rsi %0\n%rsi %-1\n%rsi %18\n%rdi %0\n%rdi %-1\n%rdi %18\n"
-            "%r8 %0\n%r8 %-1\n%r8 %18\n%r9 %0\n%r9 %-1\n%r9 %18\n"
-            "%r10 %0\n%r10 %-1\n%r10 %18\n%r11 %0\n%r11 %-1\n%r11 %18\n"
-            "%r12 %0\n%r12 %-1\n%r12 %18\n%r13 %0\n%r13 %-1\n%r13 %18\n"
-            "%r14 %0\n%r14 %-1\n%r14 %18\n%r15 %0\n%r15 %-1\n%r15 %18\n",
-            RepeatRI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} %{imm}"));
+  EXPECT_NE(RepeatRI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} ${imm}")
+            .find("%rax $0\n%rax $-1\n%rax $18\n%rbx $0\n%rbx $-1\n%rbx $18\n"
+                  "%rcx $0\n%rcx $-1\n%rcx $18\n%rdx $0\n%rdx $-1\n%rdx $18\n"),
+            std::string::npos);
 }
 
 TEST_F(AssemblerX86_64Test, RepeatRr) {
   EXPECT_NE(RepeatRr(/*f*/ nullptr, "%{reg1} %{reg2}")
             .find("%rax %eax\n%rax %ebx\n%rax %ecx\n%rax %edx\n%rax %ebp\n"
-                  "%rax %esp\n%rax %esi\n%rax %edi\n%rax %r8d\n%rax %r9d\n"
-                  "%rax %r10d\n%rax %r11d\n%rax %r12d\n%rax %r13d\n%rax %r14d\n"
-                  "%rax %r15d\n%rbx %eax\n%rbx %ebx\n%rbx %ecx\n%rbx %edx\n"),
+                  "%rax %esp\n%rax %esi\n%rax %edi\n%rax %r8d\n%rax %r9d\n"),
             std::string::npos);
 }
 
 TEST_F(AssemblerX86_64Test, RepeatRR) {
   EXPECT_NE(RepeatRR(/*f*/ nullptr, "%{reg1} %{reg2}")
             .find("%rax %rax\n%rax %rbx\n%rax %rcx\n%rax %rdx\n%rax %rbp\n"
-                  "%rax %rsp\n%rax %rsi\n%rax %rdi\n%rax %r8\n%rax %r9\n"
-                  "%rax %r10\n%rax %r11\n%rax %r12\n%rax %r13\n%rax %r14\n"
-                  "%rax %r15\n%rbx %rax\n%rbx %rbx\n%rbx %rcx\n%rbx %rdx\n"),
+                  "%rax %rsp\n%rax %rsi\n%rax %rdi\n%rax %r8\n%rax %r9\n"),
             std::string::npos);
 }
 
 TEST_F(AssemblerX86_64Test, RepeatRF) {
   EXPECT_NE(RepeatRF(/*f*/ nullptr, "%{reg1} %{reg2}")
             .find("%rax %xmm0\n%rax %xmm1\n%rax %xmm2\n%rax %xmm3\n%rax %xmm4\n"
-                  "%rax %xmm5\n%rax %xmm6\n%rax %xmm7\n%rax %xmm8\n%rax %xmm9\n"
-                  "%rax %xmm10\n%rax %xmm11\n%rax %xmm12\n%rax %xmm13\n%rax %xmm14\n"
-                  "%rax %xmm15\n%rbx %xmm0\n%rbx %xmm1\n%rbx %xmm2\n%rbx %xmm3\n"),
+                  "%rax %xmm5\n%rax %xmm6\n%rax %xmm7\n%rax %xmm8\n%rax %xmm9\n"),
             std::string::npos);
 }
 
 TEST_F(AssemblerX86_64Test, RepeatFF) {
   EXPECT_NE(RepeatFF(/*f*/ nullptr, "%{reg1} %{reg2}")
             .find("%xmm0 %xmm0\n%xmm0 %xmm1\n%xmm0 %xmm2\n%xmm0 %xmm3\n%xmm0 %xmm4\n"
-                  "%xmm0 %xmm5\n%xmm0 %xmm6\n%xmm0 %xmm7\n%xmm0 %xmm8\n%xmm0 %xmm9\n"
-                  "%xmm0 %xmm10\n%xmm0 %xmm11\n%xmm0 %xmm12\n%xmm0 %xmm13\n%xmm0 %xmm14\n"
-                  "%xmm0 %xmm15\n%xmm1 %xmm0\n%xmm1 %xmm1\n%xmm1 %xmm2\n%xmm1 %xmm3\n"),
+                  "%xmm0 %xmm5\n%xmm0 %xmm6\n%xmm0 %xmm7\n%xmm0 %xmm8\n%xmm0 %xmm9\n"),
             std::string::npos);
 }
 
 TEST_F(AssemblerX86_64Test, RepeatFFI) {
-  EXPECT_NE(RepeatFFI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg1} %{reg2} %{imm}")
-            .find("%xmm0 %xmm0 %0\n%xmm0 %xmm0 %-1\n%xmm0 %xmm0 %18\n"
-                  "%xmm0 %xmm1 %0\n%xmm0 %xmm1 %-1\n%xmm0 %xmm1 %18\n"
-                  "%xmm0 %xmm2 %0\n%xmm0 %xmm2 %-1\n%xmm0 %xmm2 %18\n"
-                  "%xmm0 %xmm3 %0\n%xmm0 %xmm3 %-1\n%xmm0 %xmm3 %18\n"),
+  EXPECT_NE(RepeatFFI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg1} %{reg2} ${imm}")
+            .find("%xmm0 %xmm0 $0\n%xmm0 %xmm0 $-1\n%xmm0 %xmm0 $18\n"
+                  "%xmm0 %xmm1 $0\n%xmm0 %xmm1 $-1\n%xmm0 %xmm1 $18\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatA) {
+  EXPECT_EQ("-1(%rax,%rbx,1)\n", RepeatA(/*f*/ nullptr, addresses_singleton_, "{mem}"));
+}
+
+TEST_F(AssemblerX86_64Test, RepeatAFull) {
+  EXPECT_EQ("15(%rdi,%rax,1)\n16(%rdi,%rbx,2)\n17(%rdi,%rcx,4)\n18(%rdi,%rdx,8)\n"
+            "-1(%rax)\n(%rbx)\n1(%rsi)\n987654321(%rdi)\n15(%rsp,%rax,1)\n"
+            "16(%rsp,%rbx,2)\n17(%rsp,%rcx,4)\n18(%rsp,%rdx,8)\n-1(%rsp)\n"
+            "(%rsp)\n1(%rsp)\n987654321(%rsp)\n-1(%r8,%r15,2)\n123456789(%r15)\n",
+            RepeatA(/*f*/ nullptr, "{mem}"));
+}
+
+TEST_F(AssemblerX86_64Test, RepeatAI) {
+  EXPECT_EQ("-1(%rax,%rbx,1) $0\n-1(%rax,%rbx,1) $-1\n-1(%rax,%rbx,1) $18\n",
+            RepeatAI(/*f*/ nullptr, /*imm_bytes*/ 1U, addresses_singleton_, "{mem} ${imm}"));
+}
+
+TEST_F(AssemblerX86_64Test, RepeatRA) {
+  EXPECT_NE(RepeatRA(/*f*/ nullptr, addresses_singleton_, "%{reg} {mem}")
+            .find("%rax -1(%rax,%rbx,1)\n%rbx -1(%rax,%rbx,1)\n%rcx -1(%rax,%rbx,1)\n"
+                  "%rdx -1(%rax,%rbx,1)\n%rbp -1(%rax,%rbx,1)\n%rsp -1(%rax,%rbx,1)\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatrA) {
+  EXPECT_NE(RepeatrA(/*f*/ nullptr, addresses_singleton_, "%{reg} {mem}")
+            .find("%eax -1(%rax,%rbx,1)\n%ebx -1(%rax,%rbx,1)\n%ecx -1(%rax,%rbx,1)\n"
+                  "%edx -1(%rax,%rbx,1)\n%ebp -1(%rax,%rbx,1)\n%esp -1(%rax,%rbx,1)\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatAR) {
+  EXPECT_NE(RepeatAR(/*f*/ nullptr, addresses_singleton_, "{mem} %{reg}")
+            .find("-1(%rax,%rbx,1) %rax\n-1(%rax,%rbx,1) %rbx\n-1(%rax,%rbx,1) %rcx\n"
+                  "-1(%rax,%rbx,1) %rdx\n-1(%rax,%rbx,1) %rbp\n-1(%rax,%rbx,1) %rsp\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatAr) {
+  EXPECT_NE(RepeatAr(/*f*/ nullptr, addresses_singleton_, "{mem} %{reg}")
+            .find("-1(%rax,%rbx,1) %eax\n-1(%rax,%rbx,1) %ebx\n-1(%rax,%rbx,1) %ecx\n"
+                  "-1(%rax,%rbx,1) %edx\n-1(%rax,%rbx,1) %ebp\n-1(%rax,%rbx,1) %esp\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatFA) {
+  EXPECT_NE(RepeatFA(/*f*/ nullptr, addresses_singleton_, "%{reg} {mem}").
+            find("%xmm0 -1(%rax,%rbx,1)\n%xmm1 -1(%rax,%rbx,1)\n%xmm2 -1(%rax,%rbx,1)\n"
+                 "%xmm3 -1(%rax,%rbx,1)\n%xmm4 -1(%rax,%rbx,1)\n%xmm5 -1(%rax,%rbx,1)\n"),
+            std::string::npos);
+}
+
+TEST_F(AssemblerX86_64Test, RepeatAF) {
+  EXPECT_NE(RepeatAF(/*f*/ nullptr, addresses_singleton_, "{mem} %{reg}")
+            .find("-1(%rax,%rbx,1) %xmm0\n-1(%rax,%rbx,1) %xmm1\n-1(%rax,%rbx,1) %xmm2\n"
+                  "-1(%rax,%rbx,1) %xmm3\n-1(%rax,%rbx,1) %xmm4\n-1(%rax,%rbx,1) %xmm5\n"),
             std::string::npos);
 }
 
@@ -412,12 +503,43 @@
   EXPECT_TRUE(CheckTools());
 }
 
+TEST_F(AssemblerX86_64Test, PopqAllAddresses) {
+  // Make sure all addressing modes combinations are tested at least once.
+  std::vector<x86_64::Address> all_addresses;
+  for (x86_64::CpuRegister* base : GetRegisters()) {
+    // Base only.
+    all_addresses.push_back(x86_64::Address(*base, -1));
+    all_addresses.push_back(x86_64::Address(*base, 0));
+    all_addresses.push_back(x86_64::Address(*base, 1));
+    all_addresses.push_back(x86_64::Address(*base, 123456789));
+    for (x86_64::CpuRegister* index : GetRegisters()) {
+      if (index->AsRegister() == x86_64::RSP) {
+        // Index cannot be RSP.
+        continue;
+      } else if (base->AsRegister() == index->AsRegister()) {
+       // Index only.
+       all_addresses.push_back(x86_64::Address(*index, x86_64::TIMES_1, -1));
+       all_addresses.push_back(x86_64::Address(*index, x86_64::TIMES_2, 0));
+       all_addresses.push_back(x86_64::Address(*index, x86_64::TIMES_4, 1));
+       all_addresses.push_back(x86_64::Address(*index, x86_64::TIMES_8, 123456789));
+      }
+      // Base and index.
+      all_addresses.push_back(x86_64::Address(*base, *index, x86_64::TIMES_1, -1));
+      all_addresses.push_back(x86_64::Address(*base, *index, x86_64::TIMES_2, 0));
+      all_addresses.push_back(x86_64::Address(*base, *index, x86_64::TIMES_4, 1));
+      all_addresses.push_back(x86_64::Address(*base, *index, x86_64::TIMES_8, 123456789));
+    }
+  }
+  DriverStr(RepeatA(&x86_64::X86_64Assembler::popq, all_addresses, "popq {mem}"), "popq");
+}
+
 TEST_F(AssemblerX86_64Test, PushqRegs) {
   DriverStr(RepeatR(&x86_64::X86_64Assembler::pushq, "pushq %{reg}"), "pushq");
 }
 
 TEST_F(AssemblerX86_64Test, PushqImm) {
-  DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi");
+  DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, /*imm_bytes*/ 4U,
+                    "pushq ${imm}"), "pushqi");
 }
 
 TEST_F(AssemblerX86_64Test, MovqRegs) {
@@ -425,7 +547,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, MovqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, /*imm_bytes*/ 8U,
+                     "movq ${imm}, %{reg}"), "movqi");
 }
 
 TEST_F(AssemblerX86_64Test, MovlRegs) {
@@ -433,7 +556,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, MovlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::movl, 4U, "mov ${imm}, %{reg}"), "movli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::movl, /*imm_bytes*/ 4U,
+                     "mov ${imm}, %{reg}"), "movli");
 }
 
 TEST_F(AssemblerX86_64Test, AddqRegs) {
@@ -441,7 +565,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, AddqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, /*imm_bytes*/ 4U,
+                     "addq ${imm}, %{reg}"), "addqi");
 }
 
 TEST_F(AssemblerX86_64Test, AddlRegs) {
@@ -449,7 +574,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, AddlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::addl, 4U, "add ${imm}, %{reg}"), "addli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::addl, /*imm_bytes*/ 4U,
+                     "add ${imm}, %{reg}"), "addli");
 }
 
 TEST_F(AssemblerX86_64Test, ImulqReg1) {
@@ -461,7 +587,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, ImulqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::imulq, 4U, "imulq ${imm}, %{reg}, %{reg}"),
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::imulq, /*imm_bytes*/ 4U,
+                     "imulq ${imm}, %{reg}, %{reg}"),
             "imulqi");
 }
 
@@ -470,7 +597,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, ImullImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::imull, 4U, "imull ${imm}, %{reg}, %{reg}"),
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::imull, /*imm_bytes*/ 4U,
+                     "imull ${imm}, %{reg}, %{reg}"),
             "imulli");
 }
 
@@ -483,7 +611,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, SubqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, /*imm_bytes*/ 4U,
+                     "subq ${imm}, %{reg}"), "subqi");
 }
 
 TEST_F(AssemblerX86_64Test, SublRegs) {
@@ -491,21 +620,19 @@
 }
 
 TEST_F(AssemblerX86_64Test, SublImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::subl, 4U, "sub ${imm}, %{reg}"), "subli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::subl, /*imm_bytes*/ 4U,
+                     "sub ${imm}, %{reg}"), "subli");
 }
 
 // Shll only allows CL as the shift count.
 std::string shll_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->shll(*reg, shifter);
     str << "shll %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -514,21 +641,19 @@
 }
 
 TEST_F(AssemblerX86_64Test, ShllImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::shll, 1U, "shll ${imm}, %{reg}"), "shlli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::shll, /*imm_bytes*/ 1U,
+                     "shll ${imm}, %{reg}"), "shlli");
 }
 
 // Shlq only allows CL as the shift count.
 std::string shlq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->shlq(*reg, shifter);
     str << "shlq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -537,21 +662,19 @@
 }
 
 TEST_F(AssemblerX86_64Test, ShlqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shlq, 1U, "shlq ${imm}, %{reg}"), "shlqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shlq, /*imm_bytes*/ 1U,
+                     "shlq ${imm}, %{reg}"), "shlqi");
 }
 
 // Shrl only allows CL as the shift count.
 std::string shrl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->shrl(*reg, shifter);
     str << "shrl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -560,21 +683,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, ShrlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::shrl, 1U, "shrl ${imm}, %{reg}"), "shrli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::shrl, /*imm_bytes*/ 1U, "shrl ${imm}, %{reg}"), "shrli");
 }
 
 // Shrq only allows CL as the shift count.
 std::string shrq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->shrq(*reg, shifter);
     str << "shrq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -583,21 +703,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, ShrqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shrq, 1U, "shrq ${imm}, %{reg}"), "shrqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shrq, /*imm_bytes*/ 1U, "shrq ${imm}, %{reg}"), "shrqi");
 }
 
 // Sarl only allows CL as the shift count.
 std::string sarl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->sarl(*reg, shifter);
     str << "sarl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -606,21 +723,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, SarlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::sarl, 1U, "sarl ${imm}, %{reg}"), "sarli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::sarl, /*imm_bytes*/ 1U, "sarl ${imm}, %{reg}"), "sarli");
 }
 
 // Sarq only allows CL as the shift count.
 std::string sarq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->sarq(*reg, shifter);
     str << "sarq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -629,21 +743,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, SarqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::sarq, 1U, "sarq ${imm}, %{reg}"), "sarqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::sarq, /*imm_bytes*/ 1U, "sarq ${imm}, %{reg}"), "sarqi");
 }
 
 // Rorl only allows CL as the shift count.
 std::string rorl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->rorl(*reg, shifter);
     str << "rorl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -652,21 +763,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, RorlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::rorl, 1U, "rorl ${imm}, %{reg}"), "rorli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::rorl, /*imm_bytes*/ 1U, "rorl ${imm}, %{reg}"), "rorli");
 }
 
 // Roll only allows CL as the shift count.
 std::string roll_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->roll(*reg, shifter);
     str << "roll %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -675,21 +783,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, RollImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::roll, 1U, "roll ${imm}, %{reg}"), "rolli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::roll, /*imm_bytes*/ 1U, "roll ${imm}, %{reg}"), "rolli");
 }
 
 // Rorq only allows CL as the shift count.
 std::string rorq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->rorq(*reg, shifter);
     str << "rorq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -698,21 +803,18 @@
 }
 
 TEST_F(AssemblerX86_64Test, RorqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::rorq, 1U, "rorq ${imm}, %{reg}"), "rorqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::rorq, /*imm_bytes*/ 1U, "rorq ${imm}, %{reg}"), "rorqi");
 }
 
 // Rolq only allows CL as the shift count.
 std::string rolq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
-
   x86_64::CpuRegister shifter(x86_64::RCX);
   for (auto reg : registers) {
     assembler->rolq(*reg, shifter);
     str << "rolq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -721,7 +823,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, RolqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::rolq, 1U, "rolq ${imm}, %{reg}"), "rolqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::rolq, /*imm_bytes*/ 1U, "rolq ${imm}, %{reg}"), "rolqi");
 }
 
 TEST_F(AssemblerX86_64Test, CmpqRegs) {
@@ -729,8 +831,9 @@
 }
 
 TEST_F(AssemblerX86_64Test, CmpqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::cmpq, 4U  /* cmpq only supports 32b imm */,
-                     "cmpq ${imm}, %{reg}"), "cmpqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::cmpq,
+                     /*imm_bytes*/ 4U,
+                     "cmpq ${imm}, %{reg}"), "cmpqi");  // only imm32
 }
 
 TEST_F(AssemblerX86_64Test, CmplRegs) {
@@ -738,7 +841,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, CmplImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::cmpl, 4U, "cmpl ${imm}, %{reg}"), "cmpli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::cmpl, /*imm_bytes*/ 4U, "cmpl ${imm}, %{reg}"), "cmpli");
 }
 
 TEST_F(AssemblerX86_64Test, Testl) {
@@ -768,8 +871,9 @@
 }
 
 TEST_F(AssemblerX86_64Test, AndqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::andq, 4U  /* andq only supports 32b imm */,
-                     "andq ${imm}, %{reg}"), "andqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::andq,
+                     /*imm_bytes*/ 4U,
+                     "andq ${imm}, %{reg}"), "andqi");  // only imm32
 }
 
 TEST_F(AssemblerX86_64Test, AndlRegs) {
@@ -777,7 +881,9 @@
 }
 
 TEST_F(AssemblerX86_64Test, AndlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::andl, 4U, "andl ${imm}, %{reg}"), "andli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::andl,
+                     /*imm_bytes*/ 4U,
+                     "andl ${imm}, %{reg}"), "andli");
 }
 
 TEST_F(AssemblerX86_64Test, OrqRegs) {
@@ -789,7 +895,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, OrlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::orl, 4U, "orl ${imm}, %{reg}"), "orli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::orl,
+                     /*imm_bytes*/ 4U, "orl ${imm}, %{reg}"), "orli");
 }
 
 TEST_F(AssemblerX86_64Test, XorqRegs) {
@@ -797,7 +904,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, XorqImm) {
-  DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq,
+                     /*imm_bytes*/ 4U, "xorq ${imm}, %{reg}"), "xorqi");
 }
 
 TEST_F(AssemblerX86_64Test, XorlRegs) {
@@ -805,7 +913,8 @@
 }
 
 TEST_F(AssemblerX86_64Test, XorlImm) {
-  DriverStr(Repeatri(&x86_64::X86_64Assembler::xorl, 4U, "xor ${imm}, %{reg}"), "xorli");
+  DriverStr(RepeatrI(&x86_64::X86_64Assembler::xorl,
+                     /*imm_bytes*/ 4U, "xor ${imm}, %{reg}"), "xorli");
 }
 
 TEST_F(AssemblerX86_64Test, Xchgq) {
@@ -813,167 +922,87 @@
 }
 
 TEST_F(AssemblerX86_64Test, Xchgl) {
-  // Test is disabled because GCC generates 0x87 0xC0 for xchgl eax, eax. All other cases are the
-  // same. Anyone know why it doesn't emit a simple 0x90? It does so for xchgq rax, rax...
+  // TODO: Test is disabled because GCC generates 0x87 0xC0 for xchgl eax, eax. All other cases
+  // are the same. Anyone know why it doesn't emit a simple 0x90? It does so for xchgq rax, rax...
   // DriverStr(Repeatrr(&x86_64::X86_64Assembler::xchgl, "xchgl %{reg2}, %{reg1}"), "xchgl");
 }
 
 TEST_F(AssemblerX86_64Test, LockCmpxchgl) {
-  GetAssembler()->LockCmpxchgl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::R8));
-  GetAssembler()->LockCmpxchgl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0),
-      x86_64::CpuRegister(x86_64::RSI));
-  const char* expected =
-    "lock cmpxchgl %ESI, 0xc(%RDI,%RBX,4)\n"
-    "lock cmpxchgl %ESI, 0xc(%RDI,%R9,4)\n"
-    "lock cmpxchgl %R8d, 0xc(%RDI,%R9,4)\n"
-    "lock cmpxchgl %ESI, (%R13)\n"
-    "lock cmpxchgl %ESI, (%R13,%R9,1)\n";
-
-  DriverStr(expected, "lock_cmpxchgl");
+  DriverStr(RepeatAr(&x86_64::X86_64Assembler::LockCmpxchgl,
+                     "lock cmpxchgl %{reg}, {mem}"), "lock_cmpxchgl");
 }
 
 TEST_F(AssemblerX86_64Test, LockCmpxchgq) {
-  GetAssembler()->LockCmpxchgq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12),
-      x86_64::CpuRegister(x86_64::R8));
-  GetAssembler()->LockCmpxchgq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RSI));
-  GetAssembler()->LockCmpxchgq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0),
-      x86_64::CpuRegister(x86_64::RSI));
-  const char* expected =
-    "lock cmpxchg %RSI, 0xc(%RDI,%RBX,4)\n"
-    "lock cmpxchg %RSI, 0xc(%RDI,%R9,4)\n"
-    "lock cmpxchg %R8, 0xc(%RDI,%R9,4)\n"
-    "lock cmpxchg %RSI, (%R13)\n"
-    "lock cmpxchg %RSI, (%R13,%R9,1)\n";
-
-  DriverStr(expected, "lock_cmpxchg");
+  DriverStr(RepeatAR(&x86_64::X86_64Assembler::LockCmpxchgq,
+                     "lock cmpxchg %{reg}, {mem}"), "lock_cmpxchg");
 }
 
-TEST_F(AssemblerX86_64Test, Movl) {
-  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->movl(x86_64::CpuRegister(x86_64::R8), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), 0));
-  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
-  const char* expected =
-    "movl 0xc(%RDI,%RBX,4), %EAX\n"
-    "movl 0xc(%RDI,%R9,4), %EAX\n"
-    "movl 0xc(%RDI,%R9,4), %R8d\n"
-    "movl (%R13), %EAX\n"
-    "movl (%R13,%R9,1), %EAX\n";
-
-  DriverStr(expected, "movl");
+TEST_F(AssemblerX86_64Test, MovqStore) {
+  DriverStr(RepeatAR(&x86_64::X86_64Assembler::movq, "movq %{reg}, {mem}"), "movq_s");
 }
 
-TEST_F(AssemblerX86_64Test, Movw) {
-  GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                       x86_64::CpuRegister(x86_64::R9));
-  GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                       x86_64::Immediate(0));
-  GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0),
-                       x86_64::Immediate(0));
-  GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::R14), 0),
-                       x86_64::Immediate(0));
-  const char* expected =
-      "movw %R9w, 0(%RAX)\n"
-      "movw $0, 0(%RAX)\n"
-      "movw $0, 0(%R9)\n"
-      "movw $0, 0(%R14)\n";
-  DriverStr(expected, "movw");
+TEST_F(AssemblerX86_64Test, MovqLoad) {
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::movq, "movq {mem}, %{reg}"), "movq_l");
+}
+
+TEST_F(AssemblerX86_64Test, MovlStore) {
+  DriverStr(RepeatAr(&x86_64::X86_64Assembler::movl, "movl %{reg}, {mem}"), "movl_s");
+}
+
+TEST_F(AssemblerX86_64Test, MovlLoad) {
+  DriverStr(RepeatrA(&x86_64::X86_64Assembler::movl, "movl {mem}, %{reg}"), "movl_l");
+}
+
+TEST_F(AssemblerX86_64Test, MovwStore) {
+  DriverStr(RepeatAw(&x86_64::X86_64Assembler::movw, "movw %{reg}, {mem}"), "movw_s");
+}
+
+TEST_F(AssemblerX86_64Test, MovbStore) {
+  DriverStr(RepeatAb(&x86_64::X86_64Assembler::movb, "movb %{reg}, {mem}"), "movb_s");
 }
 
 TEST_F(AssemblerX86_64Test, Cmpw) {
-  GetAssembler()->cmpw(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                       x86_64::Immediate(0));
-  GetAssembler()->cmpw(x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0),
-                       x86_64::Immediate(0));
-  GetAssembler()->cmpw(x86_64::Address(x86_64::CpuRegister(x86_64::R14), 0),
-                       x86_64::Immediate(0));
-  const char* expected =
-      "cmpw $0, 0(%RAX)\n"
-      "cmpw $0, 0(%R9)\n"
-      "cmpw $0, 0(%R14)\n";
-  DriverStr(expected, "cmpw");
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::cmpw,
+                     /*imm_bytes*/ 1U,
+                     "cmpw ${imm}, {mem}"), "cmpw");  // TODO: only imm8?
 }
 
 TEST_F(AssemblerX86_64Test, MovqAddrImm) {
-  GetAssembler()->movq(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                       x86_64::Immediate(-5));
-  const char* expected = "movq $-5, 0(%RAX)\n";
-  DriverStr(expected, "movq");
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::movq,
+                     /*imm_bytes*/ 4U,
+                     "movq ${imm}, {mem}"), "movq");  // only imm32
+}
+
+TEST_F(AssemblerX86_64Test, MovlAddrImm) {
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::movl,
+                     /*imm_bytes*/ 4U, "movl ${imm}, {mem}"), "movl");
+}
+
+TEST_F(AssemblerX86_64Test, MovwAddrImm) {
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::movw,
+                     /*imm_bytes*/ 2U, "movw ${imm}, {mem}"), "movw");
+}
+
+TEST_F(AssemblerX86_64Test, MovbAddrImm) {
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::movb,
+                     /*imm_bytes*/ 1U, "movb ${imm}, {mem}"), "movb");
 }
 
 TEST_F(AssemblerX86_64Test, Movntl) {
-  GetAssembler()->movntl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntl(x86_64::Address(x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntl(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0), x86_64::CpuRegister(x86_64::R9));
-  const char* expected =
-    "movntil %EAX, 0xc(%RDI,%RBX,4)\n"
-    "movntil %EAX, 0xc(%RDI,%R9,4)\n"
-    "movntil %EAX, 0xc(%RDI,%R9,4)\n"
-    "movntil %EAX, (%R13)\n"
-    "movntil %R9d, (%R13,%R9,1)\n";
-
-  DriverStr(expected, "movntl");
+  DriverStr(RepeatAr(&x86_64::X86_64Assembler::movntl, "movntil %{reg}, {mem}"), "movntl");
 }
 
 TEST_F(AssemblerX86_64Test, Movntq) {
-  GetAssembler()->movntq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntq(x86_64::Address(x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RAX));
-  GetAssembler()->movntq(x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0), x86_64::CpuRegister(x86_64::R9));
-  const char* expected =
-    "movntiq %RAX, 0xc(%RDI,%RBX,4)\n"
-    "movntiq %RAX, 0xc(%RDI,%R9,4)\n"
-    "movntiq %RAX, 0xc(%RDI,%R9,4)\n"
-    "movntiq %RAX, (%R13)\n"
-    "movntiq %R9, (%R13,%R9,1)\n";
-
-  DriverStr(expected, "movntq");
+  DriverStr(RepeatAR(&x86_64::X86_64Assembler::movntq, "movntiq %{reg}, {mem}"), "movntq");
 }
 
 TEST_F(AssemblerX86_64Test, Cvtsi2ssAddr) {
   GetAssembler()->cvtsi2ss(x86_64::XmmRegister(x86_64::XMM0),
                            x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                           false);
+                           /*is64bit*/ false);
   GetAssembler()->cvtsi2ss(x86_64::XmmRegister(x86_64::XMM0),
                            x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                           true);
+                           /*is64bit*/ true);
   const char* expected = "cvtsi2ss 0(%RAX), %xmm0\n"
                          "cvtsi2ssq 0(%RAX), %xmm0\n";
   DriverStr(expected, "cvtsi2ss");
@@ -982,111 +1011,69 @@
 TEST_F(AssemblerX86_64Test, Cvtsi2sdAddr) {
   GetAssembler()->cvtsi2sd(x86_64::XmmRegister(x86_64::XMM0),
                            x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                           false);
+                           /*is64bit*/ false);
   GetAssembler()->cvtsi2sd(x86_64::XmmRegister(x86_64::XMM0),
                            x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
-                           true);
+                           /*is64bit*/ true);
   const char* expected = "cvtsi2sd 0(%RAX), %xmm0\n"
                          "cvtsi2sdq 0(%RAX), %xmm0\n";
   DriverStr(expected, "cvtsi2sd");
 }
 
 TEST_F(AssemblerX86_64Test, CmpqAddr) {
-  GetAssembler()->cmpq(x86_64::CpuRegister(x86_64::R12),
-                       x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "cmpq 0(%R9), %R12\n";
-  DriverStr(expected, "cmpq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::cmpq, "cmpq {mem}, %{reg}"), "cmpq");
 }
 
 TEST_F(AssemblerX86_64Test, MovsxdAddr) {
-  GetAssembler()->movsxd(x86_64::CpuRegister(x86_64::R12),
-                       x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "movslq 0(%R9), %R12\n";
-  DriverStr(expected, "movsxd");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::movsxd, "movslq {mem}, %{reg}"), "movsxd");
 }
 
 TEST_F(AssemblerX86_64Test, TestqAddr) {
-  GetAssembler()->testq(x86_64::CpuRegister(x86_64::R12),
-                        x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "testq 0(%R9), %R12\n";
-  DriverStr(expected, "testq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::testq, "testq {mem}, %{reg}"), "testq");
 }
 
 TEST_F(AssemblerX86_64Test, AddqAddr) {
-  GetAssembler()->addq(x86_64::CpuRegister(x86_64::R12),
-                        x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "addq 0(%R9), %R12\n";
-  DriverStr(expected, "addq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::addq, "addq {mem}, %{reg}"), "addq");
 }
 
 TEST_F(AssemblerX86_64Test, SubqAddr) {
-  GetAssembler()->subq(x86_64::CpuRegister(x86_64::R12),
-                        x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "subq 0(%R9), %R12\n";
-  DriverStr(expected, "subq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::subq, "subq {mem}, %{reg}"), "subq");
 }
 
 TEST_F(AssemblerX86_64Test, Cvtss2sdAddr) {
-  GetAssembler()->cvtss2sd(x86_64::XmmRegister(x86_64::XMM0),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "cvtss2sd 0(%RAX), %xmm0\n";
-  DriverStr(expected, "cvtss2sd");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::cvtss2sd, "cvtss2sd {mem}, %{reg}"), "cvtss2sd");
 }
 
 TEST_F(AssemblerX86_64Test, Cvtsd2ssAddr) {
-  GetAssembler()->cvtsd2ss(x86_64::XmmRegister(x86_64::XMM0),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "cvtsd2ss 0(%RAX), %xmm0\n";
-  DriverStr(expected, "cvtsd2ss");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::cvtsd2ss, "cvtsd2ss {mem}, %{reg}"), "cvtsd2ss");
 }
 
 TEST_F(AssemblerX86_64Test, ComissAddr) {
-  GetAssembler()->comiss(x86_64::XmmRegister(x86_64::XMM14),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "comiss 0(%RAX), %xmm14\n";
-  DriverStr(expected, "comiss");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::comiss, "comiss {mem}, %{reg}"), "comiss");
 }
 
 TEST_F(AssemblerX86_64Test, ComisdAddr) {
-  GetAssembler()->comisd(x86_64::XmmRegister(x86_64::XMM0),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
-  const char* expected = "comisd 0(%R9), %xmm0\n";
-  DriverStr(expected, "comisd");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::comisd, "comisd {mem}, %{reg}"), "comisd");
 }
 
 TEST_F(AssemblerX86_64Test, UComissAddr) {
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "ucomiss 0(%RAX), %xmm0\n";
-  DriverStr(expected, "ucomiss");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::ucomiss, "ucomiss {mem}, %{reg}"), "ucomiss");
 }
 
 TEST_F(AssemblerX86_64Test, UComisdAddr) {
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM0),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "ucomisd 0(%RAX), %xmm0\n";
-  DriverStr(expected, "ucomisd");
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::ucomisd, "ucomisd {mem}, %{reg}"), "ucomisd");
 }
 
 TEST_F(AssemblerX86_64Test, Andq) {
-  GetAssembler()->andq(x86_64::CpuRegister(x86_64::R9),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "andq 0(%RAX), %r9\n";
-  DriverStr(expected, "andq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::andq, "andq {mem}, %{reg}"), "andq");
 }
 
 TEST_F(AssemblerX86_64Test, Orq) {
-  GetAssembler()->orq(x86_64::CpuRegister(x86_64::R9),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "orq 0(%RAX), %r9\n";
-  DriverStr(expected, "orq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::orq, "orq {mem}, %{reg}"), "orq");
 }
 
 TEST_F(AssemblerX86_64Test, Xorq) {
-  GetAssembler()->xorq(x86_64::CpuRegister(x86_64::R9),
-                           x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
-  const char* expected = "xorq 0(%RAX), %r9\n";
-  DriverStr(expected, "xorq");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::xorq, "xorq {mem}, %{reg}"), "xorq");
 }
 
 TEST_F(AssemblerX86_64Test, RepneScasb) {
@@ -1115,22 +1102,20 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps");
 }
 
-TEST_F(AssemblerX86_64Test, MovapsAddr) {
-  GetAssembler()->movaps(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movaps(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movaps 0x4(%RSP), %xmm0\n"
-    "movaps %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movaps_address");
+TEST_F(AssemblerX86_64Test, MovapsStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movaps, "movaps %{reg}, {mem}"), "movaps_s");
 }
 
-TEST_F(AssemblerX86_64Test, MovupsAddr) {
-  GetAssembler()->movups(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movups(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movups 0x4(%RSP), %xmm0\n"
-    "movups %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movups_address");
+TEST_F(AssemblerX86_64Test, MovapsLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movaps, "movaps {mem}, %{reg}"), "movaps_l");
+}
+
+TEST_F(AssemblerX86_64Test, MovupsStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movups, "movups %{reg}, {mem}"), "movups_s");
+}
+
+TEST_F(AssemblerX86_64Test, MovupsLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movups, "movups {mem}, %{reg}"), "movups_l");
 }
 
 TEST_F(AssemblerX86_64Test, Movss) {
@@ -1141,22 +1126,20 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd");
 }
 
-TEST_F(AssemblerX86_64Test, MovapdAddr) {
-  GetAssembler()->movapd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movapd(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movapd 0x4(%RSP), %xmm0\n"
-    "movapd %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movapd_address");
+TEST_F(AssemblerX86_64Test, MovapdStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movapd, "movapd %{reg}, {mem}"), "movapd_s");
 }
 
-TEST_F(AssemblerX86_64Test, MovupdAddr) {
-  GetAssembler()->movupd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movupd(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movupd 0x4(%RSP), %xmm0\n"
-    "movupd %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movupd_address");
+TEST_F(AssemblerX86_64Test, MovapdLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movapd, "movapd {mem}, %{reg}"), "movapd_l");
+}
+
+TEST_F(AssemblerX86_64Test, MovupdStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movupd, "movupd %{reg}, {mem}"), "movupd_s");
+}
+
+TEST_F(AssemblerX86_64Test, MovupdLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movupd, "movupd {mem}, %{reg}"), "movupd_l");
 }
 
 TEST_F(AssemblerX86_64Test, Movsd) {
@@ -1164,25 +1147,23 @@
 }
 
 TEST_F(AssemblerX86_64Test, Movdqa) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::movdqa, "movdqa %{reg2}, %{reg1}"), "movapd");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::movdqa, "movdqa %{reg2}, %{reg1}"), "movdqa");
 }
 
-TEST_F(AssemblerX86_64Test, MovdqaAddr) {
-  GetAssembler()->movdqa(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movdqa(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movdqa 0x4(%RSP), %xmm0\n"
-    "movdqa %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movdqa_address");
+TEST_F(AssemblerX86_64Test, MovdqaStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqa, "movdqa %{reg}, {mem}"), "movdqa_s");
 }
 
-TEST_F(AssemblerX86_64Test, MovdquAddr) {
-  GetAssembler()->movdqu(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->movdqu(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
-  const char* expected =
-    "movdqu 0x4(%RSP), %xmm0\n"
-    "movdqu %xmm1, 0x2(%RSP)\n";
-  DriverStr(expected, "movdqu_address");
+TEST_F(AssemblerX86_64Test, MovdqaLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqa, "movdqa {mem}, %{reg}"), "movdqa_l");
+}
+
+TEST_F(AssemblerX86_64Test, MovdquStore) {
+  DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqu, "movdqu %{reg}, {mem}"), "movdqu_s");
+}
+
+TEST_F(AssemblerX86_64Test, MovdquLoad) {
+  DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqu, "movdqu {mem}, %{reg}"), "movdqu_l");
 }
 
 TEST_F(AssemblerX86_64Test, Movd1) {
@@ -1364,11 +1345,13 @@
 }
 
 TEST_F(AssemblerX86_64Test, Roundss) {
-  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::roundss, 1, "roundss ${imm}, %{reg2}, %{reg1}"), "roundss");
+  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::roundss, /*imm_bytes*/ 1U,
+                      "roundss ${imm}, %{reg2}, %{reg1}"), "roundss");
 }
 
 TEST_F(AssemblerX86_64Test, Roundsd) {
-  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::roundsd, 1, "roundsd ${imm}, %{reg2}, %{reg1}"), "roundsd");
+  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::roundsd, /*imm_bytes*/ 1U,
+                      "roundsd ${imm}, %{reg2}, %{reg1}"), "roundsd");
 }
 
 TEST_F(AssemblerX86_64Test, Xorps) {
@@ -1564,47 +1547,58 @@
 }
 
 TEST_F(AssemblerX86_64Test, Shufps) {
-  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
+  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufps, /*imm_bytes*/ 1U,
+                      "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
 }
 
 TEST_F(AssemblerX86_64Test, Shufpd) {
-  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufpd, 1, "shufpd ${imm}, %{reg2}, %{reg1}"), "shufpd");
+  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufpd, /*imm_bytes*/ 1U,
+                      "shufpd ${imm}, %{reg2}, %{reg1}"), "shufpd");
 }
 
 TEST_F(AssemblerX86_64Test, PShufd) {
-  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::pshufd, 1, "pshufd ${imm}, %{reg2}, %{reg1}"), "pshufd");
+  DriverStr(RepeatFFI(&x86_64::X86_64Assembler::pshufd, /*imm_bytes*/ 1U,
+                      "pshufd ${imm}, %{reg2}, %{reg1}"), "pshufd");
 }
 
 TEST_F(AssemblerX86_64Test, Punpcklbw) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklbw, "punpcklbw %{reg2}, %{reg1}"), "punpcklbw");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklbw,
+                     "punpcklbw %{reg2}, %{reg1}"), "punpcklbw");
 }
 
 TEST_F(AssemblerX86_64Test, Punpcklwd) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklwd, "punpcklwd %{reg2}, %{reg1}"), "punpcklwd");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklwd,
+                     "punpcklwd %{reg2}, %{reg1}"), "punpcklwd");
 }
 
 TEST_F(AssemblerX86_64Test, Punpckldq) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckldq, "punpckldq %{reg2}, %{reg1}"), "punpckldq");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckldq,
+                     "punpckldq %{reg2}, %{reg1}"), "punpckldq");
 }
 
 TEST_F(AssemblerX86_64Test, Punpcklqdq) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklqdq, "punpcklqdq %{reg2}, %{reg1}"), "punpcklqdq");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklqdq,
+                     "punpcklqdq %{reg2}, %{reg1}"), "punpcklqdq");
 }
 
 TEST_F(AssemblerX86_64Test, Punpckhbw) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhbw, "punpckhbw %{reg2}, %{reg1}"), "punpckhbw");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhbw,
+                     "punpckhbw %{reg2}, %{reg1}"), "punpckhbw");
 }
 
 TEST_F(AssemblerX86_64Test, Punpckhwd) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhwd, "punpckhwd %{reg2}, %{reg1}"), "punpckhwd");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhwd,
+                     "punpckhwd %{reg2}, %{reg1}"), "punpckhwd");
 }
 
 TEST_F(AssemblerX86_64Test, Punpckhdq) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhdq, "punpckhdq %{reg2}, %{reg1}"), "punpckhdq");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhdq,
+                     "punpckhdq %{reg2}, %{reg1}"), "punpckhdq");
 }
 
 TEST_F(AssemblerX86_64Test, Punpckhqdq) {
-  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhqdq, "punpckhqdq %{reg2}, %{reg1}"), "punpckhqdq");
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhqdq,
+                     "punpckhqdq %{reg2}, %{reg1}"), "punpckhqdq");
 }
 
 TEST_F(AssemblerX86_64Test, Psllw) {
@@ -1653,63 +1647,21 @@
   GetAssembler()->psrld(x86_64::XmmRegister(x86_64::XMM0),  x86_64::Immediate(1));
   GetAssembler()->psrld(x86_64::XmmRegister(x86_64::XMM15), x86_64::Immediate(2));
   DriverStr("psrld $1, %xmm0\n"
-            "psrld $2, %xmm15\n", "pslldi");
+            "psrld $2, %xmm15\n", "psrldi");
 }
 
 TEST_F(AssemblerX86_64Test, Psrlq) {
   GetAssembler()->psrlq(x86_64::XmmRegister(x86_64::XMM0),  x86_64::Immediate(1));
   GetAssembler()->psrlq(x86_64::XmmRegister(x86_64::XMM15), x86_64::Immediate(2));
   DriverStr("psrlq $1, %xmm0\n"
-            "psrlq $2, %xmm15\n", "pslrqi");
+            "psrlq $2, %xmm15\n", "psrlqi");
 }
 
 TEST_F(AssemblerX86_64Test, Psrldq) {
   GetAssembler()->psrldq(x86_64::XmmRegister(x86_64::XMM0),  x86_64::Immediate(1));
   GetAssembler()->psrldq(x86_64::XmmRegister(x86_64::XMM15), x86_64::Immediate(2));
   DriverStr("psrldq $1, %xmm0\n"
-            "psrldq $2, %xmm15\n", "pslrdqi");
-}
-
-TEST_F(AssemblerX86_64Test, UcomissAddress) {
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), 0));
-  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
-  const char* expected =
-    "ucomiss 0xc(%RDI,%RBX,4), %xmm0\n"
-    "ucomiss 0xc(%RDI,%R9,4), %xmm1\n"
-    "ucomiss 0xc(%RDI,%R9,4), %xmm2\n"
-    "ucomiss (%R13), %xmm3\n"
-    "ucomiss (%R13,%R9,1), %xmm4\n";
-
-  DriverStr(expected, "ucomiss_address");
-}
-
-TEST_F(AssemblerX86_64Test, UcomisdAddress) {
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), 0));
-  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
-  const char* expected =
-    "ucomisd 0xc(%RDI,%RBX,4), %xmm0\n"
-    "ucomisd 0xc(%RDI,%R9,4), %xmm1\n"
-    "ucomisd 0xc(%RDI,%R9,4), %xmm2\n"
-    "ucomisd (%R13), %xmm3\n"
-    "ucomisd (%R13,%R9,1), %xmm4\n";
-
-  DriverStr(expected, "ucomisd_address");
+            "psrldq $2, %xmm15\n", "psrldqi");
 }
 
 std::string x87_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
@@ -1735,22 +1687,28 @@
   DriverFn(&x87_fn, "x87");
 }
 
-TEST_F(AssemblerX86_64Test, FPUIntegerLoad) {
-  GetAssembler()->filds(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
-  GetAssembler()->fildl(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 12));
-  const char* expected =
-      "fildl 0x4(%RSP)\n"
-      "fildll 0xc(%RSP)\n";
-  DriverStr(expected, "FPUIntegerLoad");
+TEST_F(AssemblerX86_64Test, FPUIntegerLoads) {
+  DriverStr(RepeatA(&x86_64::X86_64Assembler::filds,
+                    addresses_singleton_,  // no ext addressing
+                    "fildl {mem}"), "filds");
 }
 
-TEST_F(AssemblerX86_64Test, FPUIntegerStore) {
-  GetAssembler()->fistps(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 16));
-  GetAssembler()->fistpl(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 24));
-  const char* expected =
-      "fistpl 0x10(%RSP)\n"
-      "fistpll 0x18(%RSP)\n";
-  DriverStr(expected, "FPUIntegerStore");
+TEST_F(AssemblerX86_64Test, FPUIntegerLoadl) {
+  DriverStr(RepeatA(&x86_64::X86_64Assembler::fildl,
+                    addresses_singleton_,  // no ext addressing
+                    "fildll {mem}"), "fildl");
+}
+
+TEST_F(AssemblerX86_64Test, FPUIntegerStores) {
+  DriverStr(RepeatA(&x86_64::X86_64Assembler::fistps,
+                    addresses_singleton_,  // no ext addressing
+                    "fistpl {mem}"), "fistps");
+}
+
+TEST_F(AssemblerX86_64Test, FPUIntegerStorel) {
+  DriverStr(RepeatA(&x86_64::X86_64Assembler::fistpl,
+                    addresses_singleton_,  // no ext addressing
+                    "fistpll {mem}"), "fistpl");
 }
 
 TEST_F(AssemblerX86_64Test, Call) {
@@ -1762,13 +1720,15 @@
 }
 
 TEST_F(AssemblerX86_64Test, Enter) {
-  DriverStr(RepeatI(&x86_64::X86_64Assembler::enter, 2U  /* 16b immediate */, "enter ${imm}, $0",
-                    true  /* Only non-negative number */), "enter");
+  DriverStr(RepeatI(&x86_64::X86_64Assembler::enter,
+                    /*imm_bytes*/ 2U,
+                    "enter ${imm}, $0", /*non-negative*/ true), "enter");
 }
 
 TEST_F(AssemblerX86_64Test, RetImm) {
-  DriverStr(RepeatI(&x86_64::X86_64Assembler::ret, 2U  /* 16b immediate */, "ret ${imm}",
-                    true  /* Only non-negative number */), "reti");
+  DriverStr(RepeatI(&x86_64::X86_64Assembler::ret,
+                    /*imm_bytes*/ 2U,
+                    "ret ${imm}", /*non-negative*/ true), "ret");
 }
 
 std::string ret_and_leave_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
@@ -1801,18 +1761,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, BsflAddress) {
-  GetAssembler()->bsfl(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsfl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsfl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "bsfl 0xc(%RDI,%RBX,4), %R10d\n"
-    "bsfl 0xc(%R10,%RBX,4), %edi\n"
-    "bsfl 0xc(%RDI,%R9,4), %edi\n";
-
-  DriverStr(expected, "bsfl_address");
+  DriverStr(RepeatrA(&x86_64::X86_64Assembler::bsfl, "bsfl {mem}, %{reg}"), "bsfl_address");
 }
 
 TEST_F(AssemblerX86_64Test, Bsfq) {
@@ -1820,18 +1769,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, BsfqAddress) {
-  GetAssembler()->bsfq(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsfq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsfq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "bsfq 0xc(%RDI,%RBX,4), %R10\n"
-    "bsfq 0xc(%R10,%RBX,4), %RDI\n"
-    "bsfq 0xc(%RDI,%R9,4), %RDI\n";
-
-  DriverStr(expected, "bsfq_address");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::bsfq, "bsfq {mem}, %{reg}"), "bsfq_address");
 }
 
 TEST_F(AssemblerX86_64Test, Bsrl) {
@@ -1839,18 +1777,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, BsrlAddress) {
-  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "bsrl 0xc(%RDI,%RBX,4), %R10d\n"
-    "bsrl 0xc(%R10,%RBX,4), %edi\n"
-    "bsrl 0xc(%RDI,%R9,4), %edi\n";
-
-  DriverStr(expected, "bsrl_address");
+  DriverStr(RepeatrA(&x86_64::X86_64Assembler::bsrl, "bsrl {mem}, %{reg}"), "bsrl_address");
 }
 
 TEST_F(AssemblerX86_64Test, Bsrq) {
@@ -1858,18 +1785,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, BsrqAddress) {
-  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "bsrq 0xc(%RDI,%RBX,4), %R10\n"
-    "bsrq 0xc(%R10,%RBX,4), %RDI\n"
-    "bsrq 0xc(%RDI,%R9,4), %RDI\n";
-
-  DriverStr(expected, "bsrq_address");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::bsrq, "bsrq {mem}, %{reg}"), "bsrq_address");
 }
 
 TEST_F(AssemblerX86_64Test, Popcntl) {
@@ -1877,18 +1793,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, PopcntlAddress) {
-  GetAssembler()->popcntl(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->popcntl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->popcntl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "popcntl 0xc(%RDI,%RBX,4), %R10d\n"
-    "popcntl 0xc(%R10,%RBX,4), %edi\n"
-    "popcntl 0xc(%RDI,%R9,4), %edi\n";
-
-  DriverStr(expected, "popcntl_address");
+  DriverStr(RepeatrA(&x86_64::X86_64Assembler::popcntl, "popcntl {mem}, %{reg}"), "popcntl_address");
 }
 
 TEST_F(AssemblerX86_64Test, Popcntq) {
@@ -1896,18 +1801,7 @@
 }
 
 TEST_F(AssemblerX86_64Test, PopcntqAddress) {
-  GetAssembler()->popcntq(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->popcntq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
-  GetAssembler()->popcntq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
-      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
-  const char* expected =
-    "popcntq 0xc(%RDI,%RBX,4), %R10\n"
-    "popcntq 0xc(%R10,%RBX,4), %RDI\n"
-    "popcntq 0xc(%RDI,%R9,4), %RDI\n";
-
-  DriverStr(expected, "popcntq_address");
+  DriverStr(RepeatRA(&x86_64::X86_64Assembler::popcntq, "popcntq {mem}, %{reg}"), "popcntq_address");
 }
 
 TEST_F(AssemblerX86_64Test, CmovlAddress) {
@@ -1921,7 +1815,6 @@
     "cmovzl 0xc(%RDI,%RBX,4), %R10d\n"
     "cmovnzl 0xc(%R10,%RBX,4), %edi\n"
     "cmovzl 0xc(%RDI,%R9,4), %edi\n";
-
   DriverStr(expected, "cmovl_address");
 }
 
@@ -1936,7 +1829,6 @@
     "cmovzq 0xc(%RDI,%RBX,4), %R10\n"
     "cmovnzq 0xc(%R10,%RBX,4), %rdi\n"
     "cmovzq 0xc(%RDI,%R9,4), %rdi\n";
-
   DriverStr(expected, "cmovq_address");
 }
 
@@ -2050,52 +1942,21 @@
 }
 
 TEST_F(AssemblerX86_64Test, Cmpb) {
-  GetAssembler()->cmpb(x86_64::Address(x86_64::CpuRegister(x86_64::RDI), 128),
-                       x86_64::Immediate(0));
-  const char* expected = "cmpb $0, 128(%RDI)\n";
-  DriverStr(expected, "cmpb");
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::cmpb,
+                     /*imm_bytes*/ 1U,
+                     "cmpb ${imm}, {mem}"), "cmpb");
 }
 
 TEST_F(AssemblerX86_64Test, TestbAddressImmediate) {
-  GetAssembler()->testb(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
-                      x86_64::CpuRegister(x86_64::RBX),
-                      x86_64::TIMES_4,
-                      12),
-      x86_64::Immediate(1));
-  GetAssembler()->testb(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RSP), FrameOffset(7)),
-      x86_64::Immediate(-128));
-  GetAssembler()->testb(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RBX), MemberOffset(130)),
-      x86_64::Immediate(127));
-  const char* expected =
-      "testb $1, 0xc(%RDI,%RBX,4)\n"
-      "testb $-128, 0x7(%RSP)\n"
-      "testb $127, 0x82(%RBX)\n";
-
-  DriverStr(expected, "TestbAddressImmediate");
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::testb,
+                     /*imm_bytes*/ 1U,
+                     "testb ${imm}, {mem}"), "testbi");
 }
 
 TEST_F(AssemblerX86_64Test, TestlAddressImmediate) {
-  GetAssembler()->testl(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RDI),
-                      x86_64::CpuRegister(x86_64::RBX),
-                      x86_64::TIMES_4,
-                      12),
-      x86_64::Immediate(1));
-  GetAssembler()->testl(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RSP), FrameOffset(7)),
-      x86_64::Immediate(-100000));
-  GetAssembler()->testl(
-      x86_64::Address(x86_64::CpuRegister(x86_64::RBX), MemberOffset(130)),
-      x86_64::Immediate(77777777));
-  const char* expected =
-      "testl $1, 0xc(%RDI,%RBX,4)\n"
-      "testl $-100000, 0x7(%RSP)\n"
-      "testl $77777777, 0x82(%RBX)\n";
-
-  DriverStr(expected, "TestlAddressImmediate");
+  DriverStr(RepeatAI(&x86_64::X86_64Assembler::testl,
+                     /*imm_bytes*/ 4U,
+                     "testl ${imm}, {mem}"), "testli");
 }
 
 class JNIMacroAssemblerX86_64Test : public JNIMacroAssemblerTest<x86_64::X86_64JNIMacroAssembler> {
@@ -2150,15 +2011,15 @@
 
   // Construct assembly text counterpart.
   std::ostringstream str;
-  // 1) Push the spill_regs.
+  // (1) Push the spill_regs.
   str << "pushq %rsi\n";
   str << "pushq %r10\n";
-  // 2) Move down the stack pointer.
+  // (2) Move down the stack pointer.
   ssize_t displacement = static_cast<ssize_t>(frame_size) - (spill_regs.size() * 8 + 8);
   str << "subq $" << displacement << ", %rsp\n";
-  // 3) Store method reference.
+  // (3) Store method reference.
   str << "movq %rdi, (%rsp)\n";
-  // 4) Entry spills.
+  // (4) Entry spills.
   str << "movq %rax, " << frame_size + 0 << "(%rsp)\n";
   str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n";
   str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n";
@@ -2186,10 +2047,10 @@
 
   // Construct assembly text counterpart.
   std::ostringstream str;
-  // 1) Move up the stack pointer.
+  // (1) Move up the stack pointer.
   ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8;
   str << "addq $" << displacement << ", %rsp\n";
-  // 2) Pop spill regs.
+  // (2) Pop spill regs.
   str << "popq %r10\n";
   str << "popq %rsi\n";
   str << "ret\n";
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 21d3895..7b46531 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -712,6 +712,10 @@
     }
   }
 
+  bool VerifyProfileData() {
+    return profile_compilation_info_->VerifyProfileData(dex_files_);
+  }
+
   void ParseInstructionSetVariant(const StringPiece& option, ParserOptions* parser_options) {
     DCHECK(option.starts_with("--instruction-set-variant="));
     StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
@@ -1353,7 +1357,7 @@
       DCHECK(!oat_filenames_.empty());
       for (const char* oat_filename : oat_filenames_) {
         std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename));
-        if (oat_file.get() == nullptr) {
+        if (oat_file == nullptr) {
           PLOG(ERROR) << "Failed to create oat file: " << oat_filename;
           return false;
         }
@@ -1383,7 +1387,7 @@
           vdex_files_.push_back(std::move(vdex_file));
         } else {
           std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
-          if (vdex_file.get() == nullptr) {
+          if (vdex_file == nullptr) {
             PLOG(ERROR) << "Failed to open vdex file: " << vdex_filename;
             return false;
           }
@@ -1397,13 +1401,15 @@
       }
     } else {
       std::unique_ptr<File> oat_file(new File(oat_fd_, oat_location_, /* check_usage */ true));
-      if (oat_file.get() == nullptr) {
+      if (oat_file == nullptr) {
         PLOG(ERROR) << "Failed to create oat file: " << oat_location_;
         return false;
       }
       oat_file->DisableAutoClose();
       if (oat_file->SetLength(0) != 0) {
         PLOG(WARNING) << "Truncating oat file " << oat_location_ << " failed.";
+        oat_file->Erase();
+        return false;
       }
       oat_files_.push_back(std::move(oat_file));
 
@@ -1432,7 +1438,7 @@
       DCHECK_NE(output_vdex_fd_, -1);
       std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
       std::unique_ptr<File> vdex_file(new File(output_vdex_fd_, vdex_location, /* check_usage */ true));
-      if (vdex_file.get() == nullptr) {
+      if (vdex_file == nullptr) {
         PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
         return false;
       }
@@ -1442,6 +1448,7 @@
       } else {
         if (vdex_file->SetLength(0) != 0) {
           PLOG(ERROR) << "Truncating vdex file " << vdex_location << " failed.";
+          vdex_file->Erase();
           return false;
         }
       }
@@ -2305,6 +2312,10 @@
     return DoProfileGuidedOptimizations();
   }
 
+  bool DoOatLayoutOptimizations() const {
+    return DoProfileGuidedOptimizations();
+  }
+
   bool DoEagerUnquickeningOfVdex() const {
     // DexLayout can invalidate the vdex metadata, so we need to unquicken
     // the vdex file eagerly, before passing it to dexlayout.
@@ -2517,9 +2528,11 @@
                                                              compiler_options_.get(),
                                                              oat_file.get()));
       elf_writers_.back()->Start();
-      const bool do_dexlayout = DoDexLayoutOptimizations();
+      const bool do_oat_writer_layout = DoDexLayoutOptimizations() || DoOatLayoutOptimizations();
       oat_writers_.emplace_back(new linker::OatWriter(
-          IsBootImage(), timings_, do_dexlayout ? profile_compilation_info_.get() : nullptr));
+          IsBootImage(),
+          timings_,
+          do_oat_writer_layout ? profile_compilation_info_.get() : nullptr));
     }
   }
 
@@ -3103,6 +3116,19 @@
     return setup_code;
   }
 
+  // TODO: Due to the cyclic dependencies, profile loading and verifying are
+  // being done separately. Refactor and place the two next to each other.
+  // If verification fails, we don't abort the compilation and instead log an
+  // error.
+  // TODO(b/62602192, b/65260586): We should consider aborting compilation when
+  // the profile verification fails.
+  // Note: If dex2oat fails, installd will remove the oat files causing the app
+  // to fallback to apk with possible in-memory extraction. We want to avoid
+  // that, and thus we're lenient towards profile corruptions.
+  if (dex2oat->UseProfile()) {
+    dex2oat->VerifyProfileData();
+  }
+
   // Helps debugging on device. Can be used to determine which dalvikvm instance invoked a dex2oat
   // instance. Used by tools/bisection_search/bisection_search.py.
   VLOG(compiler) << "Running dex2oat (parent PID = " << getppid() << ")";
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 71f1fa6..492c76b 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -302,8 +302,8 @@
       }
 
       for (size_t i = 0, size = oat_files.size(); i != size; ++i) {
-        linker::MultiOatRelativePatcher patcher(driver->GetInstructionSet(),
-                                                driver->GetInstructionSetFeatures());
+        MultiOatRelativePatcher patcher(driver->GetInstructionSet(),
+                                        driver->GetInstructionSetFeatures());
         OatWriter* const oat_writer = oat_writers[i].get();
         ElfWriter* const elf_writer = elf_writers[i].get();
         std::vector<const DexFile*> cur_dex_files(1u, class_path[i]);
diff --git a/dex2oat/linker/multi_oat_relative_patcher_test.cc b/dex2oat/linker/multi_oat_relative_patcher_test.cc
index 1b2d43e..ca9c5f1 100644
--- a/dex2oat/linker/multi_oat_relative_patcher_test.cc
+++ b/dex2oat/linker/multi_oat_relative_patcher_test.cc
@@ -19,6 +19,7 @@
 #include "compiled_method.h"
 #include "debug/method_debug_info.h"
 #include "gtest/gtest.h"
+#include "linker/linker_patch.h"
 #include "linker/vector_output_stream.h"
 
 namespace art {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 51c2a03..a80dbf6 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -16,6 +16,7 @@
 
 #include "oat_writer.h"
 
+#include <algorithm>
 #include <unistd.h>
 #include <zlib.h>
 
@@ -29,7 +30,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "class_table-inl.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "debug/method_debug_info.h"
 #include "dex/verification_results.h"
 #include "dex_file-inl.h"
@@ -43,6 +44,7 @@
 #include "image_writer.h"
 #include "linker/buffered_output_stream.h"
 #include "linker/file_output_stream.h"
+#include "linker/linker_patch.h"
 #include "linker/method_bss_mapping_encoder.h"
 #include "linker/multi_oat_relative_patcher.h"
 #include "linker/output_stream.h"
@@ -68,6 +70,18 @@
 // If we write dex layout info in the oat file.
 static constexpr bool kWriteDexLayoutInfo = true;
 
+// Force the OAT method layout to be sorted-by-name instead of
+// the default (class_def_idx, method_idx).
+//
+// Otherwise if profiles are used, that will act as
+// the primary sort order.
+//
+// A bit easier to use for development since oatdump can easily
+// show that things are being re-ordered when two methods aren't adjacent.
+static constexpr bool kOatWriterForceOatCodeLayout = false;
+
+static constexpr bool kOatWriterDebugOatCodeLayout = false;
+
 typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
 
 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
@@ -866,158 +880,433 @@
   size_t compiled_methods_with_code_;
 };
 
-class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
+// CompiledMethod + metadata required to do ordered method layout.
+//
+// See also OrderedMethodVisitor.
+struct OatWriter::OrderedMethodData {
+  ProfileCompilationInfo::MethodHotness method_hotness;
+  OatClass* oat_class;
+  CompiledMethod* compiled_method;
+  MethodReference method_reference;
+  size_t method_offsets_index;
+
+  size_t class_def_index;
+  uint32_t access_flags;
+  const DexFile::CodeItem* code_item;
+
+  // A value of -1 denotes missing debug info
+  static constexpr size_t kDebugInfoIdxInvalid = static_cast<size_t>(-1);
+  // Index into writer_->method_info_
+  size_t debug_info_idx;
+
+  bool HasDebugInfo() const {
+    return debug_info_idx != kDebugInfoIdxInvalid;
+  }
+
+  // Bin each method according to the profile flags.
+  //
+  // Groups by e.g.
+  //  -- not hot at all
+  //  -- hot
+  //  -- hot and startup
+  //  -- hot and post-startup
+  //  -- hot and startup and poststartup
+  //  -- startup
+  //  -- startup and post-startup
+  //  -- post-startup
+  //
+  // (See MethodHotness enum definition for up-to-date binning order.)
+  bool operator<(const OrderedMethodData& other) const {
+    if (kOatWriterForceOatCodeLayout) {
+      // Development flag: Override default behavior by sorting by name.
+
+      std::string name = method_reference.PrettyMethod();
+      std::string other_name = other.method_reference.PrettyMethod();
+      return name < other_name;
+    }
+
+    // Use the profile's method hotness to determine sort order.
+    if (GetMethodHotnessOrder() < other.GetMethodHotnessOrder()) {
+      return true;
+    }
+
+    // Default: retain the original order.
+    return false;
+  }
+
+ private:
+  // Used to determine relative order for OAT code layout when determining
+  // binning.
+  size_t GetMethodHotnessOrder() const {
+    bool hotness[] = {
+      method_hotness.IsHot(),
+      method_hotness.IsStartup(),
+      method_hotness.IsPostStartup()
+    };
+
+
+    // Note: Bin-to-bin order does not matter. If the kernel does or does not read-ahead
+    // any memory, it only goes into the buffer cache and does not grow the PSS until the first
+    // time that memory is referenced in the process.
+
+    size_t hotness_bits = 0;
+    for (size_t i = 0; i < arraysize(hotness); ++i) {
+      if (hotness[i]) {
+        hotness_bits |= (1 << i);
+      }
+    }
+
+    if (kIsDebugBuild) {
+      // Check for bins that are always-empty given a real profile.
+      if (method_hotness.IsHot() &&
+              !method_hotness.IsStartup() && !method_hotness.IsPostStartup()) {
+        std::string name = method_reference.PrettyMethod();
+        LOG(WARNING) << "Method " << name << " had a Hot method that wasn't marked "
+                     << "either start-up or post-startup. Possible corrupted profile?";
+        // This is not fatal, so only warn.
+      }
+    }
+
+    return hotness_bits;
+  }
+};
+
+// Given a queue of CompiledMethod in some total order,
+// visit each one in that order.
+class OatWriter::OrderedMethodVisitor {
  public:
-  InitCodeMethodVisitor(OatWriter* writer, size_t offset)
-      : InitCodeMethodVisitor(writer, offset, writer->GetCompilerDriver()->GetCompilerOptions()) {}
+  explicit OrderedMethodVisitor(OrderedMethodList ordered_methods)
+      : ordered_methods_(std::move(ordered_methods)) {
+  }
+
+  virtual ~OrderedMethodVisitor() {}
+
+  // Invoke VisitMethod in the order of `ordered_methods`, then invoke VisitComplete.
+  bool Visit() REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (!VisitStart()) {
+      return false;
+    }
+
+    for (const OrderedMethodData& method_data : ordered_methods_)  {
+      if (!VisitMethod(method_data)) {
+        return false;
+      }
+    }
+
+    return VisitComplete();
+  }
+
+  // Invoked once at the beginning, prior to visiting anything else.
+  //
+  // Return false to abort further visiting.
+  virtual bool VisitStart() { return true; }
+
+  // Invoked repeatedly in the order specified by `ordered_methods`.
+  //
+  // Return false to short-circuit and to stop visiting further methods.
+  virtual bool VisitMethod(const OrderedMethodData& method_data)
+      REQUIRES_SHARED(Locks::mutator_lock_)  = 0;
+
+  // Invoked once at the end, after every other method has been successfully visited.
+  //
+  // Return false to indicate the overall `Visit` has failed.
+  virtual bool VisitComplete() = 0;
+
+  OrderedMethodList ReleaseOrderedMethods() {
+    return std::move(ordered_methods_);
+  }
+
+ private:
+  // List of compiled methods, sorted by the order defined in OrderedMethodData.
+  // Methods can be inserted more than once in case of duplicated methods.
+  OrderedMethodList ordered_methods_;
+};
+
+// Visit every compiled method in order to determine its order within the OAT file.
+// Methods from the same class do not need to be adjacent in the OAT code.
+class OatWriter::LayoutCodeMethodVisitor : public OatDexMethodVisitor {
+ public:
+  LayoutCodeMethodVisitor(OatWriter* writer, size_t offset)
+      : OatDexMethodVisitor(writer, offset) {
+  }
 
   bool EndClass() OVERRIDE {
     OatDexMethodVisitor::EndClass();
-    if (oat_class_index_ == writer_->oat_classes_.size()) {
-      offset_ = relative_patcher_->ReserveSpaceEnd(offset_);
-      if (generate_debug_info_) {
-        std::vector<debug::MethodDebugInfo> thunk_infos =
-            relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
-        writer_->method_info_.insert(writer_->method_info_.end(),
-                                     std::make_move_iterator(thunk_infos.begin()),
-                                     std::make_move_iterator(thunk_infos.end()));
-      }
-    }
     return true;
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
-      REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitMethod(size_t class_def_method_index,
+                   const ClassDataItemIterator& it)
+      OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)  {
+    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
     if (HasCompiledCode(compiled_method)) {
-      // Derived from CompiledMethod.
-      uint32_t quick_code_offset = 0;
+      size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid;
 
-      ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
-      uint32_t code_size = quick_code.size() * sizeof(uint8_t);
-      uint32_t thumb_offset = compiled_method->CodeDelta();
+      {
+        const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
+        ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+        uint32_t code_size = quick_code.size() * sizeof(uint8_t);
 
-      // Deduplicate code arrays if we are not producing debuggable code.
-      bool deduped = true;
-      MethodReference method_ref(dex_file_, it.GetMemberIndex());
-      if (debuggable_) {
-        quick_code_offset = relative_patcher_->GetOffset(method_ref);
-        if (quick_code_offset != 0u) {
-          // Duplicate methods, we want the same code for both of them so that the oat writer puts
-          // the same code in both ArtMethods so that we do not get different oat code at runtime.
-        } else {
-          quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
-          deduped = false;
+        // Debug method info must be pushed in the original order
+        // (i.e. all methods from the same class must be adjacent in the debug info sections)
+        // ElfCompilationUnitWriter::Write requires this.
+        if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
+          debug::MethodDebugInfo info = debug::MethodDebugInfo();
+          writer_->method_info_.push_back(info);
+
+          // The debug info is filled in LayoutReserveOffsetCodeMethodVisitor
+          // once we know the offsets.
+          //
+          // Store the index into writer_->method_info_ since future push-backs
+          // could reallocate and change the underlying data address.
+          debug_info_idx = writer_->method_info_.size() - 1;
         }
+      }
+
+      MethodReference method_ref(dex_file_, it.GetMemberIndex());
+
+      // Lookup method hotness from profile, if available.
+      // Otherwise assume a default of none-hotness.
+      ProfileCompilationInfo::MethodHotness method_hotness =
+          writer_->profile_compilation_info_ != nullptr
+              ? writer_->profile_compilation_info_->GetMethodHotness(method_ref)
+              : ProfileCompilationInfo::MethodHotness();
+
+      // Handle duplicate methods by pushing them repeatedly.
+      OrderedMethodData method_data = {
+          method_hotness,
+          oat_class,
+          compiled_method,
+          method_ref,
+          method_offsets_index_,
+          class_def_index_,
+          it.GetMethodAccessFlags(),
+          it.GetMethodCodeItem(),
+          debug_info_idx
+      };
+      ordered_methods_.push_back(method_data);
+
+      method_offsets_index_++;
+    }
+
+    return true;
+  }
+
+  OrderedMethodList ReleaseOrderedMethods() {
+    if (kOatWriterForceOatCodeLayout || writer_->profile_compilation_info_ != nullptr) {
+      // Sort by the method ordering criteria (in OrderedMethodData).
+      // Since most methods will have the same ordering criteria,
+      // we preserve the original insertion order within the same sort order.
+      std::stable_sort(ordered_methods_.begin(), ordered_methods_.end());
+    } else {
+      // The profile-less behavior is as if every method had 0 hotness
+      // associated with it.
+      //
+      // Since sorting all methods with hotness=0 should give back the same
+      // order as before, don't do anything.
+      DCHECK(std::is_sorted(ordered_methods_.begin(), ordered_methods_.end()));
+    }
+
+    return std::move(ordered_methods_);
+  }
+
+ private:
+  // List of compiled methods, later to be sorted by order defined in OrderedMethodData.
+  // Methods can be inserted more than once in case of duplicated methods.
+  OrderedMethodList ordered_methods_;
+};
+
+// Given a method order, reserve the offsets for each CompiledMethod in the OAT file.
+class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisitor {
+ public:
+  LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
+                                       size_t offset,
+                                       OrderedMethodList ordered_methods)
+      : LayoutReserveOffsetCodeMethodVisitor(writer,
+                                             offset,
+                                             writer->GetCompilerDriver()->GetCompilerOptions(),
+                                             std::move(ordered_methods)) {
+  }
+
+  virtual bool VisitComplete() OVERRIDE {
+    offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
+    if (generate_debug_info_) {
+      std::vector<debug::MethodDebugInfo> thunk_infos =
+          relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
+      writer_->method_info_.insert(writer_->method_info_.end(),
+                                   std::make_move_iterator(thunk_infos.begin()),
+                                   std::make_move_iterator(thunk_infos.end()));
+    }
+    return true;
+  }
+
+  virtual bool VisitMethod(const OrderedMethodData& method_data)
+      OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    OatClass* oat_class = method_data.oat_class;
+    CompiledMethod* compiled_method = method_data.compiled_method;
+    const MethodReference& method_ref = method_data.method_reference;
+    uint16_t method_offsets_index_ = method_data.method_offsets_index;
+    size_t class_def_index = method_data.class_def_index;
+    uint32_t access_flags = method_data.access_flags;
+    const DexFile::CodeItem* code_item = method_data.code_item;
+    bool has_debug_info = method_data.HasDebugInfo();
+    size_t debug_info_idx = method_data.debug_info_idx;
+
+    DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
+
+    // Derived from CompiledMethod.
+    uint32_t quick_code_offset = 0;
+
+    ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+    uint32_t code_size = quick_code.size() * sizeof(uint8_t);
+    uint32_t thumb_offset = compiled_method->CodeDelta();
+
+    // Deduplicate code arrays if we are not producing debuggable code.
+    bool deduped = true;
+    if (debuggable_) {
+      quick_code_offset = relative_patcher_->GetOffset(method_ref);
+      if (quick_code_offset != 0u) {
+        // Duplicate methods, we want the same code for both of them so that the oat writer puts
+        // the same code in both ArtMethods so that we do not get different oat code at runtime.
       } else {
-        quick_code_offset = dedupe_map_.GetOrCreate(
-            compiled_method,
-            [this, &deduped, compiled_method, &it, thumb_offset]() {
-              deduped = false;
-              return NewQuickCodeOffset(compiled_method, it, thumb_offset);
-            });
+        quick_code_offset = NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
+        deduped = false;
       }
 
       if (code_size != 0) {
         if (relative_patcher_->GetOffset(method_ref) != 0u) {
           // TODO: Should this be a hard failure?
           LOG(WARNING) << "Multiple definitions of "
-              << method_ref.PrettyMethod()
+              << method_ref.dex_file->PrettyMethod(method_ref.index)
               << " offsets " << relative_patcher_->GetOffset(method_ref)
               << " " << quick_code_offset;
         } else {
           relative_patcher_->SetOffset(method_ref, quick_code_offset);
         }
       }
+    } else {
+      quick_code_offset = dedupe_map_.GetOrCreate(
+          compiled_method,
+          [this, &deduped, compiled_method, &method_ref, thumb_offset]() {
+            deduped = false;
+            return NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
+          });
+    }
 
-      // Update quick method header.
-      DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
-      OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
-      uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
-      uint32_t method_info_offset = method_header->GetMethodInfoOffset();
-      // The code offset was 0 when the mapping/vmap table offset was set, so it's set
-      // to 0-offset and we need to adjust it by code_offset.
-      uint32_t code_offset = quick_code_offset - thumb_offset;
-      if (!compiled_method->GetQuickCode().empty()) {
-        // If the code is compiled, we write the offset of the stack map relative
-        // to the code,
-        if (vmap_table_offset != 0u) {
-          vmap_table_offset += code_offset;
-          DCHECK_LT(vmap_table_offset, code_offset);
-        }
-        if (method_info_offset != 0u) {
-          method_info_offset += code_offset;
-          DCHECK_LT(method_info_offset, code_offset);
-        }
+    if (code_size != 0) {
+      if (relative_patcher_->GetOffset(method_ref) != 0u) {
+        // TODO: Should this be a hard failure?
+        LOG(WARNING) << "Multiple definitions of "
+            << method_ref.dex_file->PrettyMethod(method_ref.index)
+            << " offsets " << relative_patcher_->GetOffset(method_ref)
+            << " " << quick_code_offset;
       } else {
-        CHECK(!kIsVdexEnabled);
-        // We write the offset of the quickening info relative to the code.
+        relative_patcher_->SetOffset(method_ref, quick_code_offset);
+      }
+    }
+
+    // Update quick method header.
+    DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
+    OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
+    uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
+    uint32_t method_info_offset = method_header->GetMethodInfoOffset();
+    // The code offset was 0 when the mapping/vmap table offset was set, so it's set
+    // to 0-offset and we need to adjust it by code_offset.
+    uint32_t code_offset = quick_code_offset - thumb_offset;
+    if (!compiled_method->GetQuickCode().empty()) {
+      // If the code is compiled, we write the offset of the stack map relative
+      // to the code,
+      if (vmap_table_offset != 0u) {
         vmap_table_offset += code_offset;
         DCHECK_LT(vmap_table_offset, code_offset);
       }
-      uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
-      uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
-      uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
-      *method_header = OatQuickMethodHeader(vmap_table_offset,
-                                            method_info_offset,
-                                            frame_size_in_bytes,
-                                            core_spill_mask,
-                                            fp_spill_mask,
-                                            code_size);
+      if (method_info_offset != 0u) {
+        method_info_offset += code_offset;
+        DCHECK_LT(method_info_offset, code_offset);
+      }
+    } else {
+      CHECK(!kIsVdexEnabled);
+      // We write the offset of the quickening info relative to the code.
+      vmap_table_offset += code_offset;
+      DCHECK_LT(vmap_table_offset, code_offset);
+    }
+    uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+    uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
+    uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
+    *method_header = OatQuickMethodHeader(vmap_table_offset,
+                                          method_info_offset,
+                                          frame_size_in_bytes,
+                                          core_spill_mask,
+                                          fp_spill_mask,
+                                          code_size);
 
-      if (!deduped) {
-        // Update offsets. (Checksum is updated when writing.)
-        offset_ += sizeof(*method_header);  // Method header is prepended before code.
-        offset_ += code_size;
-        // Record absolute patch locations.
-        if (!compiled_method->GetPatches().empty()) {
-          uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
-          for (const LinkerPatch& patch : compiled_method->GetPatches()) {
-            if (!patch.IsPcRelative()) {
-              writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
-            }
+    if (!deduped) {
+      // Update offsets. (Checksum is updated when writing.)
+      offset_ += sizeof(*method_header);  // Method header is prepended before code.
+      offset_ += code_size;
+      // Record absolute patch locations.
+      if (!compiled_method->GetPatches().empty()) {
+        uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
+        for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+          if (!patch.IsPcRelative()) {
+            writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
           }
         }
       }
-
-      // Exclude quickened dex methods (code_size == 0) since they have no native code.
-      if (generate_debug_info_ && code_size != 0) {
-        bool has_code_info = method_header->IsOptimized();
-        // Record debug information for this function if we are doing that.
-        debug::MethodDebugInfo info = {};
-        DCHECK(info.trampoline_name.empty());
-        info.dex_file = dex_file_;
-        info.class_def_index = class_def_index_;
-        info.dex_method_index = it.GetMemberIndex();
-        info.access_flags = it.GetMethodAccessFlags();
-        info.code_item = it.GetMethodCodeItem();
-        info.isa = compiled_method->GetInstructionSet();
-        info.deduped = deduped;
-        info.is_native_debuggable = native_debuggable_;
-        info.is_optimized = method_header->IsOptimized();
-        info.is_code_address_text_relative = true;
-        info.code_address = code_offset - executable_offset_;
-        info.code_size = code_size;
-        info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
-        info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
-        info.cfi = compiled_method->GetCFIInfo();
-        writer_->method_info_.push_back(info);
-      }
-
-      DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
-      OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
-      offsets->code_offset_ = quick_code_offset;
-      ++method_offsets_index_;
     }
 
+    // Exclude quickened dex methods (code_size == 0) since they have no native code.
+    if (generate_debug_info_ && code_size != 0) {
+      DCHECK(has_debug_info);
+
+      bool has_code_info = method_header->IsOptimized();
+      // Record debug information for this function if we are doing that.
+      debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx];
+      DCHECK(info.trampoline_name.empty());
+      info.dex_file = method_ref.dex_file;
+      info.class_def_index = class_def_index;
+      info.dex_method_index = method_ref.index;
+      info.access_flags = access_flags;
+      info.code_item = code_item;
+      info.isa = compiled_method->GetInstructionSet();
+      info.deduped = deduped;
+      info.is_native_debuggable = native_debuggable_;
+      info.is_optimized = method_header->IsOptimized();
+      info.is_code_address_text_relative = true;
+      info.code_address = code_offset - executable_offset_;
+      info.code_size = code_size;
+      info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+      info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
+      info.cfi = compiled_method->GetCFIInfo();
+    } else {
+      DCHECK(!has_debug_info);
+    }
+
+    DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
+    OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
+    offsets->code_offset_ = quick_code_offset;
+
     return true;
   }
 
+  size_t GetOffset() const {
+    return offset_;
+  }
+
  private:
-  InitCodeMethodVisitor(OatWriter* writer, size_t offset, const CompilerOptions& compiler_options)
-      : OatDexMethodVisitor(writer, offset),
+  LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
+                                       size_t offset,
+                                       const CompilerOptions& compiler_options,
+                                       OrderedMethodList ordered_methods)
+      : OrderedMethodVisitor(std::move(ordered_methods)),
+        writer_(writer),
+        offset_(offset),
         relative_patcher_(writer->relative_patcher_),
         executable_offset_(writer->oat_header_->GetExecutableOffset()),
         debuggable_(compiler_options.GetDebuggable()),
@@ -1048,22 +1337,26 @@
   };
 
   uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
-                              const ClassDataItemIterator& it,
+                              const MethodReference& method_ref,
                               uint32_t thumb_offset) {
-    offset_ = relative_patcher_->ReserveSpace(
-        offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
+    offset_ = relative_patcher_->ReserveSpace(offset_, compiled_method, method_ref);
     offset_ += CodeAlignmentSize(offset_, *compiled_method);
     DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
     return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
   }
 
+  OatWriter* writer_;
+
+  // Offset of the code of the compiled methods.
+  size_t offset_;
+
   // Deduplication is already done on a pointer basis by the compiler driver,
   // so we can simply compare the pointers to find out if things are duplicated.
   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
 
   // Cache writer_'s members and compiler options.
-  linker::MultiOatRelativePatcher* relative_patcher_;
+  MultiOatRelativePatcher* relative_patcher_;
   uint32_t executable_offset_;
   const bool debuggable_;
   const bool native_debuggable_;
@@ -1295,19 +1588,24 @@
   std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
 };
 
-class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
+class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
  public:
-  WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
-                         size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
-      : OatDexMethodVisitor(writer, relative_offset),
+  WriteCodeMethodVisitor(OatWriter* writer,
+                         OutputStream* out,
+                         const size_t file_offset,
+                         size_t relative_offset,
+                         OrderedMethodList ordered_methods)
+      : OrderedMethodVisitor(std::move(ordered_methods)),
+        writer_(writer),
+        offset_(relative_offset),
+        dex_file_(nullptr),
         pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
         class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
         out_(out),
         file_offset_(file_offset),
-        soa_(Thread::Current()),
-        no_thread_suspension_("OatWriter patching"),
         class_linker_(Runtime::Current()->GetClassLinker()),
-        dex_cache_(nullptr) {
+        dex_cache_(nullptr),
+        no_thread_suspension_("OatWriter patching") {
     patched_code_.reserve(16 * KB);
     if (writer_->HasBootImage()) {
       // If we're creating the image, the address space must be ready so that we can apply patches.
@@ -1315,12 +1613,17 @@
     }
   }
 
-  ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
+  virtual bool VisitStart() OVERRIDE {
+    return true;
   }
 
-  bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
+  void UpdateDexFileAndDexCache(const DexFile* dex_file)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    OatDexMethodVisitor::StartClass(dex_file, class_def_index);
+    dex_file_ = dex_file;
+
+    // Ordered method visiting is only for compiled methods.
+    DCHECK(writer_->MayHaveCompiledMethods());
+
     if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
       // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
       if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
@@ -1328,198 +1631,212 @@
         DCHECK(dex_cache_ != nullptr);
       }
     }
+  }
+
+  virtual bool VisitComplete() {
+    offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
+    if (UNLIKELY(offset_ == 0u)) {
+      PLOG(ERROR) << "Failed to write final relative call thunks";
+      return false;
+    }
     return true;
   }
 
-  bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
-    bool result = OatDexMethodVisitor::EndClass();
-    if (oat_class_index_ == writer_->oat_classes_.size()) {
-      DCHECK(result);  // OatDexMethodVisitor::EndClass() never fails.
-      offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
-      if (UNLIKELY(offset_ == 0u)) {
-        PLOG(ERROR) << "Failed to write final relative call thunks";
-        result = false;
-      }
-    }
-    return result;
-  }
-
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
+  virtual bool VisitMethod(const OrderedMethodData& method_data) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
-    const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
+    const MethodReference& method_ref = method_data.method_reference;
+    UpdateDexFileAndDexCache(method_ref.dex_file);
+
+    OatClass* oat_class = method_data.oat_class;
+    CompiledMethod* compiled_method = method_data.compiled_method;
+    uint16_t method_offsets_index = method_data.method_offsets_index;
 
     // No thread suspension since dex_cache_ that may get invalidated if that occurs.
     ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
-    if (HasCompiledCode(compiled_method)) {
-      size_t file_offset = file_offset_;
-      OutputStream* out = out_;
+    DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
 
-      ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
-      uint32_t code_size = quick_code.size() * sizeof(uint8_t);
+    // TODO: cleanup DCHECK_OFFSET_ to accept file_offset as parameter.
+    size_t file_offset = file_offset_;  // Used by DCHECK_OFFSET_ macro.
+    OutputStream* out = out_;
 
-      // Deduplicate code arrays.
-      const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
-      if (method_offsets.code_offset_ > offset_) {
-        offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
-        if (offset_ == 0u) {
-          ReportWriteFailure("relative call thunk", it);
+    ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+    uint32_t code_size = quick_code.size() * sizeof(uint8_t);
+
+    // Deduplicate code arrays.
+    const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index];
+    if (method_offsets.code_offset_ > offset_) {
+      offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
+      if (offset_ == 0u) {
+        ReportWriteFailure("relative call thunk", method_ref);
+        return false;
+      }
+      uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
+      if (alignment_size != 0) {
+        if (!writer_->WriteCodeAlignment(out, alignment_size)) {
+          ReportWriteFailure("code alignment padding", method_ref);
           return false;
         }
-        uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
-        if (alignment_size != 0) {
-          if (!writer_->WriteCodeAlignment(out, alignment_size)) {
-            ReportWriteFailure("code alignment padding", it);
-            return false;
-          }
-          offset_ += alignment_size;
-          DCHECK_OFFSET_();
-        }
-        DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
-                             GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
-        DCHECK_EQ(method_offsets.code_offset_,
-                  offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
-            << dex_file_->PrettyMethod(it.GetMemberIndex());
-        const OatQuickMethodHeader& method_header =
-            oat_class->method_headers_[method_offsets_index_];
-        if (!out->WriteFully(&method_header, sizeof(method_header))) {
-          ReportWriteFailure("method header", it);
-          return false;
-        }
-        writer_->size_method_header_ += sizeof(method_header);
-        offset_ += sizeof(method_header);
+        offset_ += alignment_size;
         DCHECK_OFFSET_();
+      }
+      DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
+                           GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
+      DCHECK_EQ(method_offsets.code_offset_,
+                offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
+          << dex_file_->PrettyMethod(method_ref.index);
+      const OatQuickMethodHeader& method_header =
+          oat_class->method_headers_[method_offsets_index];
+      if (!out->WriteFully(&method_header, sizeof(method_header))) {
+        ReportWriteFailure("method header", method_ref);
+        return false;
+      }
+      writer_->size_method_header_ += sizeof(method_header);
+      offset_ += sizeof(method_header);
+      DCHECK_OFFSET_();
 
-        if (!compiled_method->GetPatches().empty()) {
-          patched_code_.assign(quick_code.begin(), quick_code.end());
-          quick_code = ArrayRef<const uint8_t>(patched_code_);
-          for (const LinkerPatch& patch : compiled_method->GetPatches()) {
-            uint32_t literal_offset = patch.LiteralOffset();
-            switch (patch.GetType()) {
-              case LinkerPatch::Type::kMethodBssEntry: {
-                uint32_t target_offset =
-                    writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kCallRelative: {
-                // NOTE: Relative calls across oat files are not supported.
-                uint32_t target_offset = GetTargetOffset(patch);
-                writer_->relative_patcher_->PatchCall(&patched_code_,
-                                                      literal_offset,
-                                                      offset_ + literal_offset,
-                                                      target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kStringRelative: {
-                uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kStringInternTable: {
-                uint32_t target_offset = GetInternTableEntryOffset(patch);
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kStringBssEntry: {
-                StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
-                uint32_t target_offset =
-                    writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kTypeRelative: {
-                uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kTypeClassTable: {
-                uint32_t target_offset = GetClassTableEntryOffset(patch);
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kTypeBssEntry: {
-                TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
-                uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kCall: {
-                uint32_t target_offset = GetTargetOffset(patch);
-                PatchCodeAddress(&patched_code_, literal_offset, target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kMethodRelative: {
-                uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
-              case LinkerPatch::Type::kBakerReadBarrierBranch: {
-                writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
-                                                                        patch,
-                                                                        offset_ + literal_offset);
-                break;
-              }
-              default: {
-                DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
-                break;
-              }
+      if (!compiled_method->GetPatches().empty()) {
+        patched_code_.assign(quick_code.begin(), quick_code.end());
+        quick_code = ArrayRef<const uint8_t>(patched_code_);
+        for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+          uint32_t literal_offset = patch.LiteralOffset();
+          switch (patch.GetType()) {
+            case LinkerPatch::Type::kMethodBssEntry: {
+              uint32_t target_offset =
+                  writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kCallRelative: {
+              // NOTE: Relative calls across oat files are not supported.
+              uint32_t target_offset = GetTargetOffset(patch);
+              writer_->relative_patcher_->PatchCall(&patched_code_,
+                                                    literal_offset,
+                                                    offset_ + literal_offset,
+                                                    target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kStringRelative: {
+              uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kStringInternTable: {
+              uint32_t target_offset = GetInternTableEntryOffset(patch);
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kStringBssEntry: {
+              StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
+              uint32_t target_offset =
+                  writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kTypeRelative: {
+              uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kTypeClassTable: {
+              uint32_t target_offset = GetClassTableEntryOffset(patch);
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kTypeBssEntry: {
+              TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
+              uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kCall: {
+              uint32_t target_offset = GetTargetOffset(patch);
+              PatchCodeAddress(&patched_code_, literal_offset, target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kMethodRelative: {
+              uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
+              writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                   patch,
+                                                                   offset_ + literal_offset,
+                                                                   target_offset);
+              break;
+            }
+            case LinkerPatch::Type::kBakerReadBarrierBranch: {
+              writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
+                                                                      patch,
+                                                                      offset_ + literal_offset);
+              break;
+            }
+            default: {
+              DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
+              break;
             }
           }
         }
-
-        if (!out->WriteFully(quick_code.data(), code_size)) {
-          ReportWriteFailure("method code", it);
-          return false;
-        }
-        writer_->size_code_ += code_size;
-        offset_ += code_size;
       }
-      DCHECK_OFFSET_();
-      ++method_offsets_index_;
+
+      if (!out->WriteFully(quick_code.data(), code_size)) {
+        ReportWriteFailure("method code", method_ref);
+        return false;
+      }
+      writer_->size_code_ += code_size;
+      offset_ += code_size;
     }
+    DCHECK_OFFSET_();
 
     return true;
   }
 
+  size_t GetOffset() const {
+    return offset_;
+  }
+
  private:
+  OatWriter* const writer_;
+
+  // Updated in VisitMethod as methods are written out.
+  size_t offset_;
+
+  // Potentially varies with every different VisitMethod.
+  // Used to determine which DexCache to use when finding ArtMethods.
+  const DexFile* dex_file_;
+
+  // Pointer size we are compiling to.
   const PointerSize pointer_size_;
+  // The image writer's classloader, if there is one, else null.
   ObjPtr<mirror::ClassLoader> class_loader_;
+  // Stream to output file, where the OAT code will be written to.
   OutputStream* const out_;
   const size_t file_offset_;
-  const ScopedObjectAccess soa_;
-  const ScopedAssertNoThreadSuspension no_thread_suspension_;
   ClassLinker* const class_linker_;
   ObjPtr<mirror::DexCache> dex_cache_;
   std::vector<uint8_t> patched_code_;
+  const ScopedAssertNoThreadSuspension no_thread_suspension_;
 
-  void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
+  void ReportWriteFailure(const char* what, const MethodReference& method_ref) {
     PLOG(ERROR) << "Failed to write " << what << " for "
-        << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
+        << method_ref.PrettyMethod() << " to " << out_->GetLocation();
   }
 
   ArtMethod* GetTargetMethod(const LinkerPatch& patch)
@@ -1528,7 +1845,8 @@
     ObjPtr<mirror::DexCache> dex_cache =
         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
             Thread::Current(), *ref.dex_file);
-    ArtMethod* method = class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_);
+    ArtMethod* method =
+        class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_);
     CHECK(method != nullptr);
     return method;
   }
@@ -1920,7 +2238,7 @@
       DCHECK_ALIGNED(offset, 4u);
       oat_dex_files_[i].method_bss_mapping_offset_ = offset;
 
-      linker::MethodBssMappingEncoder encoder(
+      MethodBssMappingEncoder encoder(
           GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
       size_t number_of_entries = 0u;
       bool first_index = true;
@@ -2001,12 +2319,50 @@
 
 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
   if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+    if (kOatWriterDebugOatCodeLayout) {
+      LOG(INFO) << "InitOatCodeDexFiles: OatWriter("
+                << this << "), "
+                << "compilation is disabled";
+    }
+
     return offset;
   }
-  InitCodeMethodVisitor code_visitor(this, offset);
-  bool success = VisitDexMethods(&code_visitor);
-  DCHECK(success);
-  offset = code_visitor.GetOffset();
+  bool success = false;
+
+  {
+    ScopedObjectAccess soa(Thread::Current());
+
+    LayoutCodeMethodVisitor layout_code_visitor(this, offset);
+    success = VisitDexMethods(&layout_code_visitor);
+    DCHECK(success);
+
+    LayoutReserveOffsetCodeMethodVisitor layout_reserve_code_visitor(
+        this,
+        offset,
+        layout_code_visitor.ReleaseOrderedMethods());
+    success = layout_reserve_code_visitor.Visit();
+    DCHECK(success);
+    offset = layout_reserve_code_visitor.GetOffset();
+
+    // Save the method order because the WriteCodeMethodVisitor will need this
+    // order again.
+    DCHECK(ordered_methods_ == nullptr);
+    ordered_methods_.reset(
+        new OrderedMethodList(
+            layout_reserve_code_visitor.ReleaseOrderedMethods()));
+
+    if (kOatWriterDebugOatCodeLayout) {
+      LOG(INFO) << "IniatOatCodeDexFiles: method order: ";
+      for (const OrderedMethodData& ordered_method : *ordered_methods_) {
+        std::string pretty_name = ordered_method.method_reference.PrettyMethod();
+        LOG(INFO) << pretty_name
+                  << "@ offset "
+                  << relative_patcher_->GetOffset(ordered_method.method_reference)
+                  << " X hotness "
+                  << reinterpret_cast<void*>(ordered_method.method_hotness.GetFlags());
+      }
+    }
+  }
 
   if (HasImage()) {
     InitImageMethodVisitor image_visitor(this, offset, dex_files_);
@@ -2593,7 +2949,7 @@
                     "MethodBssMapping alignment check.");
       DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
 
-      linker::MethodBssMappingEncoder encoder(
+      MethodBssMappingEncoder encoder(
           GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
       // Allocate a sufficiently large MethodBssMapping.
       size_t number_of_method_indexes = method_indexes.NumSetBits();
@@ -2688,18 +3044,30 @@
 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
                                     size_t file_offset,
                                     size_t relative_offset) {
-  #define VISIT(VisitorType)                                              \
-    do {                                                                  \
-      VisitorType visitor(this, out, file_offset, relative_offset);       \
-      if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
-        return 0;                                                         \
-      }                                                                   \
-      relative_offset = visitor.GetOffset();                              \
-    } while (false)
+  if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+    // As with InitOatCodeDexFiles, also skip the writer if
+    // compilation was disabled.
+    if (kOatWriterDebugOatCodeLayout) {
+      LOG(INFO) << "WriteCodeDexFiles: OatWriter("
+                << this << "), "
+                << "compilation is disabled";
+    }
 
-  VISIT(WriteCodeMethodVisitor);
-
-  #undef VISIT
+    return relative_offset;
+  }
+  ScopedObjectAccess soa(Thread::Current());
+  DCHECK(ordered_methods_ != nullptr);
+  std::unique_ptr<OrderedMethodList> ordered_methods_ptr =
+      std::move(ordered_methods_);
+  WriteCodeMethodVisitor visitor(this,
+                                 out,
+                                 file_offset,
+                                 relative_offset,
+                                 std::move(*ordered_methods_ptr));
+  if (UNLIKELY(!visitor.Visit())) {
+    return 0;
+  }
+  relative_offset = visitor.GetOffset();
 
   size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
   size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index a93dd23..c742fd4 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <cstddef>
 #include <memory>
+#include <vector>
 
 #include "base/array_ref.h"
 #include "base/dchecked_vector.h"
@@ -254,6 +255,10 @@
   class OatDexMethodVisitor;
   class InitBssLayoutMethodVisitor;
   class InitOatClassesMethodVisitor;
+  class LayoutCodeMethodVisitor;
+  class LayoutReserveOffsetCodeMethodVisitor;
+  struct OrderedMethodData;
+  class OrderedMethodVisitor;
   class InitCodeMethodVisitor;
   class InitMapMethodVisitor;
   class InitMethodInfoVisitor;
@@ -486,6 +491,13 @@
   // Profile info used to generate new layout of files.
   ProfileCompilationInfo* profile_compilation_info_;
 
+  using OrderedMethodList = std::vector<OrderedMethodData>;
+
+  // List of compiled methods, sorted by the order defined in OrderedMethodData.
+  // Methods can be inserted more than once in case of duplicated methods.
+  // This pointer is only non-null after InitOatCodeDexFiles succeeds.
+  std::unique_ptr<OrderedMethodList> ordered_methods_;
+
   DISALLOW_COPY_AND_ASSIGN(OatWriter);
 };
 
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 33d1491..d89d9f0 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -23,7 +23,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler.h"
 #include "debug/method_debug_info.h"
 #include "dex/quick_compiler_callbacks.h"
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 36bd4bc..be78136 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -36,6 +36,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "class_linker.h"
+#include "compiled_method.h"
 #include "debug/elf_debug_writer.h"
 #include "debug/method_debug_info.h"
 #include "dex_file-inl.h"
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 4339b2b..bac57f9 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1034,14 +1034,13 @@
     ENSURE_VALID_ENV(env);
     art::Thread* art_thread = nullptr;
     if (event_thread != nullptr) {
-      // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
+      // TODO The locking around this call is less then what we really want.
       art::ScopedObjectAccess soa(art::Thread::Current());
       art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
-      art_thread = art::Thread::FromManagedThread(soa, event_thread);
-
-      if (art_thread == nullptr ||  // The thread hasn't been started or is already dead.
-          art_thread->IsStillStarting()) {
-        // TODO: We may want to let the EventHandler know, so it could clean up masks, potentially.
+      jvmtiError err = ERR(INTERNAL);
+      if (!ThreadUtil::GetAliveNativeThread(event_thread, soa, &art_thread, &err)) {
+        return err;
+      } else if (art_thread->IsStillStarting()) {
         return ERR(THREAD_NOT_ALIVE);
       }
     }
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 62603aa..7f841fc 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -761,12 +761,10 @@
   art::jit::ScopedJitSuspend suspend_jit;
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
   GetLocalVariableClosure c(self, depth, slot, type, val);
   if (!target->RequestSynchronousCheckpoint(&c)) {
@@ -890,12 +888,10 @@
   art::jit::ScopedJitSuspend suspend_jit;
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
   SetLocalVariableClosure c(self, depth, slot, type, val);
   if (!target->RequestSynchronousCheckpoint(&c)) {
@@ -923,12 +919,6 @@
       result_ = ERR(NO_MORE_FRAMES);
       return;
     }
-    art::ArtMethod* method = visitor.GetMethod();
-    if (!visitor.IsShadowFrame() && !method->IsNative() && !method->IsProxyMethod()) {
-      // TODO We really should support get/set for non-shadow frames.
-      result_ = ERR(OPAQUE_FRAME);
-      return;
-    }
     result_ = OK;
     art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
     *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
@@ -955,12 +945,10 @@
   art::Thread* self = art::Thread::Current();
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
   GetLocalInstanceClosure c(self, depth, data);
   if (!target->RequestSynchronousCheckpoint(&c)) {
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index f92d81e..5a38f46 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -335,12 +335,10 @@
   art::Thread* self = art::Thread::Current();
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
   struct GetContendedMonitorClosure : public art::Closure {
    public:
@@ -395,7 +393,9 @@
     jobject* out_;
   };
   GetContendedMonitorClosure closure(self, monitor);
-  target->RequestSynchronousCheckpoint(&closure);
+  if (!target->RequestSynchronousCheckpoint(&closure)) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
   return OK;
 }
 
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 699f695..d4cc42a 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -211,34 +211,6 @@
   size_t index = 0;
 };
 
-static jvmtiError GetThread(JNIEnv* env,
-                            art::ScopedObjectAccessAlreadyRunnable& soa,
-                            jthread java_thread,
-                            art::Thread** thread)
-    REQUIRES_SHARED(art::Locks::mutator_lock_)  // Needed for FromManagedThread.
-    REQUIRES(art::Locks::thread_list_lock_) {   // Needed for FromManagedThread.
-  if (java_thread == nullptr) {
-    *thread = art::Thread::Current();
-    if (*thread == nullptr) {
-      // GetStackTrace can only be run during the live phase, so the current thread should be
-      // attached and thus available. Getting a null for current means we're starting up or
-      // dying.
-      return ERR(WRONG_PHASE);
-    }
-  } else {
-    if (!env->IsInstanceOf(java_thread, art::WellKnownClasses::java_lang_Thread)) {
-      return ERR(INVALID_THREAD);
-    }
-
-    // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
-    *thread = art::Thread::FromManagedThread(soa, java_thread);
-    if (*thread == nullptr) {
-      return ERR(THREAD_NOT_ALIVE);
-    }
-  }
-  return ERR(NONE);
-}
-
 jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
                                     jthread java_thread,
                                     jint start_depth,
@@ -251,19 +223,14 @@
   art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
 
   art::Thread* thread;
-  jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(),
-                                      soa,
-                                      java_thread,
-                                      &thread);
-  if (thread_error != ERR(NONE)) {
+  jvmtiError thread_error = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(java_thread, soa, &thread, &thread_error)) {
     return thread_error;
   }
   DCHECK(thread != nullptr);
 
   art::ThreadState state = thread->GetState();
-  if (state == art::ThreadState::kStarting ||
-      state == art::ThreadState::kTerminated ||
-      thread->IsStillStarting()) {
+  if (state == art::ThreadState::kStarting || thread->IsStillStarting()) {
     return ERR(THREAD_NOT_ALIVE);
   }
 
@@ -714,22 +681,25 @@
   art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
 
   art::Thread* thread;
-  jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(),
-                                      soa,
-                                      java_thread,
-                                      &thread);
-
-  if (thread_error != ERR(NONE)) {
+  jvmtiError thread_error = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(java_thread, soa, &thread, &thread_error)) {
     return thread_error;
   }
+
   DCHECK(thread != nullptr);
+  art::ThreadState state = thread->GetState();
+  if (state == art::ThreadState::kStarting || thread->IsStillStarting()) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
 
   if (count_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
 
   GetFrameCountClosure closure;
-  thread->RequestSynchronousCheckpoint(&closure);
+  if (!thread->RequestSynchronousCheckpoint(&closure)) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
 
   *count_ptr = closure.count;
   return ERR(NONE);
@@ -793,15 +763,17 @@
   art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
 
   art::Thread* thread;
-  jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(),
-                                      soa,
-                                      java_thread,
-                                      &thread);
-  if (thread_error != ERR(NONE)) {
+  jvmtiError thread_error = ERR(INTERNAL);
+  if (!ThreadUtil::GetAliveNativeThread(java_thread, soa, &thread, &thread_error)) {
     return thread_error;
   }
   DCHECK(thread != nullptr);
 
+  art::ThreadState state = thread->GetState();
+  if (state == art::ThreadState::kStarting || thread->IsStillStarting()) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+
   if (depth < 0) {
     return ERR(ILLEGAL_ARGUMENT);
   }
@@ -920,12 +892,10 @@
   bool called_method = false;
   {
     art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-    art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
-    if (target == nullptr && thread == nullptr) {
-      return ERR(INVALID_THREAD);
-    }
-    if (target == nullptr) {
-      return ERR(THREAD_NOT_ALIVE);
+    art::Thread* target = nullptr;
+    jvmtiError err = ERR(INTERNAL);
+    if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+      return err;
     }
     if (target != self) {
       called_method = true;
@@ -1014,10 +984,11 @@
     // have the 'suspend_lock' locked here.
     art::ScopedObjectAccess soa(self);
     art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
-    target = ThreadUtil::GetNativeThread(thread, soa);
-    if (target == nullptr) {
-      return ERR(THREAD_NOT_ALIVE);
-    } else if (target != self) {
+    jvmtiError err = ERR(INTERNAL);
+    if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+      return err;
+    }
+    if (target != self) {
       // TODO This is part of the spec but we could easily avoid needing to do it. We would just put
       // all the logic into a sync-checkpoint.
       art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_);
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index d437e52..907b515 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -161,13 +161,34 @@
 }
 
 // Get the native thread. The spec says a null object denotes the current thread.
-art::Thread* ThreadUtil::GetNativeThread(jthread thread,
-                                         const art::ScopedObjectAccessAlreadyRunnable& soa) {
+bool ThreadUtil::GetNativeThread(jthread thread,
+                                 const art::ScopedObjectAccessAlreadyRunnable& soa,
+                                 /*out*/ art::Thread** thr,
+                                 /*out*/ jvmtiError* err) {
   if (thread == nullptr) {
-    return art::Thread::Current();
+    *thr = art::Thread::Current();
+    return true;
+  } else if (!soa.Env()->IsInstanceOf(thread, art::WellKnownClasses::java_lang_Thread)) {
+    *err = ERR(INVALID_THREAD);
+    return false;
+  } else {
+    *thr = art::Thread::FromManagedThread(soa, thread);
+    return true;
   }
+}
 
-  return art::Thread::FromManagedThread(soa, thread);
+bool ThreadUtil::GetAliveNativeThread(jthread thread,
+                                      const art::ScopedObjectAccessAlreadyRunnable& soa,
+                                      /*out*/ art::Thread** thr,
+                                      /*out*/ jvmtiError* err) {
+  if (!GetNativeThread(thread, soa, thr, err)) {
+    return false;
+  } else if (*thr == nullptr || (*thr)->GetState() == art::ThreadState::kTerminated) {
+    *err = ERR(THREAD_NOT_ALIVE);
+    return false;
+  } else {
+    return true;
+  }
 }
 
 jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
@@ -182,9 +203,10 @@
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
 
-  art::Thread* target = GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
+  art::Thread* target;
+  jvmtiError err = ERR(INTERNAL);
+  if (!GetNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
 
   JvmtiUniquePtr<char[]> name_uptr;
@@ -297,25 +319,18 @@
 };
 
 // Return the thread's (or current thread, if null) thread state.
-static InternalThreadState GetNativeThreadState(jthread thread,
-                                                const art::ScopedObjectAccessAlreadyRunnable& soa)
+static InternalThreadState GetNativeThreadState(art::Thread* target)
     REQUIRES_SHARED(art::Locks::mutator_lock_)
     REQUIRES(art::Locks::thread_list_lock_, art::Locks::user_code_suspension_lock_) {
-  art::Thread* self = nullptr;
-  if (thread == nullptr) {
-    self = art::Thread::Current();
-  } else {
-    self = art::Thread::FromManagedThread(soa, thread);
-  }
   InternalThreadState thread_state = {};
-  art::MutexLock tscl_mu(soa.Self(), *art::Locks::thread_suspend_count_lock_);
-  thread_state.native_thread = self;
-  if (self == nullptr || self->IsStillStarting()) {
+  art::MutexLock tscl_mu(art::Thread::Current(), *art::Locks::thread_suspend_count_lock_);
+  thread_state.native_thread = target;
+  if (target == nullptr || target->IsStillStarting()) {
     thread_state.art_state = art::ThreadState::kStarting;
     thread_state.thread_user_code_suspend_count = 0;
   } else {
-    thread_state.art_state = self->GetState();
-    thread_state.thread_user_code_suspend_count = self->GetUserCodeSuspendCount();
+    thread_state.art_state = target->GetState();
+    thread_state.thread_user_code_suspend_count = target->GetUserCodeSuspendCount();
   }
   return thread_state;
 }
@@ -456,7 +471,12 @@
     }
     art::ScopedObjectAccess soa(self);
     art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
-    state = GetNativeThreadState(thread, soa);
+    jvmtiError err = ERR(INTERNAL);
+    art::Thread* target = nullptr;
+    if (!GetNativeThread(thread, soa, &target, &err)) {
+      return err;
+    }
+    state = GetNativeThreadState(target);
     if (state.art_state == art::ThreadState::kStarting) {
       break;
     }
@@ -484,13 +504,18 @@
   }
 
   art::ScopedObjectAccess soa(self);
+  art::StackHandleScope<1> hs(self);
 
   // Need to read the Java "started" field to know whether this is starting or terminated.
-  art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
-  art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
-  art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
+  art::Handle<art::mirror::Object> peer(hs.NewHandle(soa.Decode<art::mirror::Object>(thread)));
+  art::ObjPtr<art::mirror::Class> thread_klass =
+      soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread);
+  if (!thread_klass->IsAssignableFrom(peer->GetClass())) {
+    return ERR(INVALID_THREAD);
+  }
+  art::ArtField* started_field = thread_klass->FindDeclaredInstanceField("started", "Z");
   CHECK(started_field != nullptr);
-  bool started = started_field->GetBoolean(peer) != 0;
+  bool started = started_field->GetBoolean(peer.Get()) != 0;
   constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
   constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
                                     JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
@@ -573,12 +598,10 @@
   art::Thread* self = art::Thread::Current();
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
 
   JvmtiGlobalTLSData* global_tls = reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS());
@@ -602,12 +625,10 @@
   art::Thread* self = art::Thread::Current();
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-  art::Thread* target = GetNativeThread(thread, soa);
-  if (target == nullptr && thread == nullptr) {
-    return ERR(INVALID_THREAD);
-  }
-  if (target == nullptr) {
-    return ERR(THREAD_NOT_ALIVE);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
   }
 
   JvmtiGlobalTLSData* global_tls = reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS());
@@ -726,9 +747,13 @@
     {
       art::ScopedObjectAccess soa(self);
       art::MutexLock thread_list_mu(self, *art::Locks::thread_list_lock_);
-      art::Thread* target = GetNativeThread(target_jthread, soa);
+      art::Thread* target = nullptr;
+      jvmtiError err = ERR(INTERNAL);
+      if (!GetAliveNativeThread(target_jthread, soa, &target, &err)) {
+        return err;
+      }
       art::ThreadState state = target->GetState();
-      if (state == art::ThreadState::kTerminated || state == art::ThreadState::kStarting) {
+      if (state == art::ThreadState::kStarting || target->IsStillStarting()) {
         return ERR(THREAD_NOT_ALIVE);
       } else {
         art::MutexLock thread_suspend_count_mu(self, *art::Locks::thread_suspend_count_lock_);
@@ -784,9 +809,10 @@
   {
     art::ScopedObjectAccess soa(self);
     art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-    art::Thread* target = GetNativeThread(thread, soa);
-    if (target == nullptr) {
-      return ERR(INVALID_THREAD);
+    art::Thread* target = nullptr;
+    jvmtiError err = ERR(INTERNAL);
+    if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+      return err;
     } else if (target == self) {
       target_is_self = true;
     }
@@ -820,16 +846,14 @@
       // have the 'suspend_lock' locked here.
       art::ScopedObjectAccess soa(self);
       art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
-      target = GetNativeThread(thread, soa);
-      if (target == nullptr) {
-        return ERR(INVALID_THREAD);
+      jvmtiError err = ERR(INTERNAL);
+      if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+        return err;
       } else if (target == self) {
         // We would have paused until we aren't suspended anymore due to the ScopedObjectAccess so
         // we can just return THREAD_NOT_SUSPENDED. Unfortunately we cannot do any real DCHECKs
         // about current state since it's all concurrent.
         return ERR(THREAD_NOT_SUSPENDED);
-      } else if (target->GetState() == art::ThreadState::kTerminated) {
-        return ERR(THREAD_NOT_ALIVE);
       }
       // The JVMTI spec requires us to return THREAD_NOT_SUSPENDED if it is alive but we really
       // cannot tell why resume failed.
@@ -854,6 +878,22 @@
   } while (true);
 }
 
+static bool IsCurrentThread(jthread thr) {
+  if (thr == nullptr) {
+    return true;
+  }
+  art::Thread* self = art::Thread::Current();
+  art::ScopedObjectAccess soa(self);
+  art::MutexLock mu(self, *art::Locks::thread_list_lock_);
+  art::Thread* target = nullptr;
+  jvmtiError err_unused = ERR(INTERNAL);
+  if (ThreadUtil::GetNativeThread(thr, soa, &target, &err_unused)) {
+    return target == self;
+  } else {
+    return false;
+  }
+}
+
 // Suspends all the threads in the list at the same time. Getting this behavior is a little tricky
 // since we can have threads in the list multiple times. This generally doesn't matter unless the
 // current thread is present multiple times. In that case we need to suspend only once and either
@@ -873,17 +913,12 @@
   // running thread. These indexes we need to handle specially since we need to only actually
   // suspend a single time.
   std::vector<jint> current_thread_indexes;
-  art::Thread* self = art::Thread::Current();
   for (jint i = 0; i < request_count; i++) {
-    {
-      art::ScopedObjectAccess soa(self);
-      art::MutexLock mu(self, *art::Locks::thread_list_lock_);
-      if (threads[i] == nullptr || GetNativeThread(threads[i], soa) == self) {
-        current_thread_indexes.push_back(i);
-        continue;
-      }
+    if (IsCurrentThread(threads[i])) {
+      current_thread_indexes.push_back(i);
+    } else {
+      results[i] = env->SuspendThread(threads[i]);
     }
-    results[i] = env->SuspendThread(threads[i]);
   }
   if (!current_thread_indexes.empty()) {
     jint first_current_thread_index = current_thread_indexes[0];
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index 57b1943..ceebff6 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -93,8 +93,24 @@
                                      const jthread* threads,
                                      jvmtiError* results);
 
-  static art::Thread* GetNativeThread(jthread thread,
-                                      const art::ScopedObjectAccessAlreadyRunnable& soa)
+  // Returns true if we decoded the thread and it is alive, false otherwise with an appropriate
+  // error placed into 'err'. A thread is alive if it has had it's 'start' function called and has
+  // (or at least could have) executed managed code and has not yet returned past it's first managed
+  // frame. This means that the thread returned might have IsStillStarting() return true. Code that
+  // does not consider that alive should check manually.
+  static bool GetAliveNativeThread(jthread thread,
+                                   const art::ScopedObjectAccessAlreadyRunnable& soa,
+                                   /*out*/ art::Thread** thr,
+                                   /*out*/ jvmtiError* err)
+      REQUIRES_SHARED(art::Locks::mutator_lock_)
+      REQUIRES(art::Locks::thread_list_lock_);
+
+  // Returns true if we decoded the thread, false otherwise with an appropriate error placed into
+  // 'err'
+  static bool GetNativeThread(jthread thread,
+                              const art::ScopedObjectAccessAlreadyRunnable& soa,
+                              /*out*/ art::Thread** thr,
+                              /*out*/ jvmtiError* err)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(art::Locks::thread_list_lock_);
 
diff --git a/runtime/Android.bp b/runtime/Android.bp
index db9707f..06e83b9 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -555,7 +555,6 @@
         "dex_file_test.cc",
         "dex_file_verifier_test.cc",
         "dex_instruction_test.cc",
-        "dex_method_iterator_test.cc",
         "entrypoints/math_entrypoints_test.cc",
         "entrypoints/quick/quick_trampoline_entrypoints_test.cc",
         "entrypoints_order_test.cc",
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index ece853f..d4297df 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -777,26 +777,16 @@
 }
 
 std::string ArtMethod::PrettyMethod(bool with_signature) {
-  ArtMethod* m = this;
-  if (!m->IsRuntimeMethod()) {
-    m = m->GetInterfaceMethodIfProxy(Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+  if (UNLIKELY(IsRuntimeMethod())) {
+    std::string result = GetDeclaringClassDescriptor();
+    result += '.';
+    result += GetName();
+    // Do not add "<no signature>" even if `with_signature` is true.
+    return result;
   }
-  std::string result(PrettyDescriptor(m->GetDeclaringClassDescriptor()));
-  result += '.';
-  result += m->GetName();
-  if (UNLIKELY(m->IsFastNative())) {
-    result += "!";
-  }
-  if (with_signature) {
-    const Signature signature = m->GetSignature();
-    std::string sig_as_string(signature.ToString());
-    if (signature == Signature::NoSignature()) {
-      return result + sig_as_string;
-    }
-    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
-        PrettyArguments(sig_as_string.c_str());
-  }
-  return result;
+  ArtMethod* m =
+      GetInterfaceMethodIfProxy(Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+  return m->GetDexFile()->PrettyMethod(m->GetDexMethodIndex(), with_signature);
 }
 
 std::string ArtMethod::JniShortName() {
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index b2e5251..b8d6931 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -128,8 +128,11 @@
   os << "Done Dumping histograms\n";
 }
 
-TimingLogger::TimingLogger(const char* name, bool precise, bool verbose)
-    : name_(name), precise_(precise), verbose_(verbose) {
+TimingLogger::TimingLogger(const char* name,
+                           bool precise,
+                           bool verbose,
+                           TimingLogger::TimingKind kind)
+    : name_(name), precise_(precise), verbose_(verbose), kind_(kind) {
 }
 
 void TimingLogger::Reset() {
@@ -138,12 +141,12 @@
 
 void TimingLogger::StartTiming(const char* label) {
   DCHECK(label != nullptr);
-  timings_.push_back(Timing(NanoTime(), label));
+  timings_.push_back(Timing(kind_, label));
   ATRACE_BEGIN(label);
 }
 
 void TimingLogger::EndTiming() {
-  timings_.push_back(Timing(NanoTime(), nullptr));
+  timings_.push_back(Timing(kind_, nullptr));
   ATRACE_END();
 }
 
diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h
index a5344db..a8a6701 100644
--- a/runtime/base/timing_logger.h
+++ b/runtime/base/timing_logger.h
@@ -20,6 +20,7 @@
 #include "base/histogram.h"
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "base/time_utils.h"
 
 #include <set>
 #include <string>
@@ -79,9 +80,23 @@
  public:
   static constexpr size_t kIndexNotFound = static_cast<size_t>(-1);
 
+  // Kind of timing we are going to do. We collect time at the nano second.
+  enum class TimingKind {
+    kMonotonic,
+    kThreadCpu,
+  };
+
   class Timing {
    public:
-    Timing(uint64_t time, const char* name) : time_(time), name_(name) {
+    Timing(TimingKind kind, const char* name) : name_(name) {
+       switch (kind) {
+        case TimingKind::kMonotonic:
+          time_ = NanoTime();
+          break;
+        case TimingKind::kThreadCpu:
+          time_ = ThreadCpuNanoTime();
+          break;
+       }
     }
     bool IsStartTiming() const {
       return !IsEndTiming();
@@ -131,7 +146,10 @@
     friend class TimingLogger;
   };
 
-  TimingLogger(const char* name, bool precise, bool verbose);
+  TimingLogger(const char* name,
+               bool precise,
+               bool verbose,
+               TimingKind kind = TimingKind::kMonotonic);
   ~TimingLogger();
   // Verify that all open timings have related closed timings.
   void Verify();
@@ -187,6 +205,8 @@
   const bool precise_;
   // Verbose logging.
   const bool verbose_;
+  // The kind of timing we want.
+  const TimingKind kind_;
   // Timing points that are either start or end points. For each starting point ret[i] = location
   // of end split associated with i. If it is and end split ret[i] = i.
   std::vector<Timing> timings_;
diff --git a/runtime/base/timing_logger_test.cc b/runtime/base/timing_logger_test.cc
index 35a73d0..770d2c0 100644
--- a/runtime/base/timing_logger_test.cc
+++ b/runtime/base/timing_logger_test.cc
@@ -158,4 +158,21 @@
   EXPECT_LE(timings[idx_innerinnersplit1].GetTime(), timings[idx_innerinnersplit2].GetTime());
 }
 
+TEST_F(TimingLoggerTest, ThreadCpuAndMonotonic) {
+  TimingLogger mon_logger("Scoped", true, false, TimingLogger::TimingKind::kMonotonic);
+  TimingLogger cpu_logger("Scoped", true, false, TimingLogger::TimingKind::kThreadCpu);
+  mon_logger.StartTiming("MON");
+  cpu_logger.StartTiming("CPU");
+
+  sleep(2);
+
+  cpu_logger.EndTiming();
+  mon_logger.EndTiming();
+  uint64_t mon_timing = mon_logger.GetTimings()[1].GetTime() - mon_logger.GetTimings()[0].GetTime();
+  uint64_t cpu_timing = cpu_logger.GetTimings()[1].GetTime() - cpu_logger.GetTimings()[0].GetTime();
+  EXPECT_LT(cpu_timing, MsToNs(1000u));
+  EXPECT_GT(mon_timing, MsToNs(1000u));
+  EXPECT_LT(cpu_timing, mon_timing);
+}
+
 }  // namespace art
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index eb8ced0..6d1de00 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -70,7 +70,7 @@
     if (guard_state_ < GuardState::kClosed) {
       LOG(ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction.";
     }
-    CHECK_GE(guard_state_, GuardState::kClosed);
+    DCHECK_GE(guard_state_, GuardState::kClosed);
   }
   if (auto_close_ && fd_ != -1) {
     if (Close() != 0) {
@@ -135,7 +135,7 @@
 
 bool FdFile::Open(const std::string& path, int flags, mode_t mode) {
   static_assert(O_RDONLY == 0, "Readonly flag has unexpected value.");
-  CHECK_EQ(fd_, -1) << path;
+  DCHECK_EQ(fd_, -1) << path;
   read_only_mode_ = ((flags & O_ACCMODE) == O_RDONLY);
   fd_ = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
   if (fd_ == -1) {
@@ -158,7 +158,7 @@
 
   // Test here, so the file is closed and not leaked.
   if (kCheckSafeUsage) {
-    CHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_
+    DCHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_
         << " has not been flushed before closing.";
     moveUp(GuardState::kClosed, nullptr);
   }
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 3bd4596..2282da0 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -220,7 +220,7 @@
         // If we can't get the realpath of the location there might be something wrong with the
         // classpath (maybe the file was deleted).
         // Do not continue in this case and return false.
-        PLOG(ERROR) << "Could not get the realpath of dex location " << raw_location;
+        PLOG(WARNING) << "Could not get the realpath of dex location " << raw_location;
         return false;
       }
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index f70846b..be157a3 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1302,17 +1302,27 @@
     return StringPrintf("<<invalid-method-idx-%d>>", method_idx);
   }
   const DexFile::MethodId& method_id = GetMethodId(method_idx);
-  std::string result(PrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id)));
+  std::string result;
+  const DexFile::ProtoId* proto_id = with_signature ? &GetProtoId(method_id.proto_idx_) : nullptr;
+  if (with_signature) {
+    AppendPrettyDescriptor(StringByTypeIdx(proto_id->return_type_idx_), &result);
+    result += ' ';
+  }
+  AppendPrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id), &result);
   result += '.';
   result += GetMethodName(method_id);
   if (with_signature) {
-    const Signature signature = GetMethodSignature(method_id);
-    std::string sig_as_string(signature.ToString());
-    if (signature == Signature::NoSignature()) {
-      return result + sig_as_string;
+    result += '(';
+    const DexFile::TypeList* params = GetProtoParameters(*proto_id);
+    if (params != nullptr) {
+      const char* separator = "";
+      for (uint32_t i = 0u, size = params->Size(); i != size; ++i) {
+        result += separator;
+        separator = ", ";
+        AppendPrettyDescriptor(StringByTypeIdx(params->GetTypeItem(i).type_idx_), &result);
+      }
     }
-    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
-        PrettyArguments(sig_as_string.c_str());
+    result += ')';
   }
   return result;
 }
@@ -1327,7 +1337,7 @@
     result += GetFieldTypeDescriptor(field_id);
     result += ' ';
   }
-  result += PrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id));
+  AppendPrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id), &result);
   result += '.';
   result += GetFieldName(field_id);
   return result;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 1a73062..a7bf59e 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -423,28 +423,83 @@
     ASSERT_EQ("()V", signature);
   }
 
-  // Check both virtual methods.
-  ASSERT_EQ(2U, it.NumVirtualMethods());
-  {
+  // Check all virtual methods.
+  struct Result {
+    const char* name;
+    const char* signature;
+    const char* pretty_method;
+  };
+  static const Result results[] = {
+      {
+          "m1",
+          "(IDJLjava/lang/Object;)Ljava/lang/Float;",
+          "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m2",
+          "(ZSC)LGetMethodSignature;",
+          "GetMethodSignature GetMethodSignature.m2(boolean, short, char)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m3",
+          "()V",
+          "void GetMethodSignature.m3()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m4",
+          "(I)V",
+          "void GetMethodSignature.m4(int)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m5",
+          "(II)V",
+          "void GetMethodSignature.m5(int, int)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m6",
+          "(II[[I)V",
+          "void GetMethodSignature.m6(int, int, int[][])"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m7",
+          "(II[[ILjava/lang/Object;)V",
+          "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m8",
+          "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V",
+          "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m9",
+          "()I",
+          "int GetMethodSignature.m9()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "mA",
+          "()[[I",
+          "int[][] GetMethodSignature.mA()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "mB",
+          "()[[Ljava/lang/Object;",
+          "java.lang.Object[][] GetMethodSignature.mB()"
+      },
+  };
+  ASSERT_EQ(arraysize(results), it.NumVirtualMethods());
+  for (const Result& r : results) {
     it.Next();
     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
 
     const char* name = raw->StringDataByIdx(method_id.name_idx_);
-    ASSERT_STREQ("m1", name);
+    ASSERT_STREQ(r.name, name);
 
     std::string signature(raw->GetMethodSignature(method_id).ToString());
-    ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
-  }
+    ASSERT_EQ(r.signature, signature);
 
-  {
-    it.Next();
-    const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
-
-    const char* name = raw->StringDataByIdx(method_id.name_idx_);
-    ASSERT_STREQ("m2", name);
-
-    std::string signature(raw->GetMethodSignature(method_id).ToString());
-    ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
+    std::string plain_method = std::string("GetMethodSignature.") + r.name;
+    ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false));
+    ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true));
   }
 }
 
diff --git a/runtime/dex_method_iterator.h b/runtime/dex_method_iterator.h
deleted file mode 100644
index a44bc16..0000000
--- a/runtime/dex_method_iterator.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_METHOD_ITERATOR_H_
-#define ART_RUNTIME_DEX_METHOD_ITERATOR_H_
-
-#include <vector>
-
-#include "dex_file-inl.h"
-
-namespace art {
-
-class DexMethodIterator {
- public:
-  explicit DexMethodIterator(const std::vector<const DexFile*>& dex_files)
-      : dex_files_(dex_files),
-        found_next_(false),
-        dex_file_index_(0),
-        class_def_index_(0),
-        class_def_(nullptr),
-        class_data_(nullptr),
-        direct_method_(false) {
-    CHECK_NE(0U, dex_files_.size());
-  }
-
-  bool HasNext() {
-    if (found_next_) {
-      return true;
-    }
-    while (true) {
-      // End of DexFiles, we are done.
-      if (dex_file_index_ == dex_files_.size()) {
-        return false;
-      }
-      if (class_def_index_ == GetDexFileInternal().NumClassDefs()) {
-        // End of this DexFile, advance and retry.
-        class_def_index_ = 0;
-        dex_file_index_++;
-        continue;
-      }
-      if (class_def_ == nullptr) {
-        class_def_ = &GetDexFileInternal().GetClassDef(class_def_index_);
-      }
-      if (class_data_ == nullptr) {
-        class_data_ = GetDexFileInternal().GetClassData(*class_def_);
-        if (class_data_ == nullptr) {
-          // empty class, such as a marker interface
-          // End of this class, advance and retry.
-          class_def_ = nullptr;
-          class_def_index_++;
-          continue;
-        }
-      }
-      if (it_.get() == nullptr) {
-        it_.reset(new ClassDataItemIterator(GetDexFileInternal(), class_data_));
-        GetIterator().SkipAllFields();
-        direct_method_ = true;
-      }
-      if (direct_method_ && GetIterator().HasNextDirectMethod()) {
-        // Found method
-        found_next_ = true;
-        return true;
-      }
-      direct_method_ = false;
-      if (GetIterator().HasNextVirtualMethod()) {
-        // Found method
-        found_next_ = true;
-        return true;
-      }
-      // End of this class, advance and retry.
-      DCHECK(!GetIterator().HasNext());
-      it_.reset(nullptr);
-      class_data_ = nullptr;
-      class_def_ = nullptr;
-      class_def_index_++;
-    }
-  }
-
-  void Next() {
-    found_next_ = false;
-    if (it_.get() != nullptr) {
-      // Advance to next method if we currently are looking at a class.
-      GetIterator().Next();
-    }
-  }
-
-  const DexFile& GetDexFile() {
-    CHECK(HasNext());
-    return GetDexFileInternal();
-  }
-
-  uint32_t GetMemberIndex() {
-    CHECK(HasNext());
-    return GetIterator().GetMemberIndex();
-  }
-
-  InvokeType GetInvokeType() {
-    CHECK(HasNext());
-    CHECK(class_def_ != nullptr);
-    return GetIterator().GetMethodInvokeType(*class_def_);
-  }
-
- private:
-  ClassDataItemIterator& GetIterator() const {
-    CHECK(it_.get() != nullptr);
-    return *it_.get();
-  }
-
-  const DexFile& GetDexFileInternal() const {
-    CHECK_LT(dex_file_index_, dex_files_.size());
-    const DexFile* dex_file = dex_files_[dex_file_index_];
-    CHECK(dex_file != nullptr);
-    return *dex_file;
-  }
-
-  const std::vector<const DexFile*>& dex_files_;
-
-  bool found_next_;
-
-  uint32_t dex_file_index_;
-  uint32_t class_def_index_;
-  const DexFile::ClassDef* class_def_;
-  const uint8_t* class_data_;
-  std::unique_ptr<ClassDataItemIterator> it_;
-  bool direct_method_;
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_DEX_METHOD_ITERATOR_H_
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
deleted file mode 100644
index e83829b..0000000
--- a/runtime/dex_method_iterator_test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_method_iterator.h"
-
-#include "base/stl_util.h"
-#include "common_runtime_test.h"
-#include "oat_file.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-current-inl.h"
-
-namespace art {
-
-class DexMethodIteratorTest : public CommonRuntimeTest {
-};
-
-TEST_F(DexMethodIteratorTest, Basic) {
-  ScopedObjectAccess soa(Thread::Current());
-  std::vector<const DexFile*> dex_files;
-  CHECK_NE(boot_class_path_.size(), 0U);
-  for (size_t i = 0; i < boot_class_path_.size(); ++i) {
-    dex_files.push_back(boot_class_path_[i]);
-  }
-  DexMethodIterator it(dex_files);
-  while (it.HasNext()) {
-    const DexFile& dex_file = it.GetDexFile();
-    InvokeType invoke_type = it.GetInvokeType();
-    uint32_t method_idx = it.GetMemberIndex();
-    if ((false)) {
-      LOG(INFO) << invoke_type << " " << dex_file.PrettyMethod(method_idx);
-    }
-    it.Next();
-  }
-}
-
-}  // namespace art
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index cff3ea7..2dd4db3 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -237,7 +237,8 @@
 }
 
 IndirectRef IndirectReferenceTable::Add(IRTSegmentState previous_state,
-                                        ObjPtr<mirror::Object> obj) {
+                                        ObjPtr<mirror::Object> obj,
+                                        std::string* error_msg) {
   if (kDebugIRT) {
     LOG(INFO) << "+++ Add: previous_state=" << previous_state.top_index
               << " top_index=" << segment_state_.top_index
@@ -253,28 +254,34 @@
 
   if (top_index == max_entries_) {
     if (resizable_ == ResizableCapacity::kNo) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")\n"
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
-      UNREACHABLE();
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")"
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this);
+      *error_msg = oss.str();
+      return nullptr;
     }
 
     // Try to double space.
     if (std::numeric_limits<size_t>::max() / 2 < max_entries_) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")" << std::endl
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this)
-                << " Resizing failed: exceeds size_t";
-      UNREACHABLE();
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")" << std::endl
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+          << " Resizing failed: exceeds size_t";
+      *error_msg = oss.str();
+      return nullptr;
     }
 
-    std::string error_msg;
-    if (!Resize(max_entries_ * 2, &error_msg)) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")" << std::endl
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this)
-                 << " Resizing failed: " << error_msg;
-      UNREACHABLE();
+    std::string inner_error_msg;
+    if (!Resize(max_entries_ * 2, &inner_error_msg)) {
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")" << std::endl
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+          << " Resizing failed: " << inner_error_msg;
+      *error_msg = oss.str();
+      return nullptr;
     }
   }
 
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 6d52d95..bf287b1 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -244,8 +244,10 @@
   bool IsValid() const;
 
   // Add a new entry. "obj" must be a valid non-null object reference. This function will
-  // abort if the table is full (max entries reached, or expansion failed).
-  IndirectRef Add(IRTSegmentState previous_state, ObjPtr<mirror::Object> obj)
+  // return null if an error happened (with an appropriate error message set).
+  IndirectRef Add(IRTSegmentState previous_state,
+                  ObjPtr<mirror::Object> obj,
+                  std::string* error_msg)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Given an IndirectRef in the table, return the Object it refers to.
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 6aefe23..9278509 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -80,13 +80,13 @@
   EXPECT_FALSE(irt.Remove(cookie, iref0)) << "unexpectedly successful removal";
 
   // Add three, check, remove in the order in which they were added.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
-  IndirectRef iref1 = irt.Add(cookie, obj1.Get());
+  IndirectRef iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 2, 2);
-  IndirectRef iref2 = irt.Add(cookie, obj2.Get());
+  IndirectRef iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -108,11 +108,11 @@
   EXPECT_TRUE(irt.Get(iref0) == nullptr);
 
   // Add three, remove in the opposite order.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -128,11 +128,11 @@
 
   // Add three, remove middle / middle / bottom / top.  (Second attempt
   // to remove middle should fail.)
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -157,20 +157,20 @@
   // Add four entries.  Remove #1, add new entry, verify that table size
   // is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
   // that we delete one and don't hole-compact the other.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
-  IndirectRef iref3 = irt.Add(cookie, obj3.Get());
+  IndirectRef iref3 = irt.Add(cookie, obj3.Get(), &error_msg);
   EXPECT_TRUE(iref3 != nullptr);
   CheckDump(&irt, 4, 4);
 
   ASSERT_TRUE(irt.Remove(cookie, iref1));
   CheckDump(&irt, 3, 3);
 
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
 
   ASSERT_EQ(4U, irt.Capacity()) << "hole not filled";
@@ -193,12 +193,12 @@
   // Add an entry, remove it, add a new entry, and try to use the original
   // iref.  They have the same slot number but are for different objects.
   // With the extended checks in place, this should fail.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_FALSE(irt.Remove(cookie, iref0)) << "mismatched del succeeded";
@@ -209,12 +209,12 @@
 
   // Same as above, but with the same object.  A more rigorous checker
   // (e.g. with slot serialization) will catch this.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
-  iref1 = irt.Add(cookie, obj0.Get());
+  iref1 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   if (iref0 != iref1) {
@@ -229,7 +229,7 @@
   ASSERT_TRUE(irt.Get(nullptr) == nullptr);
 
   // Stale lookup.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
@@ -241,12 +241,12 @@
   static const size_t kTableInitial = kTableMax / 2;
   IndirectRef manyRefs[kTableInitial];
   for (size_t i = 0; i < kTableInitial; i++) {
-    manyRefs[i] = irt.Add(cookie, obj0.Get());
+    manyRefs[i] = irt.Add(cookie, obj0.Get(), &error_msg);
     ASSERT_TRUE(manyRefs[i] != nullptr) << "Failed adding " << i;
     CheckDump(&irt, i + 1, 1);
   }
   // ...this one causes overflow.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   ASSERT_TRUE(iref0 != nullptr);
   ASSERT_EQ(kTableInitial + 1, irt.Capacity());
   CheckDump(&irt, kTableInitial + 1, 1);
@@ -306,16 +306,16 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
-    IndirectRef iref1 = irt.Add(cookie0, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie0, obj2.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
+    IndirectRef iref1 = irt.Add(cookie0, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie0, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie0, iref1));
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref3 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref3 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     // Must not have filled the previous hole.
     EXPECT_EQ(irt.Capacity(), 4u);
@@ -337,21 +337,21 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj2.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj2.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref2));
 
     // Pop segment.
     irt.SetSegmentState(cookie1);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref2) == nullptr);
@@ -373,25 +373,25 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj2.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref1));
 
     // New segment.
     const IRTSegmentState cookie2 = irt.GetSegmentState();
 
-    IndirectRef iref3 = irt.Add(cookie2, obj3.Get());
+    IndirectRef iref3 = irt.Add(cookie2, obj3.Get(), &error_msg);
 
     // Pop segment.
     irt.SetSegmentState(cookie2);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 3u);
     EXPECT_TRUE(irt.Get(iref1) == nullptr);
@@ -412,20 +412,20 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
     EXPECT_TRUE(irt.Remove(cookie1, iref1));
 
     // Emptied segment, push new one.
     const IRTSegmentState cookie2 = irt.GetSegmentState();
 
-    IndirectRef iref2 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj2.Get());
-    IndirectRef iref4 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref2 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj2.Get(), &error_msg);
+    IndirectRef iref4 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref3));
 
@@ -433,7 +433,7 @@
     UNUSED(cookie2);
     irt.SetSegmentState(cookie1);
 
-    IndirectRef iref5 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref5 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref3) == nullptr);
@@ -455,14 +455,14 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj2.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref2));
 
@@ -473,7 +473,7 @@
     const IRTSegmentState cookie1_second = irt.GetSegmentState();
     UNUSED(cookie1_second);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref3) == nullptr);
@@ -504,7 +504,7 @@
   const IRTSegmentState cookie = kIRTFirstSegment;
 
   for (size_t i = 0; i != kTableMax + 1; ++i) {
-    irt.Add(cookie, obj0.Get());
+    irt.Add(cookie, obj0.Get(), &error_msg);
   }
 
   EXPECT_EQ(irt.Capacity(), kTableMax + 1);
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 1593577..5a16053 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -35,6 +35,7 @@
 #include "mirror/class_loader.h"
 #include "nativebridge/native_bridge.h"
 #include "nativehelper/ScopedLocalRef.h"
+#include "nativehelper/ScopedUtfChars.h"
 #include "nativeloader/native_loader.h"
 #include "object_callbacks.h"
 #include "parsed_options.h"
@@ -588,7 +589,12 @@
     return nullptr;
   }
   WriterMutexLock mu(self, *Locks::jni_globals_lock_);
-  IndirectRef ref = globals_.Add(kIRTFirstSegment, obj);
+  std::string error_msg;
+  IndirectRef ref = globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
   return reinterpret_cast<jobject>(ref);
 }
 
@@ -606,7 +612,12 @@
     self->CheckEmptyCheckpointFromWeakRefAccess(Locks::jni_weak_globals_lock_);
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
-  IndirectRef ref = weak_globals_.Add(kIRTFirstSegment, obj);
+  std::string error_msg;
+  IndirectRef ref = weak_globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
   return reinterpret_cast<jweak>(ref);
 }
 
@@ -833,9 +844,42 @@
       // The library will be associated with class_loader. The JNI
       // spec says we can't load the same library into more than one
       // class loader.
+      //
+      // This isn't very common. So spend some time to get a readable message.
+      auto call_to_string = [&](jobject obj) -> std::string {
+        if (obj == nullptr) {
+          return "null";
+        }
+        // Handle jweaks. Ignore double local-ref.
+        ScopedLocalRef<jobject> local_ref(env, env->NewLocalRef(obj));
+        if (local_ref != nullptr) {
+          ScopedLocalRef<jclass> local_class(env, env->GetObjectClass(local_ref.get()));
+          jmethodID to_string = env->GetMethodID(local_class.get(),
+                                                 "toString",
+                                                 "()Ljava/lang/String;");
+          DCHECK(to_string != nullptr);
+          ScopedLocalRef<jobject> local_string(env,
+                                               env->CallObjectMethod(local_ref.get(), to_string));
+          if (local_string != nullptr) {
+            ScopedUtfChars utf(env, reinterpret_cast<jstring>(local_string.get()));
+            if (utf.c_str() != nullptr) {
+              return utf.c_str();
+            }
+          }
+          env->ExceptionClear();
+          return "(Error calling toString)";
+        }
+        return "null";
+      };
+      std::string old_class_loader = call_to_string(library->GetClassLoader());
+      std::string new_class_loader = call_to_string(class_loader);
       StringAppendF(error_msg, "Shared library \"%s\" already opened by "
-          "ClassLoader %p; can't open in ClassLoader %p",
-          path.c_str(), library->GetClassLoader(), class_loader);
+          "ClassLoader %p(%s); can't open in ClassLoader %p(%s)",
+          path.c_str(),
+          library->GetClassLoader(),
+          old_class_loader.c_str(),
+          class_loader,
+          new_class_loader.c_str());
       LOG(WARNING) << *error_msg;
       return false;
     }
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 12fa49e..1ed7889 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -1053,6 +1053,98 @@
   }
 }
 
+bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
+  std::unordered_map<std::string, const DexFile*> key_to_dex_file;
+  for (const DexFile* dex_file : dex_files) {
+    key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
+  }
+  for (const DexFileData* dex_data : info_) {
+    const auto it = key_to_dex_file.find(dex_data->profile_key);
+    if (it == key_to_dex_file.end()) {
+      // It is okay if profile contains data for additional dex files.
+      continue;
+    }
+    const DexFile* dex_file = it->second;
+    const std::string& dex_location = dex_file->GetLocation();
+    if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
+      LOG(ERROR) << "Dex checksum mismatch while verifying profile "
+                 << "dex location " << dex_location << " (checksum="
+                 << dex_file->GetLocationChecksum() << ", profile checksum="
+                 << dex_data->checksum;
+      return false;
+    }
+
+    if (dex_data->num_method_ids != dex_file->NumMethodIds()) {
+      LOG(ERROR) << "Number of method ids in dex file and profile don't match."
+                 << "dex location " << dex_location << " NumMethodId in DexFile"
+                 << dex_file->NumMethodIds() << ", NumMethodId in profile"
+                 << dex_data->num_method_ids;
+      return false;
+    }
+
+    // Verify method_encoding.
+    for (const auto& method_it : dex_data->method_map) {
+      size_t method_id = (size_t)(method_it.first);
+      if (method_id >= dex_file->NumMethodIds()) {
+        LOG(ERROR) << "Invalid method id in profile file. dex location="
+                   << dex_location << " method_id=" << method_id << " NumMethodIds="
+                   << dex_file->NumMethodIds();
+        return false;
+      }
+
+      // Verify class indices of inline caches.
+      const InlineCacheMap &inline_cache_map = method_it.second;
+      for (const auto& inline_cache_it : inline_cache_map) {
+        const DexPcData dex_pc_data = inline_cache_it.second;
+        if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
+          // No class indices to verify.
+          continue;
+        }
+
+        const ClassSet &classes = dex_pc_data.classes;
+        SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
+        // Group the classes by dex. We expect that most of the classes will come from
+        // the same dex, so this will be more efficient than encoding the dex index
+        // for each class reference.
+        GroupClassesByDex(classes, &dex_to_classes_map);
+        for (const auto &dex_it : dex_to_classes_map) {
+          uint8_t dex_profile_index = dex_it.first;
+          const auto dex_file_inline_cache_it = key_to_dex_file.find(
+              info_[dex_profile_index]->profile_key);
+          if (dex_file_inline_cache_it == key_to_dex_file.end()) {
+            // It is okay if profile contains data for additional dex files.
+            continue;
+          }
+          const DexFile *dex_file_for_inline_cache_check = dex_file_inline_cache_it->second;
+          const std::vector<dex::TypeIndex> &dex_classes = dex_it.second;
+          for (size_t i = 0; i < dex_classes.size(); i++) {
+            if (dex_classes[i].index_ >= dex_file_for_inline_cache_check->NumTypeIds()) {
+              LOG(ERROR) << "Invalid inline cache in profile file. dex location="
+                  << dex_location << " method_id=" << method_id
+                  << " dex_profile_index="
+                  << static_cast<uint16_t >(dex_profile_index) << " type_index="
+                  << dex_classes[i].index_
+                  << " NumTypeIds="
+                  << dex_file_for_inline_cache_check->NumTypeIds();
+              return false;
+            }
+          }
+        }
+      }
+    }
+    // Verify class_ids.
+    for (const auto& class_id : dex_data->class_set) {
+      if (class_id.index_ >= dex_file->NumTypeIds()) {
+        LOG(ERROR) << "Invalid class id in profile file. dex_file location "
+                   << dex_location << " class_id=" << class_id.index_ << " NumClassIds="
+                   << dex_file->NumClassDefs();
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 // TODO(calin): fail fast if the dex checksums don't match.
 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::LoadInternal(
       int fd, std::string* error, bool merge_classes) {
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 009554c..09de29e 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -305,6 +305,15 @@
   // If merge_classes is set to false, classes will not be merged/loaded.
   bool Load(int fd, bool merge_classes = true);
 
+  // Verify integrity of the profile file with the provided dex files.
+  // If there exists a DexData object which maps to a dex_file, then it verifies that:
+  // - The checksums of the DexData and dex_file are equals.
+  // - No method id exceeds NumMethodIds corresponding to the dex_file.
+  // - No class id exceeds NumTypeIds corresponding to the dex_file.
+  // - For every inline_caches, class_ids does not exceed NumTypeIds corresponding to
+  //   the dex_file they are in.
+  bool VerifyProfileData(const std::vector<const DexFile *> &dex_files);
+
   // Load profile information from the given file
   // If the current profile is non-empty the load will fail.
   // If clear_if_invalid is true and the file is invalid the method clears the
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h
index 25893b7..d66df08 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni_env_ext-inl.h
@@ -25,7 +25,13 @@
 
 template<typename T>
 inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
-  IndirectRef ref = locals.Add(local_ref_cookie, obj);
+  std::string error_msg;
+  IndirectRef ref = locals.Add(local_ref_cookie, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    // This is really unexpected if we allow resizing local IRTs...
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
 
   // TODO: fix this to understand PushLocalFrame, so we can turn it on.
   if (false) {
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 3ff94f9..8352657 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -99,7 +99,14 @@
   if (obj == nullptr) {
     return nullptr;
   }
-  return reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj));
+  std::string error_msg;
+  jobject ref = reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj, &error_msg));
+  if (UNLIKELY(ref == nullptr)) {
+    // This is really unexpected if we allow resizing local IRTs...
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
+  return ref;
 }
 
 void JNIEnvExt::DeleteLocalRef(jobject obj) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 77a5b55..78f6b25 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -128,7 +128,8 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetDirectMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetDirectMethodsStartOffset(),
                                        GetVirtualMethodsStartOffset());
 }
@@ -140,7 +141,8 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetDeclaredMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetDirectMethodsStartOffset(),
                                        GetCopiedMethodsStartOffset());
 }
@@ -152,7 +154,8 @@
 
 inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethodsSliceUnchecked(
     PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetVirtualMethodsStartOffset(),
                                        GetCopiedMethodsStartOffset());
 }
@@ -164,9 +167,11 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetVirtualMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods,
+                                       pointer_size,
                                        GetVirtualMethodsStartOffset(),
-                                       NumMethods());
+                                       NumMethods(methods));
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -176,7 +181,11 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetCopiedMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size, GetCopiedMethodsStartOffset(), NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods,
+                                       pointer_size,
+                                       GetCopiedMethodsStartOffset(),
+                                       NumMethods(methods));
 }
 
 inline LengthPrefixedArray<ArtMethod>* Class::GetMethodsPtr() {
@@ -187,19 +196,21 @@
 template<VerifyObjectFlags kVerifyFlags>
 inline ArraySlice<ArtMethod> Class::GetMethodsSlice(PointerSize pointer_size) {
   DCHECK(IsLoaded() || IsErroneous());
-  return GetMethodsSliceRangeUnchecked(pointer_size, 0, NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods, pointer_size, 0, NumMethods(methods));
 }
 
-inline ArraySlice<ArtMethod> Class::GetMethodsSliceRangeUnchecked(PointerSize pointer_size,
-                                                                  uint32_t start_offset,
-                                                                  uint32_t end_offset) {
+inline ArraySlice<ArtMethod> Class::GetMethodsSliceRangeUnchecked(
+    LengthPrefixedArray<ArtMethod>* methods,
+    PointerSize pointer_size,
+    uint32_t start_offset,
+    uint32_t end_offset) {
   DCHECK_LE(start_offset, end_offset);
-  DCHECK_LE(end_offset, NumMethods());
+  DCHECK_LE(end_offset, NumMethods(methods));
   uint32_t size = end_offset - start_offset;
   if (size == 0u) {
     return ArraySlice<ArtMethod>();
   }
-  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
   DCHECK(methods != nullptr);
   DCHECK_LE(end_offset, methods->size());
   size_t method_size = ArtMethod::Size(pointer_size);
@@ -211,7 +222,10 @@
 }
 
 inline uint32_t Class::NumMethods() {
-  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return NumMethods(GetMethodsPtr());
+}
+
+inline uint32_t Class::NumMethods(LengthPrefixedArray<ArtMethod>* methods) {
   return (methods == nullptr) ? 0 : methods->size();
 }
 
@@ -969,7 +983,8 @@
 
 inline ArraySlice<ArtMethod> Class::GetMethods(PointerSize pointer_size) {
   CheckPointerSize(pointer_size);
-  return GetMethodsSliceRangeUnchecked(pointer_size, 0u, NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods, pointer_size, 0u, NumMethods(methods));
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetIFields() {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c44b616..148273b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -773,6 +773,8 @@
   ALWAYS_INLINE uint32_t NumDeclaredVirtualMethods() REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE uint32_t NumMethods() REQUIRES_SHARED(Locks::mutator_lock_);
+  static ALWAYS_INLINE uint32_t NumMethods(LengthPrefixedArray<ArtMethod>* methods)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* GetVirtualMethod(size_t i, PointerSize pointer_size)
@@ -1294,9 +1296,11 @@
   ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ALWAYS_INLINE ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked(PointerSize pointer_size,
-                                                                    uint32_t start_offset,
-                                                                    uint32_t end_offset)
+  ALWAYS_INLINE static ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked(
+      LengthPrefixedArray<ArtMethod>* methods,
+      PointerSize pointer_size,
+      uint32_t start_offset,
+      uint32_t end_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <bool throw_on_failure>
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 05b63d2..7cabae5 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -54,7 +54,8 @@
 
 static bool OatFileIsOnSystem(const std::unique_ptr<const OatFile>& oat_file) {
   UniqueCPtr<const char[]> path(realpath(oat_file->GetLocation().c_str(), nullptr));
-  return path != nullptr && android::base::StartsWith(oat_file->GetLocation(), GetAndroidRoot());
+  return path != nullptr && android::base::StartsWith(oat_file->GetLocation(),
+                                                      GetAndroidRoot().c_str());
 }
 
 const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
diff --git a/runtime/primitive.cc b/runtime/primitive.cc
index 1ec345a..6f3571c 100644
--- a/runtime/primitive.cc
+++ b/runtime/primitive.cc
@@ -60,9 +60,9 @@
   return kBoxedDescriptors[type];
 }
 
-std::ostream& operator<<(std::ostream& os, const Primitive::Type& type) {
-  int32_t int_type = static_cast<int32_t>(type);
-  if (type >= Primitive::kPrimNot && type <= Primitive::kPrimVoid) {
+std::ostream& operator<<(std::ostream& os, Primitive::Type type) {
+  uint32_t int_type = static_cast<uint32_t>(type);
+  if (type <= Primitive::kPrimLast) {
     os << kTypeNames[int_type];
   } else {
     os << "Type[" << int_type << "]";
diff --git a/runtime/primitive.h b/runtime/primitive.h
index a0edaee..a429914 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -49,7 +49,7 @@
     kPrimLast = kPrimVoid
   };
 
-  static Type GetType(char type) {
+  static constexpr Type GetType(char type) {
     switch (type) {
       case 'B':
         return kPrimByte;
@@ -74,7 +74,7 @@
     }
   }
 
-  static size_t ComponentSizeShift(Type type) {
+  static constexpr size_t ComponentSizeShift(Type type) {
     switch (type) {
       case kPrimVoid:
       case kPrimBoolean:
@@ -86,13 +86,12 @@
       case kPrimLong:
       case kPrimDouble:  return 3;
       case kPrimNot:     return ComponentSizeShiftWidth(kObjectReferenceSize);
-      default:
-        LOG(FATAL) << "Invalid type " << static_cast<int>(type);
-        return 0;
     }
+    LOG(FATAL) << "Invalid type " << static_cast<int>(type);
+    UNREACHABLE();
   }
 
-  static size_t ComponentSize(Type type) {
+  static constexpr size_t ComponentSize(Type type) {
     switch (type) {
       case kPrimVoid:    return 0;
       case kPrimBoolean:
@@ -104,10 +103,9 @@
       case kPrimLong:
       case kPrimDouble:  return 8;
       case kPrimNot:     return kObjectReferenceSize;
-      default:
-        LOG(FATAL) << "Invalid type " << static_cast<int>(type);
-        return 0;
     }
+    LOG(FATAL) << "Invalid type " << static_cast<int>(type);
+    UNREACHABLE();
   }
 
   static const char* Descriptor(Type type) {
@@ -141,26 +139,6 @@
   // Returns the descriptor corresponding to the boxed type of |type|.
   static const char* BoxedDescriptor(Type type);
 
-  static bool IsFloatingPointType(Type type) {
-    return type == kPrimFloat || type == kPrimDouble;
-  }
-
-  static bool IsIntegralType(Type type) {
-    // The Java language does not allow treating boolean as an integral type but
-    // our bit representation makes it safe.
-    switch (type) {
-      case kPrimBoolean:
-      case kPrimByte:
-      case kPrimChar:
-      case kPrimShort:
-      case kPrimInt:
-      case kPrimLong:
-        return true;
-      default:
-        return false;
-    }
-  }
-
   // Return true if |type| is an numeric type.
   static constexpr bool IsNumericType(Type type) {
     switch (type) {
@@ -175,6 +153,8 @@
       case Primitive::Type::kPrimDouble: return true;
       case Primitive::Type::kPrimVoid: return false;
     }
+    LOG(FATAL) << "Invalid type " << static_cast<int>(type);
+    UNREACHABLE();
   }
 
   // Returns true if it is possible to widen type |from| to type |to|. Both |from| and
@@ -190,73 +170,15 @@
     return IsNumericType(from) && IsNumericType(to) && from <= to;
   }
 
-  static bool IsIntOrLongType(Type type) {
-    return type == kPrimInt || type == kPrimLong;
-  }
-
   static bool Is64BitType(Type type) {
     return type == kPrimLong || type == kPrimDouble;
   }
 
-  // Return the general kind of `type`, fusing integer-like types as kPrimInt.
-  static Type PrimitiveKind(Type type) {
-    switch (type) {
-      case kPrimBoolean:
-      case kPrimByte:
-      case kPrimShort:
-      case kPrimChar:
-      case kPrimInt:
-        return kPrimInt;
-      default:
-        return type;
-    }
-  }
-
-  static int64_t MinValueOfIntegralType(Type type) {
-    switch (type) {
-      case kPrimBoolean:
-        return std::numeric_limits<bool>::min();
-      case kPrimByte:
-        return std::numeric_limits<int8_t>::min();
-      case kPrimChar:
-        return std::numeric_limits<uint16_t>::min();
-      case kPrimShort:
-        return std::numeric_limits<int16_t>::min();
-      case kPrimInt:
-        return std::numeric_limits<int32_t>::min();
-      case kPrimLong:
-        return std::numeric_limits<int64_t>::min();
-      default:
-        LOG(FATAL) << "non integral type";
-    }
-    return 0;
-  }
-
-  static int64_t MaxValueOfIntegralType(Type type) {
-    switch (type) {
-      case kPrimBoolean:
-        return std::numeric_limits<bool>::max();
-      case kPrimByte:
-        return std::numeric_limits<int8_t>::max();
-      case kPrimChar:
-        return std::numeric_limits<uint16_t>::max();
-      case kPrimShort:
-        return std::numeric_limits<int16_t>::max();
-      case kPrimInt:
-        return std::numeric_limits<int32_t>::max();
-      case kPrimLong:
-        return std::numeric_limits<int64_t>::max();
-      default:
-        LOG(FATAL) << "non integral type";
-    }
-    return 0;
-  }
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
 };
 
-std::ostream& operator<<(std::ostream& os, const Primitive::Type& state);
+std::ostream& operator<<(std::ostream& os, Primitive::Type state);
 
 }  // namespace art
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 3fe18c7..b72dec6 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -25,6 +25,21 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+// We need dladdr.
+#ifndef __APPLE__
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#define DEFINED_GNU_SOURCE
+#endif
+#include <dlfcn.h>
+#include <libgen.h>
+#ifdef DEFINED_GNU_SOURCE
+#undef _GNU_SOURCE
+#undef DEFINED_GNU_SOURCE
+#endif
+#endif
+
+
 #include <memory>
 
 #include "android-base/stringprintf.h"
@@ -148,7 +163,7 @@
   }
 }
 
-std::string PrettyDescriptor(const char* descriptor) {
+void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
   // Count the number of '['s to get the dimensionality.
   const char* c = descriptor;
   size_t dim = 0;
@@ -166,74 +181,41 @@
     // To make life easier, we make primitives look like unqualified
     // reference types.
     switch (*c) {
-    case 'B': c = "byte;"; break;
-    case 'C': c = "char;"; break;
-    case 'D': c = "double;"; break;
-    case 'F': c = "float;"; break;
-    case 'I': c = "int;"; break;
-    case 'J': c = "long;"; break;
-    case 'S': c = "short;"; break;
-    case 'Z': c = "boolean;"; break;
-    case 'V': c = "void;"; break;  // Used when decoding return types.
-    default: return descriptor;
+      case 'B': c = "byte;"; break;
+      case 'C': c = "char;"; break;
+      case 'D': c = "double;"; break;
+      case 'F': c = "float;"; break;
+      case 'I': c = "int;"; break;
+      case 'J': c = "long;"; break;
+      case 'S': c = "short;"; break;
+      case 'Z': c = "boolean;"; break;
+      case 'V': c = "void;"; break;  // Used when decoding return types.
+      default: result->append(descriptor); return;
     }
   }
 
   // At this point, 'c' is a string of the form "fully/qualified/Type;"
   // or "primitive;". Rewrite the type with '.' instead of '/':
-  std::string result;
   const char* p = c;
   while (*p != ';') {
     char ch = *p++;
     if (ch == '/') {
       ch = '.';
     }
-    result.push_back(ch);
+    result->push_back(ch);
   }
   // ...and replace the semicolon with 'dim' "[]" pairs:
   for (size_t i = 0; i < dim; ++i) {
-    result += "[]";
+    result->append("[]");
   }
-  return result;
 }
 
-std::string PrettyArguments(const char* signature) {
+std::string PrettyDescriptor(const char* descriptor) {
   std::string result;
-  result += '(';
-  CHECK_EQ(*signature, '(');
-  ++signature;  // Skip the '('.
-  while (*signature != ')') {
-    size_t argument_length = 0;
-    while (signature[argument_length] == '[') {
-      ++argument_length;
-    }
-    if (signature[argument_length] == 'L') {
-      argument_length = (strchr(signature, ';') - signature + 1);
-    } else {
-      ++argument_length;
-    }
-    {
-      std::string argument_descriptor(signature, argument_length);
-      result += PrettyDescriptor(argument_descriptor.c_str());
-    }
-    if (signature[argument_length] != ')') {
-      result += ", ";
-    }
-    signature += argument_length;
-  }
-  CHECK_EQ(*signature, ')');
-  ++signature;  // Skip the ')'.
-  result += ')';
+  AppendPrettyDescriptor(descriptor, &result);
   return result;
 }
 
-std::string PrettyReturnType(const char* signature) {
-  const char* return_type = strchr(signature, ')');
-  CHECK(return_type != nullptr);
-  ++return_type;  // Skip ')'.
-  return PrettyDescriptor(return_type);
-}
-
 std::string PrettyJavaAccessFlags(uint32_t access_flags) {
   std::string result;
   if ((access_flags & kAccPublic) != 0) {
@@ -735,6 +717,54 @@
   *task_cpu = strtoull(fields[36].c_str(), nullptr, 10);
 }
 
+std::string GetAndroidRootSafe(std::string* error_msg) {
+  // Prefer ANDROID_ROOT if it's set.
+  const char* android_dir = getenv("ANDROID_ROOT");
+  if (android_dir != nullptr) {
+    if (!OS::DirectoryExists(android_dir)) {
+      *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_dir);
+      return "";
+    }
+    return android_dir;
+  }
+
+  // Check where libart is from, and derive from there. Only do this for non-Mac.
+#ifndef __APPLE__
+  {
+    Dl_info info;
+    if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
+      // Make a duplicate of the fname so dirname can modify it.
+      UniqueCPtr<char> fname(strdup(info.dli_fname));
+
+      char* dir1 = dirname(fname.get());  // This is the lib directory.
+      char* dir2 = dirname(dir1);         // This is the "system" directory.
+      if (OS::DirectoryExists(dir2)) {
+        std::string tmp = dir2;  // Make a copy here so that fname can be released.
+        return tmp;
+      }
+    }
+  }
+#endif
+
+  // Try "/system".
+  if (!OS::DirectoryExists("/system")) {
+    *error_msg = "Failed to find ANDROID_ROOT directory /system";
+    return "";
+  }
+  return "/system";
+}
+
+std::string GetAndroidRoot() {
+  std::string error_msg;
+  std::string ret = GetAndroidRootSafe(&error_msg);
+  if (ret.empty()) {
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
+  return ret;
+}
+
+
 static const char* GetAndroidDirSafe(const char* env_var,
                                      const char* default_dir,
                                      std::string* error_msg) {
@@ -754,7 +784,7 @@
   return android_dir;
 }
 
-const char* GetAndroidDir(const char* env_var, const char* default_dir) {
+static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
   std::string error_msg;
   const char* dir = GetAndroidDirSafe(env_var, default_dir, &error_msg);
   if (dir != nullptr) {
@@ -765,14 +795,6 @@
   }
 }
 
-const char* GetAndroidRoot() {
-  return GetAndroidDir("ANDROID_ROOT", "/system");
-}
-
-const char* GetAndroidRootSafe(std::string* error_msg) {
-  return GetAndroidDirSafe("ANDROID_ROOT", "/system", error_msg);
-}
-
 const char* GetAndroidData() {
   return GetAndroidDir("ANDROID_DATA", "/data");
 }
@@ -782,11 +804,11 @@
 }
 
 std::string GetDefaultBootImageLocation(std::string* error_msg) {
-  const char* android_root = GetAndroidRootSafe(error_msg);
-  if (android_root == nullptr) {
+  std::string android_root = GetAndroidRootSafe(error_msg);
+  if (android_root.empty()) {
     return "";
   }
-  return StringPrintf("%s/framework/boot.art", android_root);
+  return StringPrintf("%s/framework/boot.art", android_root.c_str());
 }
 
 void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
diff --git a/runtime/utils.h b/runtime/utils.h
index 739681d..4cb06c1 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -81,13 +81,10 @@
 // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
 // "[[I" would be "int[][]", "[Ljava/lang/String;" would be
 // "java.lang.String[]", and so forth.
+void AppendPrettyDescriptor(const char* descriptor, std::string* result);
 std::string PrettyDescriptor(const char* descriptor);
 std::string PrettyDescriptor(Primitive::Type type);
 
-// Utilities for printing the types for method signatures.
-std::string PrettyArguments(const char* signature);
-std::string PrettyReturnType(const char* signature);
-
 // Returns a human-readable version of the Java part of the access flags, e.g., "private static "
 // (note the trailing whitespace).
 std::string PrettyJavaAccessFlags(uint32_t access_flags);
@@ -142,9 +139,9 @@
 void SetThreadName(const char* thread_name);
 
 // Find $ANDROID_ROOT, /system, or abort.
-const char* GetAndroidRoot();
-// Find $ANDROID_ROOT, /system, or return null.
-const char* GetAndroidRootSafe(std::string* error_msg);
+std::string GetAndroidRoot();
+// Find $ANDROID_ROOT, /system, or return an empty string.
+std::string GetAndroidRootSafe(std::string* error_msg);
 
 // Find $ANDROID_DATA, /data, or abort.
 const char* GetAndroidData();
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index ee8eb36..e846c98 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -16,9 +16,11 @@
 
 #include "utils.h"
 
+#include <libgen.h>
 #include <stdlib.h>
 
 #include "base/enums.h"
+#include "base/stl_util.h"
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "exec_utils.h"
@@ -91,23 +93,6 @@
   EXPECT_EQ("short", PrettyDescriptor("S"));
 }
 
-TEST_F(UtilsTest, PrettyArguments) {
-  EXPECT_EQ("()", PrettyArguments("()V"));
-  EXPECT_EQ("(int)", PrettyArguments("(I)V"));
-  EXPECT_EQ("(int, int)", PrettyArguments("(II)V"));
-  EXPECT_EQ("(int, int, int[][])", PrettyArguments("(II[[I)V"));
-  EXPECT_EQ("(int, int, int[][], java.lang.Poop)", PrettyArguments("(II[[ILjava/lang/Poop;)V"));
-  EXPECT_EQ("(int, int, int[][], java.lang.Poop, java.lang.Poop[][])", PrettyArguments("(II[[ILjava/lang/Poop;[[Ljava/lang/Poop;)V"));
-}
-
-TEST_F(UtilsTest, PrettyReturnType) {
-  EXPECT_EQ("void", PrettyReturnType("()V"));
-  EXPECT_EQ("int", PrettyReturnType("()I"));
-  EXPECT_EQ("int[][]", PrettyReturnType("()[[I"));
-  EXPECT_EQ("java.lang.Poop", PrettyReturnType("()Ljava/lang/Poop;"));
-  EXPECT_EQ("java.lang.Poop[][]", PrettyReturnType("()[[Ljava/lang/Poop;"));
-}
-
 TEST_F(UtilsTest, PrettyTypeOf) {
   ScopedObjectAccess soa(Thread::Current());
   EXPECT_EQ("null", mirror::Object::PrettyTypeOf(nullptr));
@@ -430,4 +415,40 @@
   EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 57, buffer, buffer_end), nullptr);
 }
 
+TEST_F(UtilsTest, GetAndroidRootSafe) {
+  std::string error_msg;
+
+  // We don't expect null returns for most cases, so don't check and let std::string crash.
+
+  // CommonRuntimeTest sets ANDROID_ROOT, so expect this to be the same.
+  std::string android_root = GetAndroidRootSafe(&error_msg);
+  std::string android_root_env = getenv("ANDROID_ROOT");
+  EXPECT_EQ(android_root, android_root_env);
+
+  // Set ANDROID_ROOT to something else (but the directory must exist). So use dirname.
+  char* root_dup = strdup(android_root_env.c_str());
+  char* dir = dirname(root_dup);
+  ASSERT_EQ(0, setenv("ANDROID_ROOT", dir, 1 /* overwrite */));
+  std::string android_root2 = GetAndroidRootSafe(&error_msg);
+  EXPECT_STREQ(dir, android_root2.c_str());
+  free(root_dup);
+
+  // Set a bogus value for ANDROID_ROOT. This should be an error.
+  ASSERT_EQ(0, setenv("ANDROID_ROOT", "/this/is/obviously/bogus", 1 /* overwrite */));
+  EXPECT_TRUE(GetAndroidRootSafe(&error_msg) == nullptr);
+
+  // Unset ANDROID_ROOT and see that it still returns something (as libart code is running).
+  ASSERT_EQ(0, unsetenv("ANDROID_ROOT"));
+  std::string android_root3 = GetAndroidRootSafe(&error_msg);
+  // This should be the same as the other root (modulo realpath), otherwise the test setup is
+  // broken.
+  UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
+  UniqueCPtr<char> real_root3(realpath(android_root3.c_str(), nullptr));
+  EXPECT_STREQ(real_root.get(), real_root3.get());
+
+
+  // Reset ANDROID_ROOT, as other things may depend on it.
+  ASSERT_EQ(0, setenv("ANDROID_ROOT", android_root_env.c_str(), 1 /* overwrite */));
+}
+
 }  // namespace art
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt
index 7e85ab1..1d05160 100644
--- a/test/004-JniTest/expected.txt
+++ b/test/004-JniTest/expected.txt
@@ -60,3 +60,4 @@
 hi-default δλ
 Clinit Lookup: ClassWithoutClinit: <NSME Exception>
 Clinit Lookup: ClassWithClinit: Main$ClassWithClinit()(Class: class java.lang.reflect.Constructor)
+Got UnsatisfiedLinkError for duplicate loadLibrary
diff --git a/test/004-JniTest/src-ex/A.java b/test/004-JniTest/src-ex/A.java
new file mode 100644
index 0000000..8fe0e0a
--- /dev/null
+++ b/test/004-JniTest/src-ex/A.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class A {
+    public static void run(String lib) {
+        System.loadLibrary(lib);
+    }
+}
\ No newline at end of file
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index fe5f4e3..871107c 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.regex.Pattern;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -58,6 +61,8 @@
         testCriticalNativeMethods();
 
         testClinitMethodLookup();
+
+        testDoubleLoad(args[0]);
     }
 
     private static native boolean registerNativesJniTest();
@@ -346,6 +351,57 @@
     private static class ClassWithClinit {
       static {}
     }
+
+  private static void testDoubleLoad(String library) {
+    // Test that nothing observably happens on loading "library" again.
+    System.loadLibrary(library);
+
+    // Now load code in a separate classloader and try to let it load.
+    ClassLoader loader = createClassLoader();
+    try {
+      Class<?> aClass = loader.loadClass("A");
+      Method runMethod = aClass.getDeclaredMethod("run", String.class);
+      runMethod.invoke(null, library);
+    } catch (InvocationTargetException ite) {
+      if (ite.getCause() instanceof UnsatisfiedLinkError) {
+        if (!(loader instanceof java.net.URLClassLoader)) {
+          String msg = ite.getCause().getMessage();
+          String pattern = "^Shared library .*libarttest.* already opened by ClassLoader.*" +
+                           "004-JniTest.jar.*; can't open in ClassLoader.*004-JniTest-ex.jar.*";
+          if (!Pattern.matches(pattern, msg)) {
+            throw new RuntimeException("Could not find pattern in message", ite.getCause());
+          }
+        }
+        System.out.println("Got UnsatisfiedLinkError for duplicate loadLibrary");
+      } else {
+        throw new RuntimeException(ite);
+      }
+    } catch (Throwable t) {
+      // Anything else just let die.
+      throw new RuntimeException(t);
+    }
+  }
+
+  private static ClassLoader createClassLoader() {
+    String location = System.getenv("DEX_LOCATION");
+    try {
+      Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+      Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class);
+
+      return (ClassLoader)ctor.newInstance(location + "/004-JniTest-ex.jar",
+                                           Main.class.getClassLoader());
+    } catch (ClassNotFoundException e) {
+      // Running on RI. Use URLClassLoader.
+      try {
+        return new java.net.URLClassLoader(
+            new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") });
+      } catch (Throwable t) {
+        throw new RuntimeException(t);
+      }
+    } catch (Throwable t) {
+      throw new RuntimeException(t);
+    }
+  }
 }
 
 @FunctionalInterface
diff --git a/test/063-process-manager/src/Main.java b/test/063-process-manager/src/Main.java
index 1005b77..2cfc0d7 100644
--- a/test/063-process-manager/src/Main.java
+++ b/test/063-process-manager/src/Main.java
@@ -10,7 +10,7 @@
             ProcessBuilder pb = new ProcessBuilder("sleep", "0");
             Process proc = pb.start();
             proc.waitFor();
-            Thread.sleep(500);  // Consider checking for (and waiting on) the reaper state here.
+            waitForReaperTimedWaiting(true /* reaperMustExist */);
         }
 
         for (int i = 1; i <= 2; i++) {
@@ -32,6 +32,11 @@
         System.out.println("child died");
     }
 
+    private static boolean isReaperThread(Thread t) {
+        String name = t.getName();
+        return name.indexOf("process reaper") >= 0;
+    }
+
     static private void checkManager() {
         Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
         boolean found = false;
@@ -39,8 +44,7 @@
         for (Map.Entry<Thread, StackTraceElement[]> entry :
                  traces.entrySet()) {
             Thread t = entry.getKey();
-            String name = t.getName();
-            if (name.indexOf("process reaper") >= 0) {
+            if (isReaperThread(t)) {
                 Thread.State state = t.getState();
                 System.out.println("process manager: " + state);
                 if (state != Thread.State.RUNNABLE && state != Thread.State.TIMED_WAITING) {
@@ -56,4 +60,34 @@
             System.out.println("process manager: nonexistent");
         }
     }
+
+    private static void waitForReaperTimedWaiting(boolean reaperMustExist) {
+        for (;;) {
+            Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+
+            boolean ok = true;
+            boolean found = false;
+
+            for (Thread t : traces.keySet()) {
+                if (isReaperThread(t)) {
+                    found = true;
+                    Thread.State state = t.getState();
+                    if (state != Thread.State.TIMED_WAITING) {
+                        ok = false;
+                        break;
+                    }
+                }
+            }
+
+            if (ok && (!reaperMustExist || found)) {
+                return;
+            }
+
+            try {
+                Thread.sleep(100);
+            } catch (Exception e) {
+                // Ignore.
+            }
+        }
+    }
 }
diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java
index f5cbc2a..3f7bb56 100644
--- a/test/088-monitor-verification/src/Main.java
+++ b/test/088-monitor-verification/src/Main.java
@@ -25,7 +25,7 @@
     /**
      * Drives tests.
      */
-    public static void main(String[] args) {
+    public static void main(String[] args) throws Exception {
         System.loadLibrary(args[0]);
         if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) {
             // Some tests ensure that the verifier was able to guarantee balanced locking by
@@ -40,6 +40,7 @@
         ensureJitCompiled(Main.class, "notExcessiveNesting");
         ensureJitCompiled(Main.class, "notNested");
         ensureJitCompiled(TwoPath.class, "twoPath");
+        ensureJitCompiled(Class.forName("OK"), "runBalancedJoin");
 
         Main m = new Main();
 
diff --git a/test/1930-monitor-info/src/art/Monitors.java b/test/1930-monitor-info/src/art/Monitors.java
index b28a3ee..7fe2b60 100644
--- a/test/1930-monitor-info/src/art/Monitors.java
+++ b/test/1930-monitor-info/src/art/Monitors.java
@@ -36,12 +36,40 @@
 
   public static class NamedLock {
     public final String name;
+    private volatile int calledNotify;
     public NamedLock(String name) {
       this.name = name;
+      calledNotify = 0;
     }
+
     public String toString() {
       return String.format("NamedLock[%s]", name);
     }
+
+    public final void DoWait() throws Exception {
+      final int v = calledNotify;
+      while (v == calledNotify) {
+        wait();
+      }
+    }
+
+    public final void DoWait(long t) throws Exception {
+      final int v = calledNotify;
+      final long target = System.currentTimeMillis() + (t / 2);
+      while (v == calledNotify && (t < 0 || System.currentTimeMillis() < target)) {
+        wait(t);
+      }
+    }
+
+    public final void DoNotifyAll() throws Exception {
+      calledNotify++;
+      notifyAll();
+    }
+
+    public final void DoNotify() throws Exception {
+      calledNotify++;
+      notify();
+    }
   }
 
   public static final class MonitorUsage {
@@ -91,7 +119,7 @@
   public static class LockController {
     private static enum Action { HOLD, RELEASE, NOTIFY, NOTIFY_ALL, WAIT, TIMED_WAIT }
 
-    public final Object lock;
+    public final NamedLock lock;
     public final long timeout;
     private final AtomicStampedReference<Action> action;
     private volatile Thread runner = null;
@@ -100,10 +128,10 @@
     private static final AtomicInteger cnt = new AtomicInteger(0);
     private volatile Throwable exe;
 
-    public LockController(Object lock) {
+    public LockController(NamedLock lock) {
       this(lock, 10 * 1000);
     }
-    public LockController(Object lock, long timeout) {
+    public LockController(NamedLock lock, long timeout) {
       this.lock = lock;
       this.timeout = timeout;
       this.action = new AtomicStampedReference(Action.HOLD, 0);
@@ -177,16 +205,16 @@
                       Thread.yield();
                       break;
                     case NOTIFY:
-                      lock.notify();
+                      lock.DoNotify();
                       break;
                     case NOTIFY_ALL:
-                      lock.notifyAll();
+                      lock.DoNotifyAll();
                       break;
                     case TIMED_WAIT:
-                      lock.wait(timeout);
+                      lock.DoWait(timeout);
                       break;
                     case WAIT:
-                      lock.wait();
+                      lock.DoWait();
                       break;
                     default:
                       throw new Error("Unknown action " + action);
diff --git a/test/1930-monitor-info/src/art/Test1930.java b/test/1930-monitor-info/src/art/Test1930.java
index a7fa1c7..ee03d73 100644
--- a/test/1930-monitor-info/src/art/Test1930.java
+++ b/test/1930-monitor-info/src/art/Test1930.java
@@ -96,7 +96,7 @@
         printMonitorUsage(lk);
         sem.release();
         try {
-          lk.wait();
+          lk.DoWait();
         } catch (Exception e) {
           throw new Error("Error waiting!", e);
         }
@@ -107,7 +107,7 @@
     sem.acquire();
     synchronized (lk) {
       printMonitorUsage(lk);
-      lk.notifyAll();
+      lk.DoNotifyAll();
     }
     t.join();
     printMonitorUsage(lk);
diff --git a/test/1931-monitor-events/src/art/Monitors.java b/test/1931-monitor-events/src/art/Monitors.java
index b28a3ee..7fe2b60 100644
--- a/test/1931-monitor-events/src/art/Monitors.java
+++ b/test/1931-monitor-events/src/art/Monitors.java
@@ -36,12 +36,40 @@
 
   public static class NamedLock {
     public final String name;
+    private volatile int calledNotify;
     public NamedLock(String name) {
       this.name = name;
+      calledNotify = 0;
     }
+
     public String toString() {
       return String.format("NamedLock[%s]", name);
     }
+
+    public final void DoWait() throws Exception {
+      final int v = calledNotify;
+      while (v == calledNotify) {
+        wait();
+      }
+    }
+
+    public final void DoWait(long t) throws Exception {
+      final int v = calledNotify;
+      final long target = System.currentTimeMillis() + (t / 2);
+      while (v == calledNotify && (t < 0 || System.currentTimeMillis() < target)) {
+        wait(t);
+      }
+    }
+
+    public final void DoNotifyAll() throws Exception {
+      calledNotify++;
+      notifyAll();
+    }
+
+    public final void DoNotify() throws Exception {
+      calledNotify++;
+      notify();
+    }
   }
 
   public static final class MonitorUsage {
@@ -91,7 +119,7 @@
   public static class LockController {
     private static enum Action { HOLD, RELEASE, NOTIFY, NOTIFY_ALL, WAIT, TIMED_WAIT }
 
-    public final Object lock;
+    public final NamedLock lock;
     public final long timeout;
     private final AtomicStampedReference<Action> action;
     private volatile Thread runner = null;
@@ -100,10 +128,10 @@
     private static final AtomicInteger cnt = new AtomicInteger(0);
     private volatile Throwable exe;
 
-    public LockController(Object lock) {
+    public LockController(NamedLock lock) {
       this(lock, 10 * 1000);
     }
-    public LockController(Object lock, long timeout) {
+    public LockController(NamedLock lock, long timeout) {
       this.lock = lock;
       this.timeout = timeout;
       this.action = new AtomicStampedReference(Action.HOLD, 0);
@@ -177,16 +205,16 @@
                       Thread.yield();
                       break;
                     case NOTIFY:
-                      lock.notify();
+                      lock.DoNotify();
                       break;
                     case NOTIFY_ALL:
-                      lock.notifyAll();
+                      lock.DoNotifyAll();
                       break;
                     case TIMED_WAIT:
-                      lock.wait(timeout);
+                      lock.DoWait(timeout);
                       break;
                     case WAIT:
-                      lock.wait();
+                      lock.DoWait();
                       break;
                     default:
                       throw new Error("Unknown action " + action);
diff --git a/test/1932-monitor-events-misc/src/art/Monitors.java b/test/1932-monitor-events-misc/src/art/Monitors.java
index b28a3ee..7fe2b60 100644
--- a/test/1932-monitor-events-misc/src/art/Monitors.java
+++ b/test/1932-monitor-events-misc/src/art/Monitors.java
@@ -36,12 +36,40 @@
 
   public static class NamedLock {
     public final String name;
+    private volatile int calledNotify;
     public NamedLock(String name) {
       this.name = name;
+      calledNotify = 0;
     }
+
     public String toString() {
       return String.format("NamedLock[%s]", name);
     }
+
+    public final void DoWait() throws Exception {
+      final int v = calledNotify;
+      while (v == calledNotify) {
+        wait();
+      }
+    }
+
+    public final void DoWait(long t) throws Exception {
+      final int v = calledNotify;
+      final long target = System.currentTimeMillis() + (t / 2);
+      while (v == calledNotify && (t < 0 || System.currentTimeMillis() < target)) {
+        wait(t);
+      }
+    }
+
+    public final void DoNotifyAll() throws Exception {
+      calledNotify++;
+      notifyAll();
+    }
+
+    public final void DoNotify() throws Exception {
+      calledNotify++;
+      notify();
+    }
   }
 
   public static final class MonitorUsage {
@@ -91,7 +119,7 @@
   public static class LockController {
     private static enum Action { HOLD, RELEASE, NOTIFY, NOTIFY_ALL, WAIT, TIMED_WAIT }
 
-    public final Object lock;
+    public final NamedLock lock;
     public final long timeout;
     private final AtomicStampedReference<Action> action;
     private volatile Thread runner = null;
@@ -100,10 +128,10 @@
     private static final AtomicInteger cnt = new AtomicInteger(0);
     private volatile Throwable exe;
 
-    public LockController(Object lock) {
+    public LockController(NamedLock lock) {
       this(lock, 10 * 1000);
     }
-    public LockController(Object lock, long timeout) {
+    public LockController(NamedLock lock, long timeout) {
       this.lock = lock;
       this.timeout = timeout;
       this.action = new AtomicStampedReference(Action.HOLD, 0);
@@ -177,16 +205,16 @@
                       Thread.yield();
                       break;
                     case NOTIFY:
-                      lock.notify();
+                      lock.DoNotify();
                       break;
                     case NOTIFY_ALL:
-                      lock.notifyAll();
+                      lock.DoNotifyAll();
                       break;
                     case TIMED_WAIT:
-                      lock.wait(timeout);
+                      lock.DoWait(timeout);
                       break;
                     case WAIT:
-                      lock.wait();
+                      lock.DoWait();
                       break;
                     default:
                       throw new Error("Unknown action " + action);
diff --git a/test/1933-monitor-current-contended/src/art/Monitors.java b/test/1933-monitor-current-contended/src/art/Monitors.java
index b28a3ee..7fe2b60 100644
--- a/test/1933-monitor-current-contended/src/art/Monitors.java
+++ b/test/1933-monitor-current-contended/src/art/Monitors.java
@@ -36,12 +36,40 @@
 
   public static class NamedLock {
     public final String name;
+    private volatile int calledNotify;
     public NamedLock(String name) {
       this.name = name;
+      calledNotify = 0;
     }
+
     public String toString() {
       return String.format("NamedLock[%s]", name);
     }
+
+    public final void DoWait() throws Exception {
+      final int v = calledNotify;
+      while (v == calledNotify) {
+        wait();
+      }
+    }
+
+    public final void DoWait(long t) throws Exception {
+      final int v = calledNotify;
+      final long target = System.currentTimeMillis() + (t / 2);
+      while (v == calledNotify && (t < 0 || System.currentTimeMillis() < target)) {
+        wait(t);
+      }
+    }
+
+    public final void DoNotifyAll() throws Exception {
+      calledNotify++;
+      notifyAll();
+    }
+
+    public final void DoNotify() throws Exception {
+      calledNotify++;
+      notify();
+    }
   }
 
   public static final class MonitorUsage {
@@ -91,7 +119,7 @@
   public static class LockController {
     private static enum Action { HOLD, RELEASE, NOTIFY, NOTIFY_ALL, WAIT, TIMED_WAIT }
 
-    public final Object lock;
+    public final NamedLock lock;
     public final long timeout;
     private final AtomicStampedReference<Action> action;
     private volatile Thread runner = null;
@@ -100,10 +128,10 @@
     private static final AtomicInteger cnt = new AtomicInteger(0);
     private volatile Throwable exe;
 
-    public LockController(Object lock) {
+    public LockController(NamedLock lock) {
       this(lock, 10 * 1000);
     }
-    public LockController(Object lock, long timeout) {
+    public LockController(NamedLock lock, long timeout) {
       this.lock = lock;
       this.timeout = timeout;
       this.action = new AtomicStampedReference(Action.HOLD, 0);
@@ -177,16 +205,16 @@
                       Thread.yield();
                       break;
                     case NOTIFY:
-                      lock.notify();
+                      lock.DoNotify();
                       break;
                     case NOTIFY_ALL:
-                      lock.notifyAll();
+                      lock.DoNotifyAll();
                       break;
                     case TIMED_WAIT:
-                      lock.wait(timeout);
+                      lock.DoWait(timeout);
                       break;
                     case WAIT:
-                      lock.wait();
+                      lock.DoWait();
                       break;
                     default:
                       throw new Error("Unknown action " + action);
diff --git a/test/1933-monitor-current-contended/src/art/Test1933.java b/test/1933-monitor-current-contended/src/art/Test1933.java
index e21c395..194a043 100644
--- a/test/1933-monitor-current-contended/src/art/Test1933.java
+++ b/test/1933-monitor-current-contended/src/art/Test1933.java
@@ -34,9 +34,13 @@
      controller1.waitForLockToBeHeld();
      controller1.DoWait();
      controller1.waitForNotifySleep();
-     System.out.println("c1 is contending for monitor: " + controller1.getWorkerContendedMonitor());
+     // Spurious wakeups can hurt us here. Just retry until we get the result we expect. The test
+     // will timeout eventually.
+     Object mon = controller1.getWorkerContendedMonitor();
+     for (; mon == null; mon = controller1.getWorkerContendedMonitor()) { Thread.yield(); }
+     System.out.println("c1 is contending for monitor: " + mon);
      synchronized (lk) {
-       lk.notifyAll();
+       lk.DoNotifyAll();
      }
      controller1.DoUnlock();
   }
diff --git a/test/529-checker-unresolved/src/Main.java b/test/529-checker-unresolved/src/Main.java
index c2683ac..255ce78 100644
--- a/test/529-checker-unresolved/src/Main.java
+++ b/test/529-checker-unresolved/src/Main.java
@@ -45,21 +45,21 @@
   }
 
   /// CHECK-START: void Main.callUnresolvedStaticFieldAccess() register (before)
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimByte
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimChar
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimInt
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimLong
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimFloat
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimDouble
-  /// CHECK:        UnresolvedStaticFieldSet field_type:PrimNot
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Int8
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Uint16
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Int32
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Int64
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Float32
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Float64
+  /// CHECK:        UnresolvedStaticFieldSet field_type:Reference
 
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimByte
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimChar
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimInt
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimLong
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimFloat
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimDouble
-  /// CHECK:        UnresolvedStaticFieldGet field_type:PrimNot
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Int8
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Uint16
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Int32
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Int64
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Float32
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Float64
+  /// CHECK:        UnresolvedStaticFieldGet field_type:Reference
   static public void callUnresolvedStaticFieldAccess() {
     Object o = new Object();
     UnresolvedClass.staticByte = (byte)1;
@@ -90,21 +90,21 @@
   }
 
   /// CHECK-START: void Main.callUnresolvedInstanceFieldAccess(UnresolvedClass) register (before)
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimByte
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimChar
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimInt
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimLong
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimFloat
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimDouble
-  /// CHECK:        UnresolvedInstanceFieldSet field_type:PrimNot
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Int8
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Uint16
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Int32
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Int64
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Float32
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Float64
+  /// CHECK:        UnresolvedInstanceFieldSet field_type:Reference
 
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimByte
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimChar
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimInt
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimLong
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimFloat
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimDouble
-  /// CHECK:        UnresolvedInstanceFieldGet field_type:PrimNot
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Int8
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Uint16
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Int32
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Int64
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Float32
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Float64
+  /// CHECK:        UnresolvedInstanceFieldGet field_type:Reference
   static public void callUnresolvedInstanceFieldAccess(UnresolvedClass c) {
     Object o = new Object();
     c.instanceByte = (byte)1;
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 1f1920c..55873ea 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -63,16 +63,12 @@
   /// CHECK-START-X86_64: int Main.testSimple(int) sharpening (after)
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
-  /// CHECK-START-MIPS: int Main.testSimple(int) pc_relative_fixups_mips (after)
-  /// CHECK:                MipsComputeBaseMethodAddress
-  /// CHECK-NOT:            MipsComputeBaseMethodAddress
-
   /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after)
   /// CHECK:                X86ComputeBaseMethodAddress
   /// CHECK-NOT:            X86ComputeBaseMethodAddress
 
   public static int testSimple(int x) {
-    // This call should use PC-relative dex cache array load to retrieve the target method.
+    // This call should use PC-relative .bss array load to retrieve the target method.
     return $noinline$foo(x);
   }
 
@@ -104,14 +100,6 @@
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
-  /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) pc_relative_fixups_mips (after)
-  /// CHECK:                MipsComputeBaseMethodAddress
-  /// CHECK-NOT:            MipsComputeBaseMethodAddress
-
-  /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) pc_relative_fixups_mips (after)
-  /// CHECK:                MipsComputeBaseMethodAddress
-  /// CHECK-NEXT:           If
-
   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
   /// CHECK:                X86ComputeBaseMethodAddress
   /// CHECK-NOT:            X86ComputeBaseMethodAddress
@@ -122,7 +110,7 @@
 
   public static int testDiamond(boolean negate, int x) {
     // These calls should use PC-relative loads to retrieve the target method.
-    // PC-relative bases used by MIPS and X86 should be pulled before the If.
+    // PC-relative bases used by MIPS32R2 and X86 should be pulled before the If.
     if (negate) {
       return $noinline$foo(-x);
     } else {
@@ -130,24 +118,6 @@
     }
   }
 
-  /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (before)
-  /// CHECK-NOT:            MipsComputeBaseMethodAddress
-
-  /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after)
-  /// CHECK:                MipsComputeBaseMethodAddress
-  /// CHECK-NOT:            MipsComputeBaseMethodAddress
-
-  /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after)
-  /// CHECK:                InvokeStaticOrDirect
-  /// CHECK-NOT:            InvokeStaticOrDirect
-
-  /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after)
-  /// CHECK:                ArrayLength
-  /// CHECK-NEXT:           MipsComputeBaseMethodAddress
-  /// CHECK-NEXT:           Goto
-  /// CHECK:                begin_block
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
-
   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before)
   /// CHECK-NOT:            X86ComputeBaseMethodAddress
 
@@ -167,23 +137,13 @@
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
   public static int testLoop(int[] array, int x) {
-    // PC-relative bases used by MIPS and X86 should be pulled before the loop.
+    // PC-relative bases used by MIPS32R2 and X86 should be pulled before the loop.
     for (int i : array) {
       x += $noinline$foo(i);
     }
     return x;
   }
 
-  /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_mips (before)
-  /// CHECK-NOT:            MipsComputeBaseMethodAddress
-
-  /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_mips (after)
-  /// CHECK:                If
-  /// CHECK:                begin_block
-  /// CHECK:                ArrayLength
-  /// CHECK-NEXT:           MipsComputeBaseMethodAddress
-  /// CHECK-NEXT:           Goto
-
   /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before)
   /// CHECK-NOT:            X86ComputeBaseMethodAddress
 
@@ -195,7 +155,7 @@
   /// CHECK-NEXT:           Goto
 
   public static int testLoopWithDiamond(int[] array, boolean negate, int x) {
-    // PC-relative bases used by MIPS and X86 should be pulled before the loop
+    // PC-relative bases used by MIPS32R2 and X86 should be pulled before the loop
     // but not outside the if.
     if (array != null) {
       for (int i : array) {
diff --git a/test/566-polymorphic-inlining/run b/test/566-polymorphic-inlining/run
new file mode 100644
index 0000000..2919f46
--- /dev/null
+++ b/test/566-polymorphic-inlining/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -Xjitinitialsize:32M to prevent profiling info creation failure.
+exec ${RUN} \
+  --runtime-option -Xjitinitialsize:32M \
+  "${@}"
diff --git a/test/597-deopt-invoke-stub/src/Main.java b/test/597-deopt-invoke-stub/src/Main.java
index 0751783..8c6f069 100644
--- a/test/597-deopt-invoke-stub/src/Main.java
+++ b/test/597-deopt-invoke-stub/src/Main.java
@@ -16,8 +16,8 @@
 
 public class Main implements Runnable {
     static final int numberOfThreads = 2;
-    volatile static boolean sExitFlag = false;
-    volatile static boolean sEntered = false;
+    static boolean sExitFlag = false;
+    static boolean sEntered = false;
     int threadIndex;
 
     private static native void deoptimizeAll();
@@ -46,8 +46,17 @@
     private static int $noinline$bar() {
         // Should be entered via interpreter bridge.
         assertIsInterpreted();
-        sEntered = true;
-        while (!sExitFlag) {}
+        synchronized (Main.class) {
+            sEntered = true;
+            Main.class.notify();
+            while (!sExitFlag) {
+                try {
+                    Main.class.wait();
+                } catch (InterruptedException e) {
+                    throw new Error("Unexpected exception.");
+                }
+            }
+        }
         assertIsInterpreted();
         return 0x1234;
     }
@@ -62,11 +71,20 @@
 
     public void run() {
         if (threadIndex == 0) {
-            while (!sEntered) {
-              Thread.yield();
+            synchronized (Main.class) {
+                while (!sEntered) {
+                    try {
+                        Main.class.wait();
+                    } catch (InterruptedException e) {
+                        throw new Error("Unexpected exception.");
+                    }
+                }
             }
             deoptimizeAll();
-            sExitFlag = true;
+            synchronized (Main.class) {
+                sExitFlag = true;
+                Main.class.notify();
+            }
         } else {
             ensureJitCompiled(Main.class, "$noinline$foo");
             $noinline$foo();
diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java
index e018b56..9643b90 100644
--- a/test/651-checker-byte-simd-minmax/src/Main.java
+++ b/test/651-checker-byte-simd-minmax/src/Main.java
@@ -165,6 +165,28 @@
     }
   }
 
+  /// CHECK-START: void Main.doitMin100(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:i\d+>>  InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]       loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  private static void doitMin100(byte[] x, byte[] y) {
+    int min = Math.min(x.length, y.length);
+    for (int i = 0; i < min; i++) {
+      x[i] = (byte) Math.min(y[i], 100);
+    }
+  }
+
   public static void main(String[] args) {
     // Initialize cross-values for all possible values.
     int total = 256 * 256;
@@ -202,6 +224,11 @@
       byte expected = (byte) Math.max(y[i] & 0xff, z[i] & 0xff);
       expectEquals(expected, x[i]);
     }
+    doitMin100(x, y);
+    for (int i = 0; i < total; i++) {
+      byte expected = (byte) Math.min(y[i], 100);
+      expectEquals(expected, x[i]);
+    }
 
     System.out.println("passed");
   }
diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java
index 57cad9b..8a0262c 100644
--- a/test/651-checker-char-simd-minmax/src/Main.java
+++ b/test/651-checker-char-simd-minmax/src/Main.java
@@ -89,6 +89,28 @@
     }
   }
 
+  /// CHECK-START: void Main.doitMin100(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:c\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:i\d+>>  InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.doitMin100(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]       loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] unsigned:true loop:<<Loop>>  outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  private static void doitMin100(char[] x, char[] y) {
+    int min = Math.min(x.length, y.length);
+    for (int i = 0; i < min; i++) {
+      x[i] = (char) Math.min(y[i], 100);
+    }
+  }
+
   public static void main(String[] args) {
     char[] interesting = {
       0x0000, 0x0001, 0x007f, 0x0080, 0x0081, 0x00ff,
@@ -124,6 +146,11 @@
       char expected = (char) Math.max(y[i], z[i]);
       expectEquals(expected, x[i]);
     }
+    doitMin100(x, y);
+    for (int i = 0; i < total; i++) {
+      char expected = (char) Math.min(y[i], 100);
+      expectEquals(expected, x[i]);
+    }
 
     System.out.println("passed");
   }
diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java
index 4f2a7a4..ffbf73b 100644
--- a/test/651-checker-short-simd-minmax/src/Main.java
+++ b/test/651-checker-short-simd-minmax/src/Main.java
@@ -165,6 +165,28 @@
     }
   }
 
+  /// CHECK-START: void Main.doitMin100(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:s\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:i\d+>>  InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.doitMin100(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                     loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]       loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  private static void doitMin100(short[] x, short[] y) {
+    int min = Math.min(x.length, y.length);
+    for (int i = 0; i < min; i++) {
+      x[i] = (short) Math.min(y[i], 100);
+    }
+  }
+
   public static void main(String[] args) {
     short[] interesting = {
       (short) 0x0000, (short) 0x0001, (short) 0x007f,
@@ -216,6 +238,11 @@
       short expected = (short) Math.max(y[i] & 0xffff, z[i] & 0xffff);
       expectEquals(expected, x[i]);
     }
+    doitMin100(x, y);
+    for (int i = 0; i < total; i++) {
+      short expected = (short) Math.min(y[i], 100);
+      expectEquals(expected, x[i]);
+    }
 
     System.out.println("passed");
   }
diff --git a/test/656-checker-simd-opt/src/Main.java b/test/656-checker-simd-opt/src/Main.java
index 091633f..39a126f 100644
--- a/test/656-checker-simd-opt/src/Main.java
+++ b/test/656-checker-simd-opt/src/Main.java
@@ -92,7 +92,91 @@
     }
   }
 
-  public static void main(String[] args) {
+  /// CHECK-START: long Main.longInductionReduction(long[]) loop_optimization (before)
+  /// CHECK-DAG: <<L0:j\d+>>    LongConstant 0             loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1             loop:none
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0              loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>] loop:none
+  /// CHECK-DAG: <<Phi1:j\d+>>  Phi [<<L0>>,<<Add1:j\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>  Phi [<<L1>>,<<Add2:j\d+>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add2>>       Add [<<Phi2>>,<<Get>>]     loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add1>>       Add [<<Phi1>>,<<L1>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.longInductionReduction(long[]) loop_optimization (after)
+  /// CHECK-DAG: <<L0:j\d+>>    LongConstant 0               loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1               loop:none
+  /// CHECK-DAG: <<L2:j\d+>>    LongConstant 2               loop:none
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]   loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Get>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>   VecSetScalars [<<L1>>]       loop:none
+  /// CHECK-DAG: <<Phi1:j\d+>>  Phi [<<L0>>,{{j\d+}}]        loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>  Phi [<<Set>>,{{d\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                VecAdd [<<Phi2>>,<<Rep>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi1>>,<<L2>>]        loop:<<Loop>>      outer_loop:none
+  static long longInductionReduction(long[] y) {
+    long x = 1;
+    for (long i = 0; i < 10; i++) {
+      x += y[0];
+    }
+    return x;
+  }
+
+  /// CHECK-START: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (before)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
+  /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                       loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]          loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,<<Add:i\d+>>]           loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<Get>>]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add>>        Add [<<Phi>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
+  /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                       loop:none
+  /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]          loop:none
+  /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<Get>>]            loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
+  static void intVectorLongInvariant(int[] x, long[] y) {
+    for (int i = 0; i < 100; i++) {
+      x[i] = (int) y[0];
+    }
+  }
+
+  /// CHECK-START: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                        loop:none
+  /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                        loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1                       loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,<<Add:i\d+>>]            loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:i\d+>>   ArrayGet [{{l\d+}},<<Phi>>]          loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>  TypeConversion [<<Get>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<AddL:j\d+>>  Add [<<Cnv1>>,<<L1>>]                loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:i\d+>>  TypeConversion [<<AddL>>]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                ArraySet [{{l\d+}},<<Phi>>,<<Cnv2>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add>>        Add [<<Phi>>,<<I1>>]                 loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
+  /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1                      loop:none
+  /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<L1>>]             loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>  VecLoad [{{l\d+}},<<Phi>>]          loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add:d\d+>>   VecAdd [<<Load>>,<<Rep>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
+  static void longCanBeDoneWithInt(int[] x, int[] y) {
+    for (int i = 0; i < 100; i++) {
+      x[i] = (int) (y[i] + 1L);
+    }
+  }
+
+  static void testUnroll() {
     float[] x = new float[100];
     float[] y = new float[100];
     for (int i = 0; i < 100; i++) {
@@ -104,51 +188,89 @@
       expectEquals(5.0f, x[i]);
       expectEquals(2.0f, y[i]);
     }
-    {
-      int[] a = new int[100];
-      int[] b = new int[100];
-      for (int i = 0; i < 100; i++) {
-        a[i] = 0;
-        b[i] = i;
-      }
-      stencil(a, b, 100);
-      for (int i = 1; i < 99; i++) {
-        int e = i + i + i;
-        expectEquals(e, a[i]);
-        expectEquals(i, b[i]);
-      }
+  }
+
+  static void testStencil1() {
+    int[] a = new int[100];
+    int[] b = new int[100];
+    for (int i = 0; i < 100; i++) {
+      a[i] = 0;
+      b[i] = i;
     }
-    {
-      int[] a = new int[100];
-      int[] b = new int[100];
-      for (int i = 0; i < 100; i++) {
-        a[i] = 0;
-        b[i] = i;
-      }
-      stencilSubInt(a, b, 100);
-      for (int i = 1; i < 99; i++) {
-        int e = i + i + i;
-        expectEquals(e, a[i]);
-        expectEquals(i, b[i]);
-      }
+    stencil(a, b, 100);
+    for (int i = 1; i < 99; i++) {
+      int e = i + i + i;
+      expectEquals(e, a[i]);
+      expectEquals(i, b[i]);
     }
-    {
-      int[] a = new int[100];
-      int[] b = new int[100];
-      for (int i = 0; i < 100; i++) {
-        a[i] = 0;
-        b[i] = i;
-      }
-      stencilAddInt(a, b, 100);
-      for (int i = 1; i < 99; i++) {
-        int e = i + i + i;
-        expectEquals(e, a[i]);
-        expectEquals(i, b[i]);
-      }
+  }
+
+  static void testStencil2() {
+    int[] a = new int[100];
+    int[] b = new int[100];
+    for (int i = 0; i < 100; i++) {
+      a[i] = 0;
+      b[i] = i;
     }
+    stencilSubInt(a, b, 100);
+    for (int i = 1; i < 99; i++) {
+      int e = i + i + i;
+      expectEquals(e, a[i]);
+      expectEquals(i, b[i]);
+    }
+  }
+
+  static void testStencil3() {
+    int[] a = new int[100];
+    int[] b = new int[100];
+    for (int i = 0; i < 100; i++) {
+      a[i] = 0;
+      b[i] = i;
+    }
+    stencilAddInt(a, b, 100);
+    for (int i = 1; i < 99; i++) {
+      int e = i + i + i;
+      expectEquals(e, a[i]);
+      expectEquals(i, b[i]);
+    }
+  }
+
+  static void testTypes() {
+    int[] a = new int[100];
+    int[] b = new int[100];
+    long[] l = { 3 };
+    expectEquals(31, longInductionReduction(l));
+    intVectorLongInvariant(a, l);
+    for (int i = 0; i < 100; i++) {
+      expectEquals(3, a[i]);
+    }
+    longCanBeDoneWithInt(b, a);
+    for (int i = 0; i < 100; i++) {
+      expectEquals(4, b[i]);
+    }
+  }
+
+  public static void main(String[] args) {
+    testUnroll();
+    testStencil1();
+    testStencil2();
+    testStencil3();
+    testTypes();
     System.out.println("passed");
   }
 
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
   private static void expectEquals(float expected, float result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
diff --git a/test/660-checker-simd-sad-byte/expected.txt b/test/660-checker-simd-sad-byte/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-byte/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-byte/info.txt b/test/660-checker-simd-sad-byte/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-byte/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
new file mode 100644
index 0000000..72d1c24
--- /dev/null
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ */
+public class Main {
+
+  // TODO: lower precision still coming, b/64091002
+
+  private static byte sadByte2Byte(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    byte sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(b1[i] - b2[i]);
+    }
+    return sad;
+  }
+
+  private static byte sadByte2ByteAlt(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    byte sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  private static byte sadByte2ByteAlt2(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    byte sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  private static short sadByte2Short(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(b1[i] - b2[i]);
+    }
+    return sad;
+  }
+
+  private static short sadByte2ShortAlt(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  private static short sadByte2ShortAlt2(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadByte2Int(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  private static int sadByte2Int(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(b1[i] - b2[i]);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  private static int sadByte2IntAlt(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  private static int sadByte2IntAlt2(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      byte s = b1[i];
+      byte p = b2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadByte2Long(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  private static long sadByte2Long(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long x = b1[i];
+      long y = b2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:b\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  private static long sadByte2LongAt1(byte[] b1, byte[] b2) {
+    int min_length = Math.min(b1.length, b2.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      long x = b1[i];
+      long y = b2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    byte[] b1 = { 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    byte[] b2 = { 0,  127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(-1, sadByte2Byte(b1, b2));
+    expectEquals(-1, sadByte2Byte(b2, b1));
+    expectEquals(-1, sadByte2ByteAlt(b1, b2));
+    expectEquals(-1, sadByte2ByteAlt(b2, b1));
+    expectEquals(-1, sadByte2ByteAlt2(b1, b2));
+    expectEquals(-1, sadByte2ByteAlt2(b2, b1));
+    expectEquals(255, sadByte2Short(b1, b2));
+    expectEquals(255, sadByte2Short(b2, b1));
+    expectEquals(255, sadByte2ShortAlt(b1, b2));
+    expectEquals(255, sadByte2ShortAlt(b2, b1));
+    expectEquals(255, sadByte2ShortAlt2(b1, b2));
+    expectEquals(255, sadByte2ShortAlt2(b2, b1));
+    expectEquals(255, sadByte2Int(b1, b2));
+    expectEquals(255, sadByte2Int(b2, b1));
+    expectEquals(255, sadByte2IntAlt(b1, b2));
+    expectEquals(255, sadByte2IntAlt(b2, b1));
+    expectEquals(255, sadByte2IntAlt2(b1, b2));
+    expectEquals(255, sadByte2IntAlt2(b2, b1));
+    expectEquals(255, sadByte2Long(b1, b2));
+    expectEquals(255L, sadByte2Long(b2, b1));
+    expectEquals(256L, sadByte2LongAt1(b1, b2));
+    expectEquals(256L, sadByte2LongAt1(b2, b1));
+
+    // Use cross-values to test all cases.
+    // One for scalar cleanup.
+    int n = 256;
+    int m = n * n + 1;
+    int k = 0;
+    b1 = new byte[m];
+    b2 = new byte[m];
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        b1[k] = (byte) i;
+        b2[k] = (byte) j;
+        k++;
+      }
+    }
+    b1[k] = 10;
+    b2[k] = 2;
+    expectEquals(8, sadByte2Byte(b1, b2));
+    expectEquals(8, sadByte2ByteAlt(b1, b2));
+    expectEquals(8, sadByte2ByteAlt2(b1, b2));
+    expectEquals(21768, sadByte2Short(b1, b2));
+    expectEquals(21768, sadByte2ShortAlt(b1, b2));
+    expectEquals(21768, sadByte2ShortAlt2(b1, b2));
+    expectEquals(5592328, sadByte2Int(b1, b2));
+    expectEquals(5592328, sadByte2IntAlt(b1, b2));
+    expectEquals(5592328, sadByte2IntAlt2(b1, b2));
+    expectEquals(5592328L, sadByte2Long(b1, b2));
+    expectEquals(5592329L, sadByte2LongAt1(b1, b2));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/660-checker-simd-sad-char/expected.txt b/test/660-checker-simd-sad-char/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-char/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-char/info.txt b/test/660-checker-simd-sad-char/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-char/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
new file mode 100644
index 0000000..bb0c58f
--- /dev/null
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ */
+public class Main {
+
+  // TODO: lower precision still coming, b/64091002
+
+  // TODO: consider unsigned SAD too, b/64091002
+
+  private static char sadShort2Short(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    char sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(s1[i] - s2[i]);
+    }
+    return sad;
+  }
+
+  private static char sadShort2ShortAlt(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    char sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      char s = s1[i];
+      char p = s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  private static char sadShort2ShortAlt2(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    char sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      char s = s1[i];
+      char p = s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2Int(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2Int(char[], char[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static int sadShort2Int(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(s1[i] - s2[i]);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2IntAlt(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2IntAlt(char[], char[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static int sadShort2IntAlt(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      char s = s1[i];
+      char p = s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2IntAlt2(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2IntAlt2(char[], char[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static int sadShort2IntAlt2(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      char s = s1[i];
+      char p = s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadShort2Long(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadShort2Long(char[], char[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static long sadShort2Long(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long x = s1[i];
+      long y = s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadShort2LongAt1(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadShort2LongAt1(char[], char[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static long sadShort2LongAt1(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      long x = s1[i];
+      long y = s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    char[] s1 = { 0, 0x8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    char[] s2 = { 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(1, sadShort2Short(s1, s2));
+    expectEquals(1, sadShort2Short(s2, s1));
+    expectEquals(1, sadShort2ShortAlt(s1, s2));
+    expectEquals(1, sadShort2ShortAlt(s2, s1));
+    expectEquals(1, sadShort2ShortAlt2(s1, s2));
+    expectEquals(1, sadShort2ShortAlt2(s2, s1));
+    expectEquals(1, sadShort2Int(s1, s2));
+    expectEquals(1, sadShort2Int(s2, s1));
+    expectEquals(1, sadShort2IntAlt(s1, s2));
+    expectEquals(1, sadShort2IntAlt(s2, s1));
+    expectEquals(1, sadShort2IntAlt2(s1, s2));
+    expectEquals(1, sadShort2IntAlt2(s2, s1));
+    expectEquals(1L, sadShort2Long(s1, s2));
+    expectEquals(1L, sadShort2Long(s2, s1));
+    expectEquals(2L, sadShort2LongAt1(s1, s2));
+    expectEquals(2L, sadShort2LongAt1(s2, s1));
+
+    // Use cross-values to test all cases.
+    char[] interesting = {
+      (char) 0x0000,
+      (char) 0x0001,
+      (char) 0x0002,
+      (char) 0x1234,
+      (char) 0x8000,
+      (char) 0x8001,
+      (char) 0x7fff,
+      (char) 0xffff
+    };
+    int n = interesting.length;
+    int m = n * n + 1;
+    s1 = new char[m];
+    s2 = new char[m];
+    int k = 0;
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        s1[k] = interesting[i];
+        s2[k] = interesting[j];
+        k++;
+      }
+    }
+    s1[k] = 10;
+    s2[k] = 2;
+    expectEquals(56196, sadShort2Short(s1, s2));
+    expectEquals(56196, sadShort2ShortAlt(s1, s2));
+    expectEquals(56196, sadShort2ShortAlt2(s1, s2));
+    expectEquals(1497988, sadShort2Int(s1, s2));
+    expectEquals(1497988, sadShort2IntAlt(s1, s2));
+    expectEquals(1497988, sadShort2IntAlt2(s1, s2));
+    expectEquals(1497988L, sadShort2Long(s1, s2));
+    expectEquals(1497989L, sadShort2LongAt1(s1, s2));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/660-checker-simd-sad-int/expected.txt b/test/660-checker-simd-sad-int/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-int/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-int/info.txt b/test/660-checker-simd-sad-int/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-int/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
new file mode 100644
index 0000000..0daeedd
--- /dev/null
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ */
+public class Main {
+
+  /// CHECK-START: int Main.sadInt2Int(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadInt2Int(int[] x, int[] y) {
+    int min_length = Math.min(x.length, y.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(x[i] - y[i]);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                       loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                       loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub1:i\d+>>   Sub [<<Get2>>,<<Get1>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub2:i\d+>>   Sub [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Select:i\d+>> Select [<<Sub2>>,<<Sub1>>,{{z\d+}}] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Select>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]            loop:<<Loop>>      outer_loop:none
+  //
+  // No ABS? No SAD!
+  //
+  /// CHECK-START-ARM64: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static int sadInt2IntAlt(int[] x, int[] y) {
+    int min_length = Math.min(x.length, y.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      int s = x[i];
+      int p = y[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadInt2IntAlt2(int[] x, int[] y) {
+    int min_length = Math.min(x.length, y.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      int s = x[i];
+      int p = y[i];
+      int m = s - p;
+      if (m < 0) m = -m;
+      sad += m;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadInt2Long(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadInt2Long(int[] x, int[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long s = x[i];
+      long p = y[i];
+      sad += Math.abs(s - p);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadInt2LongAt1(int[] x, int[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      long s = x[i];
+      long p = y[i];
+      sad += Math.abs(s - p);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    int[] x = { 0, Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    int[] y = { 0, Integer.MIN_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(1, sadInt2Int(x, y));
+    expectEquals(1, sadInt2Int(y, x));
+    expectEquals(-1, sadInt2IntAlt(x, y));
+    expectEquals(-1, sadInt2IntAlt(y, x));
+    expectEquals(1, sadInt2IntAlt2(x, y));
+    expectEquals(1, sadInt2IntAlt2(y, x));
+    expectEquals(4294967295L, sadInt2Long(x, y));
+    expectEquals(4294967295L, sadInt2Long(y, x));
+    expectEquals(4294967296L, sadInt2LongAt1(x, y));
+    expectEquals(4294967296L, sadInt2LongAt1(y, x));
+
+    // Use cross-values for the interesting values.
+    int[] interesting = {
+      0x00000000, 0x00000001, 0x00007fff, 0x00008000, 0x00008001, 0x0000ffff,
+      0x00010000, 0x00010001, 0x00017fff, 0x00018000, 0x00018001, 0x0001ffff,
+      0x7fff0000, 0x7fff0001, 0x7fff7fff, 0x7fff8000, 0x7fff8001, 0x7fffffff,
+      0x80000000, 0x80000001, 0x80007fff, 0x80008000, 0x80008001, 0x8000ffff,
+      0x80010000, 0x80010001, 0x80017fff, 0x80018000, 0x80018001, 0x8001ffff,
+      0xffff0000, 0xffff0001, 0xffff7fff, 0xffff8000, 0xffff8001, 0xffffffff
+    };
+    int n = interesting.length;
+    int m = n * n + 1;
+    x = new int[m];
+    y = new int[m];
+    int k = 0;
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        x[k] = interesting[i];
+        y[k] = interesting[j];
+        k++;
+      }
+    }
+    x[k] = 10;
+    y[k] = 2;
+    expectEquals(8, sadInt2Int(x, y));
+    expectEquals(-13762600, sadInt2IntAlt(x, y));
+    expectEquals(8, sadInt2IntAlt2(x, y));
+    expectEquals(2010030931928L, sadInt2Long(x, y));
+    expectEquals(2010030931929L, sadInt2LongAt1(x, y));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/660-checker-simd-sad-long/expected.txt b/test/660-checker-simd-sad-long/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-long/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-long/info.txt b/test/660-checker-simd-sad-long/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-long/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-long/src/Main.java b/test/660-checker-simd-sad-long/src/Main.java
new file mode 100644
index 0000000..06f62bd
--- /dev/null
+++ b/test/660-checker-simd-sad-long/src/Main.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ */
+public class Main {
+
+  /// CHECK-START: long Main.sadLong2Long(long[], long[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadLong2Long(long[] x, long[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(x[i] - y[i]);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadLong2LongAlt(long[], long[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                       loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                       loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub1:j\d+>>   Sub [<<Get2>>,<<Get1>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub2:j\d+>>   Sub [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Select:j\d+>> Select [<<Sub2>>,<<Sub1>>,{{z\d+}}] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Select>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]            loop:<<Loop>>      outer_loop:none
+  //
+  // No ABS? No SAD!
+  //
+  /// CHECK-START: long Main.sadLong2LongAlt(long[], long[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  private static long sadLong2LongAlt(long[] x, long[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long s = x[i];
+      long p = y[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadLong2LongAlt2(long[] x, long[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long s = x[i];
+      long p = y[i];
+      long m = s - p;
+      if (m < 0) m = -m;
+      sad += m;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:j\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadLong2LongAt1(long[] x, long[] y) {
+    int min_length = Math.min(x.length, y.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(x[i] - y[i]);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    long[] x = { 0, Long.MIN_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    long[] y = { 0, Long.MAX_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(1L, sadLong2Long(x, y));
+    expectEquals(1L, sadLong2Long(y, x));
+    expectEquals(-1L, sadLong2LongAlt(x, y));
+    expectEquals(-1L, sadLong2LongAlt(y, x));
+    expectEquals(1L, sadLong2LongAlt2(x, y));
+    expectEquals(1L, sadLong2LongAlt2(y, x));
+    expectEquals(2L, sadLong2LongAt1(x, y));
+    expectEquals(2L, sadLong2LongAt1(y, x));
+
+    // Use cross-values for the interesting values.
+    long[] interesting = {
+      0x0000000000000000L, 0x0000000000000001L, 0x000000007fffffffL,
+      0x0000000080000000L, 0x0000000080000001L, 0x00000000ffffffffL,
+      0x0000000100000000L, 0x0000000100000001L, 0x000000017fffffffL,
+      0x0000000180000000L, 0x0000000180000001L, 0x00000001ffffffffL,
+      0x7fffffff00000000L, 0x7fffffff00000001L, 0x7fffffff7fffffffL,
+      0x7fffffff80000000L, 0x7fffffff80000001L, 0x7fffffffffffffffL,
+      0x8000000000000000L, 0x8000000000000001L, 0x800000007fffffffL,
+      0x8000000080000000L, 0x8000000080000001L, 0x80000000ffffffffL,
+      0x8000000100000000L, 0x8000000100000001L, 0x800000017fffffffL,
+      0x8000000180000000L, 0x8000000180000001L, 0x80000001ffffffffL,
+      0xffffffff00000000L, 0xffffffff00000001L, 0xffffffff7fffffffL,
+      0xffffffff80000000L, 0xffffffff80000001L, 0xffffffffffffffffL
+    };
+    int n = interesting.length;
+    int m = n * n + 1;
+    x = new long[m];
+    y = new long[m];
+    int k = 0;
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        x[k] = interesting[i];
+        y[k] = interesting[j];
+        k++;
+      }
+    }
+    x[k] = 10;
+    y[k] = 2;
+    expectEquals(8L, sadLong2Long(x, y));
+    expectEquals(-901943132200L, sadLong2LongAlt(x, y));
+    expectEquals(8L, sadLong2LongAlt2(x, y));
+    expectEquals(9L, sadLong2LongAt1(x, y));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/660-checker-simd-sad-short/expected.txt b/test/660-checker-simd-sad-short/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-short/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-short/info.txt b/test/660-checker-simd-sad-short/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-short/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
new file mode 100644
index 0000000..d94308e
--- /dev/null
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ */
+public class Main {
+
+  // TODO: lower precision still coming, b/64091002
+
+  private static short sadShort2Short(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(s1[i] - s2[i]);
+    }
+    return sad;
+  }
+
+  private static short sadShort2ShortAlt(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = s1[i];
+      short p = s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  private static short sadShort2ShortAlt2(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = s1[i];
+      short p = s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2Int(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadShort2Int(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(s1[i] - s2[i]);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadShort2IntAlt(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = s1[i];
+      short p = s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadShort2IntAlt2(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = s1[i];
+      short p = s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadShort2Long(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadShort2Long(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long x = s1[i];
+      long y = s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadShort2LongAt1(short[] s1, short[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      long x = s1[i];
+      long y = s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    short[] s1 = { 0, -32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    short[] s2 = { 0,  32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(-1, sadShort2Short(s1, s2));
+    expectEquals(-1, sadShort2Short(s2, s1));
+    expectEquals(-1, sadShort2ShortAlt(s1, s2));
+    expectEquals(-1, sadShort2ShortAlt(s2, s1));
+    expectEquals(-1, sadShort2ShortAlt2(s1, s2));
+    expectEquals(-1, sadShort2ShortAlt2(s2, s1));
+    expectEquals(65535, sadShort2Int(s1, s2));
+    expectEquals(65535, sadShort2Int(s2, s1));
+    expectEquals(65535, sadShort2IntAlt(s1, s2));
+    expectEquals(65535, sadShort2IntAlt(s2, s1));
+    expectEquals(65535, sadShort2IntAlt2(s1, s2));
+    expectEquals(65535, sadShort2IntAlt2(s2, s1));
+    expectEquals(65535L, sadShort2Long(s1, s2));
+    expectEquals(65535L, sadShort2Long(s2, s1));
+    expectEquals(65536L, sadShort2LongAt1(s1, s2));
+    expectEquals(65536L, sadShort2LongAt1(s2, s1));
+
+    // Use cross-values to test all cases.
+    short[] interesting = {
+      (short) 0x0000,
+      (short) 0x0001,
+      (short) 0x0002,
+      (short) 0x1234,
+      (short) 0x8000,
+      (short) 0x8001,
+      (short) 0x7fff,
+      (short) 0xffff
+    };
+    int n = interesting.length;
+    int m = n * n + 1;
+    s1 = new short[m];
+    s2 = new short[m];
+    int k = 0;
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        s1[k] = interesting[i];
+        s2[k] = interesting[j];
+        k++;
+      }
+    }
+    s1[k] = 10;
+    s2[k] = 2;
+    expectEquals(-18932, sadShort2Short(s1, s2));
+    expectEquals(-18932, sadShort2ShortAlt(s1, s2));
+    expectEquals(-18932, sadShort2ShortAlt2(s1, s2));
+    expectEquals(1291788, sadShort2Int(s1, s2));
+    expectEquals(1291788, sadShort2IntAlt(s1, s2));
+    expectEquals(1291788, sadShort2IntAlt2(s1, s2));
+    expectEquals(1291788L, sadShort2Long(s1, s2));
+    expectEquals(1291789L, sadShort2LongAt1(s1, s2));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java
index 71eb3cd..bcfa968 100644
--- a/test/661-checker-simd-reduc/src/Main.java
+++ b/test/661-checker-simd-reduc/src/Main.java
@@ -80,6 +80,101 @@
     return sum;
   }
 
+  /// CHECK-START: int Main.reductionIntChain() loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons1>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi2>>]  loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Get1>>]       loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Cons1>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:i\d+>>   Phi [<<Phi1>>,{{i\d+}}]       loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi3>>]  loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi4>>,<<Get2>>]       loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi3>>,<<Cons1>>]      loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 Return [<<Phi4>>]             loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
+  /// CHECK-START-ARM64: int Main.reductionIntChain() loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
+  /// CHECK-DAG: <<Set1:d\d+>>   VecSetScalars [<<Cons1>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set1>>,{{d\d+}}]       loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Red1:d\d+>>   VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr1:i\d+>>  VecExtractScalar [<<Red1>>]   loop:none
+  /// CHECK-DAG: <<Set2:d\d+>>   VecSetScalars [<<Extr1>>]     loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:d\d+>>   Phi [<<Set2>>,{{d\d+}}]       loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi3>>]   loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi4>>,<<Load2>>]   loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi3>>,<<Cons4>>]      loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Red2:d\d+>>   VecReduce [<<Phi4>>]          loop:none
+  /// CHECK-DAG: <<Extr2:i\d+>>  VecExtractScalar [<<Red2>>]   loop:none
+  /// CHECK-DAG:                 Return [<<Extr2>>]            loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
+  // NOTE: pattern is robust with respect to vector loop unrolling.
+  private static int reductionIntChain() {
+    int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+    int r = 1;
+    for (int i = 0; i < 16; i++) {
+      r += x[i];
+    }
+    for (int i = 0; i < 16; i++) {
+      r += x[i];
+    }
+    return r;
+  }
+
+  /// CHECK-START: int Main.reductionIntToLoop(int[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [{{l\d+}},<<Phi1>>]  loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Get>>]        loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Phi2>>,{{i\d+}}]       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:i\d+>>   Phi [<<Phi2>>,{{i\d+}}]       loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
+  /// CHECK-START-ARM64: int Main.reductionIntToLoop(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Extr>>,{{i\d+}}]       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:i\d+>>   Phi [<<Extr>>,{{i\d+}}]       loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
+  private static int reductionIntToLoop(int[] x) {
+    int r = 0;
+    for (int i = 0; i < 4; i++) {
+      r += x[i];
+    }
+    for (int i = r; i < 16; i++) {
+      r += i;
+    }
+    return r;
+  }
+
   /// CHECK-START: long Main.reductionLong(long[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Long0:j\d+>>  LongConstant 0                loop:none
@@ -468,10 +563,28 @@
     }
 
     // Test various reductions in loops.
+    int[] x0 = { 0, 0, 0, 0 };
+    int[] x1 = { 0, 0, 0, 1 };
+    int[] x2 = { 1, 1, 1, 1 };
     expectEquals(-74, reductionByte(xb));
     expectEquals(-27466, reductionShort(xs));
     expectEquals(38070, reductionChar(xc));
     expectEquals(365750, reductionInt(xi));
+    expectEquals(273, reductionIntChain());
+    expectEquals(120, reductionIntToLoop(x0));
+    expectEquals(121, reductionIntToLoop(x1));
+    expectEquals(118, reductionIntToLoop(x2));
+    expectEquals(-1205, reductionIntToLoop(xi));
+    expectEquals(365750L, reductionLong(xl));
+    expectEquals(-75, reductionByteM1(xb));
+    expectEquals(-27467, reductionShortM1(xs));
+    expectEquals(38069, reductionCharM1(xc));
+    expectEquals(365749, reductionIntM1(xi));
+    expectEquals(365749L, reductionLongM1(xl));
+    expectEquals(74, reductionMinusByte(xb));
+    expectEquals(27466, reductionMinusShort(xs));
+    expectEquals(27466, reductionMinusChar(xc));
+    expectEquals(-365750, reductionMinusInt(xi));
     expectEquals(365750L, reductionLong(xl));
     expectEquals(-75, reductionByteM1(xb));
     expectEquals(-27467, reductionShortM1(xs));
diff --git a/test/661-oat-writer-layout/expected.no-compiled-code.txt b/test/661-oat-writer-layout/expected.no-compiled-code.txt
new file mode 100644
index 0000000..4ed7577
--- /dev/null
+++ b/test/661-oat-writer-layout/expected.no-compiled-code.txt
@@ -0,0 +1 @@
+No OAT class
diff --git a/test/661-oat-writer-layout/expected.txt b/test/661-oat-writer-layout/expected.txt
new file mode 100644
index 0000000..db28e4f
--- /dev/null
+++ b/test/661-oat-writer-layout/expected.txt
@@ -0,0 +1,73 @@
+JNI_OnLoad called
+A::m_a$$$
+A::m_b$$$
+A::m_c$$$
+B::m_a$$$
+B::m_b$$$
+B::m_c$$$
+C::m_a$$$
+C::m_b$$$
+C::m_c$$$
+A::m_a$Hot$$
+A::m_b$Hot$$
+A::m_c$Hot$$
+B::m_a$Hot$$
+B::m_b$Hot$$
+B::m_c$Hot$$
+C::m_a$Hot$$
+C::m_b$Hot$$
+C::m_c$Hot$$
+A::m_a$$Startup$
+A::m_b$$Startup$
+A::m_c$$Startup$
+B::m_a$$Startup$
+B::m_b$$Startup$
+B::m_c$$Startup$
+C::m_a$$Startup$
+C::m_b$$Startup$
+C::m_c$$Startup$
+A::m_a$Hot$Startup$
+A::m_b$Hot$Startup$
+A::m_c$Hot$Startup$
+B::m_a$Hot$Startup$
+B::m_b$Hot$Startup$
+B::m_c$Hot$Startup$
+C::m_a$Hot$Startup$
+C::m_b$Hot$Startup$
+C::m_c$Hot$Startup$
+A::m_a$$$Poststartup
+A::m_b$$$Poststartup
+A::m_c$$$Poststartup
+B::m_a$$$Poststartup
+B::m_b$$$Poststartup
+B::m_c$$$Poststartup
+C::m_a$$$Poststartup
+C::m_b$$$Poststartup
+C::m_c$$$Poststartup
+A::m_a$Hot$$Poststartup
+A::m_b$Hot$$Poststartup
+A::m_c$Hot$$Poststartup
+B::m_a$Hot$$Poststartup
+B::m_b$Hot$$Poststartup
+B::m_c$Hot$$Poststartup
+C::m_a$Hot$$Poststartup
+C::m_b$Hot$$Poststartup
+C::m_c$Hot$$Poststartup
+A::m_a$$Startup$Poststartup
+A::m_b$$Startup$Poststartup
+A::m_c$$Startup$Poststartup
+B::m_a$$Startup$Poststartup
+B::m_b$$Startup$Poststartup
+B::m_c$$Startup$Poststartup
+C::m_a$$Startup$Poststartup
+C::m_b$$Startup$Poststartup
+C::m_c$$Startup$Poststartup
+A::m_a$Hot$Startup$Poststartup
+A::m_b$Hot$Startup$Poststartup
+A::m_c$Hot$Startup$Poststartup
+B::m_a$Hot$Startup$Poststartup
+B::m_b$Hot$Startup$Poststartup
+B::m_c$Hot$Startup$Poststartup
+C::m_a$Hot$Startup$Poststartup
+C::m_b$Hot$Startup$Poststartup
+C::m_c$Hot$Startup$Poststartup
diff --git a/test/661-oat-writer-layout/info.txt b/test/661-oat-writer-layout/info.txt
new file mode 100644
index 0000000..897b85c
--- /dev/null
+++ b/test/661-oat-writer-layout/info.txt
@@ -0,0 +1,4 @@
+Tests Oat Writer is correctly changing the layout of OatMethod code addresses.
+
+Whenever we pass in a profile to dex2oat, we expect that it sorts the methods by the
+MethodHotness bitmask (and sub-sorts by class_def_idx, then method_id).
diff --git a/test/661-oat-writer-layout/oat_writer_layout.cc b/test/661-oat-writer-layout/oat_writer_layout.cc
new file mode 100644
index 0000000..61996b2
--- /dev/null
+++ b/test/661-oat-writer-layout/oat_writer_layout.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+#include "art_method.h"
+#include "class_linker.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "mirror/executable.h"
+#include "mirror/object-inl.h"
+#include "obj_ptr.h"
+#include "oat_file.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread.h"
+
+namespace art {
+namespace {
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getOatMethodQuickCode(JNIEnv* env,
+                                                                   jclass,
+                                                                   jobject method) {
+  CHECK(method != nullptr);
+  ScopedObjectAccess soa(env);
+  ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method);
+  ArtMethod* art_method = exec->GetArtMethod();
+
+  const void* quick_code =
+    art_method->GetOatMethodQuickCode(Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+
+  return static_cast<jlong>(reinterpret_cast<uintptr_t>(quick_code));
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatCompiledCode(JNIEnv* env,
+                                                                   jclass,
+                                                                   jclass kls) {
+  CHECK(kls != nullptr);
+  ScopedObjectAccess soa(env);
+  Thread* self = Thread::Current();
+
+  ObjPtr<mirror::Class> klass_ptr = self->DecodeJObject(kls)->AsClass();
+
+  bool found = false;
+  OatFile::OatClass oat_class = OatFile::FindOatClass(*klass_ptr->GetDexCache()->GetDexFile(),
+                                                      klass_ptr->GetDexClassDefIndex(),
+                                                      /* out */ &found);
+
+  if (!found) {
+    return false;
+  }
+
+  OatClassType type = oat_class.GetType();
+  switch (type) {
+    case kOatClassAllCompiled:
+    case kOatClassSomeCompiled:
+      return true;
+
+    case kOatClassNoneCompiled:
+    case kOatClassMax:
+      return false;
+  }
+
+  LOG(FATAL) << "unhandled switch statement";
+  UNREACHABLE();
+}
+
+}  // namespace
+}  // namespace art
diff --git a/test/661-oat-writer-layout/parse_oatdump_offsets.sh b/test/661-oat-writer-layout/parse_oatdump_offsets.sh
new file mode 100755
index 0000000..ab9b9a9
--- /dev/null
+++ b/test/661-oat-writer-layout/parse_oatdump_offsets.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Quick and dirty helper tool to print the sorted oat code offsets from oatdump.
+#
+# Usage:
+#
+# oatdump --oat-file=661-oat-writer-layout.odex | $ANDROID_BUILD_TOP/art/test/661-oat-writer-layout/parse_oatdump_offsets.sh
+#
+
+found_method=""
+tmp_file="$(mktemp)"
+while read -r line; do
+
+  if [[ $line == *dex_method_idx=* ]]; then
+    found_method=$line
+  fi
+
+  if [[ $line == *"code_offset: "* ]]; then
+    echo $line $found_method >> "$tmp_file"
+  fi
+done
+
+sort "$tmp_file"
diff --git a/test/661-oat-writer-layout/profile b/test/661-oat-writer-layout/profile
new file mode 100644
index 0000000..5406484
--- /dev/null
+++ b/test/661-oat-writer-layout/profile
@@ -0,0 +1,63 @@
+HLA;->m_a$Hot$$()V
+SLA;->m_a$$Startup$()V
+HSLA;->m_a$Hot$Startup$()V
+PLA;->m_a$$$Poststartup()V
+HPLA;->m_a$Hot$$Poststartup()V
+SPLA;->m_a$$Startup$Poststartup()V
+HSPLA;->m_a$Hot$Startup$Poststartup()V
+HLA;->m_b$Hot$$()V
+SLA;->m_b$$Startup$()V
+HSLA;->m_b$Hot$Startup$()V
+PLA;->m_b$$$Poststartup()V
+HPLA;->m_b$Hot$$Poststartup()V
+SPLA;->m_b$$Startup$Poststartup()V
+HSPLA;->m_b$Hot$Startup$Poststartup()V
+HLA;->m_c$Hot$$()V
+SLA;->m_c$$Startup$()V
+HSLA;->m_c$Hot$Startup$()V
+PLA;->m_c$$$Poststartup()V
+HPLA;->m_c$Hot$$Poststartup()V
+SPLA;->m_c$$Startup$Poststartup()V
+HSPLA;->m_c$Hot$Startup$Poststartup()V
+HLB;->m_a$Hot$$()V
+SLB;->m_a$$Startup$()V
+HSLB;->m_a$Hot$Startup$()V
+PLB;->m_a$$$Poststartup()V
+HPLB;->m_a$Hot$$Poststartup()V
+SPLB;->m_a$$Startup$Poststartup()V
+HSPLB;->m_a$Hot$Startup$Poststartup()V
+HLB;->m_b$Hot$$()V
+SLB;->m_b$$Startup$()V
+HSLB;->m_b$Hot$Startup$()V
+PLB;->m_b$$$Poststartup()V
+HPLB;->m_b$Hot$$Poststartup()V
+SPLB;->m_b$$Startup$Poststartup()V
+HSPLB;->m_b$Hot$Startup$Poststartup()V
+HLB;->m_c$Hot$$()V
+SLB;->m_c$$Startup$()V
+HSLB;->m_c$Hot$Startup$()V
+PLB;->m_c$$$Poststartup()V
+HPLB;->m_c$Hot$$Poststartup()V
+SPLB;->m_c$$Startup$Poststartup()V
+HSPLB;->m_c$Hot$Startup$Poststartup()V
+HLC;->m_a$Hot$$()V
+SLC;->m_a$$Startup$()V
+HSLC;->m_a$Hot$Startup$()V
+PLC;->m_a$$$Poststartup()V
+HPLC;->m_a$Hot$$Poststartup()V
+SPLC;->m_a$$Startup$Poststartup()V
+HSPLC;->m_a$Hot$Startup$Poststartup()V
+HLC;->m_b$Hot$$()V
+SLC;->m_b$$Startup$()V
+HSLC;->m_b$Hot$Startup$()V
+PLC;->m_b$$$Poststartup()V
+HPLC;->m_b$Hot$$Poststartup()V
+SPLC;->m_b$$Startup$Poststartup()V
+HSPLC;->m_b$Hot$Startup$Poststartup()V
+HLC;->m_c$Hot$$()V
+SLC;->m_c$$Startup$()V
+HSLC;->m_c$Hot$Startup$()V
+PLC;->m_c$$$Poststartup()V
+HPLC;->m_c$Hot$$Poststartup()V
+SPLC;->m_c$$Startup$Poststartup()V
+HSPLC;->m_c$Hot$Startup$Poststartup()V
diff --git a/test/661-oat-writer-layout/run b/test/661-oat-writer-layout/run
new file mode 100644
index 0000000..f93d7b7
--- /dev/null
+++ b/test/661-oat-writer-layout/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Always use the 'profile'.
+# Note that this test only works with --compiler-filter=speed
+# -- we accomplish this by blacklisting other compiler variants.
+"${RUN}" "$@" --profile
diff --git a/test/661-oat-writer-layout/src/Generated.java b/test/661-oat-writer-layout/src/Generated.java
new file mode 100644
index 0000000..09f4e88
--- /dev/null
+++ b/test/661-oat-writer-layout/src/Generated.java
@@ -0,0 +1,109 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// Lists several combinations of Classes X Methods X Hotness:
+//
+// Class A-C:
+//   - Ensure method hotness overrides sorting by class_def_idx
+//
+// Method m_a : m_c
+//   - Ensure method hotness overrides sorting by method_id
+//
+// Method m_a$Hot$Enum$Bits
+//   - $X$Y$Z is an encoding of MethodHotness flags ($[Hot]$[Startup]$[Poststartup])
+//   - The method name encoding matches the `profile` hotness.
+//   - Check all variations of the bits to make sure it sorts by hotness correctly.
+//
+
+class A {
+  // Note that every method has unique dex code (by using a unique string literal).
+  // This is to prevent dex/oat code deduping. Deduped methods do not get distinct bins.
+  void m_a$$$() { System.out.println("Don't dedupe me! A::m_a$$$"); }
+  void m_a$Hot$$() { System.out.println("Don't dedupe me! A::m_a$Hot$$"); }
+  void m_a$$Startup$() { System.out.println("Don't dedupe me! A::m_a$$Startup$"); }
+  void m_a$Hot$Startup$() { System.out.println("Don't dedupe me! A::m_a$Hot$Startup$"); }
+  void m_a$$$Poststartup() { System.out.println("Don't dedupe me! A::m_a$$$Poststartup"); }
+  void m_a$Hot$$Poststartup() { System.out.println("Don't dedupe me! A::m_a$Hot$$Poststartup"); }
+  void m_a$$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_a$$Startup$Poststartup"); }
+  void m_a$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_a$Hot$Startup$Poststartup"); }
+  void m_b$$$() { System.out.println("Don't dedupe me! A::m_b$$$"); }
+  void m_b$Hot$$() { System.out.println("Don't dedupe me! A::m_b$Hot$$"); }
+  void m_b$$Startup$() { System.out.println("Don't dedupe me! A::m_b$$Startup$"); }
+  void m_b$Hot$Startup$() { System.out.println("Don't dedupe me! A::m_b$Hot$Startup$"); }
+  void m_b$$$Poststartup() { System.out.println("Don't dedupe me! A::m_b$$$Poststartup"); }
+  void m_b$Hot$$Poststartup() { System.out.println("Don't dedupe me! A::m_b$Hot$$Poststartup"); }
+  void m_b$$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_b$$Startup$Poststartup"); }
+  void m_b$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_b$Hot$Startup$Poststartup"); }
+  void m_c$$$() { System.out.println("Don't dedupe me! A::m_c$$$"); }
+  void m_c$Hot$$() { System.out.println("Don't dedupe me! A::m_c$Hot$$"); }
+  void m_c$$Startup$() { System.out.println("Don't dedupe me! A::m_c$$Startup$"); }
+  void m_c$Hot$Startup$() { System.out.println("Don't dedupe me! A::m_c$Hot$Startup$"); }
+  void m_c$$$Poststartup() { System.out.println("Don't dedupe me! A::m_c$$$Poststartup"); }
+  void m_c$Hot$$Poststartup() { System.out.println("Don't dedupe me! A::m_c$Hot$$Poststartup"); }
+  void m_c$$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_c$$Startup$Poststartup"); }
+  void m_c$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! A::m_c$Hot$Startup$Poststartup"); }
+}
+class B {
+  void m_a$$$() { System.out.println("Don't dedupe me! B::m_a$$$"); }
+  void m_a$Hot$$() { System.out.println("Don't dedupe me! B::m_a$Hot$$"); }
+  void m_a$$Startup$() { System.out.println("Don't dedupe me! B::m_a$$Startup$"); }
+  void m_a$Hot$Startup$() { System.out.println("Don't dedupe me! B::m_a$Hot$Startup$"); }
+  void m_a$$$Poststartup() { System.out.println("Don't dedupe me! B::m_a$$$Poststartup"); }
+  void m_a$Hot$$Poststartup() { System.out.println("Don't dedupe me! B::m_a$Hot$$Poststartup"); }
+  void m_a$$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_a$$Startup$Poststartup"); }
+  void m_a$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_a$Hot$Startup$Poststartup"); }
+  void m_b$$$() { System.out.println("Don't dedupe me! B::m_b$$$"); }
+  void m_b$Hot$$() { System.out.println("Don't dedupe me! B::m_b$Hot$$"); }
+  void m_b$$Startup$() { System.out.println("Don't dedupe me! B::m_b$$Startup$"); }
+  void m_b$Hot$Startup$() { System.out.println("Don't dedupe me! B::m_b$Hot$Startup$"); }
+  void m_b$$$Poststartup() { System.out.println("Don't dedupe me! B::m_b$$$Poststartup"); }
+  void m_b$Hot$$Poststartup() { System.out.println("Don't dedupe me! B::m_b$Hot$$Poststartup"); }
+  void m_b$$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_b$$Startup$Poststartup"); }
+  void m_b$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_b$Hot$Startup$Poststartup"); }
+  void m_c$$$() { System.out.println("Don't dedupe me! B::m_c$$$"); }
+  void m_c$Hot$$() { System.out.println("Don't dedupe me! B::m_c$Hot$$"); }
+  void m_c$$Startup$() { System.out.println("Don't dedupe me! B::m_c$$Startup$"); }
+  void m_c$Hot$Startup$() { System.out.println("Don't dedupe me! B::m_c$Hot$Startup$"); }
+  void m_c$$$Poststartup() { System.out.println("Don't dedupe me! B::m_c$$$Poststartup"); }
+  void m_c$Hot$$Poststartup() { System.out.println("Don't dedupe me! B::m_c$Hot$$Poststartup"); }
+  void m_c$$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_c$$Startup$Poststartup"); }
+  void m_c$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! B::m_c$Hot$Startup$Poststartup"); }
+}
+class C {
+  void m_a$$$() { System.out.println("Don't dedupe me! C::m_a$$$"); }
+  void m_a$Hot$$() { System.out.println("Don't dedupe me! C::m_a$Hot$$"); }
+  void m_a$$Startup$() { System.out.println("Don't dedupe me! C::m_a$$Startup$"); }
+  void m_a$Hot$Startup$() { System.out.println("Don't dedupe me! C::m_a$Hot$Startup$"); }
+  void m_a$$$Poststartup() { System.out.println("Don't dedupe me! C::m_a$$$Poststartup"); }
+  void m_a$Hot$$Poststartup() { System.out.println("Don't dedupe me! C::m_a$Hot$$Poststartup"); }
+  void m_a$$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_a$$Startup$Poststartup"); }
+  void m_a$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_a$Hot$Startup$Poststartup"); }
+  void m_b$$$() { System.out.println("Don't dedupe me! C::m_b$$$"); }
+  void m_b$Hot$$() { System.out.println("Don't dedupe me! C::m_b$Hot$$"); }
+  void m_b$$Startup$() { System.out.println("Don't dedupe me! C::m_b$$Startup$"); }
+  void m_b$Hot$Startup$() { System.out.println("Don't dedupe me! C::m_b$Hot$Startup$"); }
+  void m_b$$$Poststartup() { System.out.println("Don't dedupe me! C::m_b$$$Poststartup"); }
+  void m_b$Hot$$Poststartup() { System.out.println("Don't dedupe me! C::m_b$Hot$$Poststartup"); }
+  void m_b$$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_b$$Startup$Poststartup"); }
+  void m_b$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_b$Hot$Startup$Poststartup"); }
+  void m_c$$$() { System.out.println("Don't dedupe me! C::m_c$$$"); }
+  void m_c$Hot$$() { System.out.println("Don't dedupe me! C::m_c$Hot$$"); }
+  void m_c$$Startup$() { System.out.println("Don't dedupe me! C::m_c$$Startup$"); }
+  void m_c$Hot$Startup$() { System.out.println("Don't dedupe me! C::m_c$Hot$Startup$"); }
+  void m_c$$$Poststartup() { System.out.println("Don't dedupe me! C::m_c$$$Poststartup"); }
+  void m_c$Hot$$Poststartup() { System.out.println("Don't dedupe me! C::m_c$Hot$$Poststartup"); }
+  void m_c$$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_c$$Startup$Poststartup"); }
+  void m_c$Hot$Startup$Poststartup() { System.out.println("Don't dedupe me! C::m_c$Hot$Startup$Poststartup"); }
+}
diff --git a/test/661-oat-writer-layout/src/Main.java b/test/661-oat-writer-layout/src/Main.java
new file mode 100644
index 0000000..940798d
--- /dev/null
+++ b/test/661-oat-writer-layout/src/Main.java
@@ -0,0 +1,80 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class Main {
+
+  static class OatMethodAndOffset implements Comparable<OatMethodAndOffset> {
+    Method method;
+    long codeOffset;
+
+    public OatMethodAndOffset(Method method, long codeOffset) {
+      this.method = method;
+      this.codeOffset = codeOffset;
+    }
+
+    // e.g. "Foo::Bar()"
+    public String methodReferenceString() {
+      return method.getDeclaringClass().getName() + "::" + method.getName();
+    }
+
+    @Override
+    public int compareTo(OatMethodAndOffset other) {
+      return Long.compareUnsigned(codeOffset, other.codeOffset);
+    }
+  }
+
+  // Print the list of methods in Generated.class, sorted by their OAT code address.
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+
+    // Make sure to check "Test.class" because Main.class still has JNI which could be compiled
+    // even if the rest of the classes are not.
+    if (!hasOatCompiledCode(Test.class)) {
+      System.out.println("No OAT class");
+      return;
+    }
+
+    // We only care about explicitly defined methods from Generated.java.
+    Method[] interesting_methods;
+    try {
+      interesting_methods = Test.getTestMethods();
+    } catch (NoSuchMethodException e) {
+      e.printStackTrace();
+      return;
+    }
+
+    // Get the list of oat code methods for each Java method.
+    ArrayList<OatMethodAndOffset> offsets_list = new ArrayList<OatMethodAndOffset>();
+    for (Method m : interesting_methods) {
+      offsets_list.add(new OatMethodAndOffset(m, getOatMethodQuickCode(m)));
+    }
+
+    // Sort by the offset address.
+    Collections.sort(offsets_list);
+
+    // Print each method as a method reference string.
+    for (OatMethodAndOffset m : offsets_list) {
+      System.out.println(m.methodReferenceString());
+    }
+  }
+
+  // Does Main.class have an OatClass with actually compiled code?
+  private static native boolean hasOatCompiledCode(Class kls);
+  // Get the OatMethod's pointer to code. We get 'real' memory address, not relative offset,
+  // but it's still good since we never compare multiple OAT files here.
+  private static native long getOatMethodQuickCode(Method method);
+}
diff --git a/test/661-oat-writer-layout/src/Test.java b/test/661-oat-writer-layout/src/Test.java
new file mode 100644
index 0000000..db67b48
--- /dev/null
+++ b/test/661-oat-writer-layout/src/Test.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.lang.reflect.Method;
+
+public class Test {
+  // Returns list of all methods in Generated.java
+  // This is to avoid having to introspect classes with extra code
+  // (for example, we ignore <init> methods).
+  public static Method[] getTestMethods() throws NoSuchMethodException, SecurityException {
+    Method[] all_methods = new Method[72];
+    all_methods[0] = A.class.getDeclaredMethod("m_a$$$");
+    all_methods[1] = A.class.getDeclaredMethod("m_a$Hot$$");
+    all_methods[2] = A.class.getDeclaredMethod("m_a$$Startup$");
+    all_methods[3] = A.class.getDeclaredMethod("m_a$Hot$Startup$");
+    all_methods[4] = A.class.getDeclaredMethod("m_a$$$Poststartup");
+    all_methods[5] = A.class.getDeclaredMethod("m_a$Hot$$Poststartup");
+    all_methods[6] = A.class.getDeclaredMethod("m_a$$Startup$Poststartup");
+    all_methods[7] = A.class.getDeclaredMethod("m_a$Hot$Startup$Poststartup");
+    all_methods[8] = A.class.getDeclaredMethod("m_b$$$");
+    all_methods[9] = A.class.getDeclaredMethod("m_b$Hot$$");
+    all_methods[10] = A.class.getDeclaredMethod("m_b$$Startup$");
+    all_methods[11] = A.class.getDeclaredMethod("m_b$Hot$Startup$");
+    all_methods[12] = A.class.getDeclaredMethod("m_b$$$Poststartup");
+    all_methods[13] = A.class.getDeclaredMethod("m_b$Hot$$Poststartup");
+    all_methods[14] = A.class.getDeclaredMethod("m_b$$Startup$Poststartup");
+    all_methods[15] = A.class.getDeclaredMethod("m_b$Hot$Startup$Poststartup");
+    all_methods[16] = A.class.getDeclaredMethod("m_c$$$");
+    all_methods[17] = A.class.getDeclaredMethod("m_c$Hot$$");
+    all_methods[18] = A.class.getDeclaredMethod("m_c$$Startup$");
+    all_methods[19] = A.class.getDeclaredMethod("m_c$Hot$Startup$");
+    all_methods[20] = A.class.getDeclaredMethod("m_c$$$Poststartup");
+    all_methods[21] = A.class.getDeclaredMethod("m_c$Hot$$Poststartup");
+    all_methods[22] = A.class.getDeclaredMethod("m_c$$Startup$Poststartup");
+    all_methods[23] = A.class.getDeclaredMethod("m_c$Hot$Startup$Poststartup");
+    all_methods[24] = B.class.getDeclaredMethod("m_a$$$");
+    all_methods[25] = B.class.getDeclaredMethod("m_a$Hot$$");
+    all_methods[26] = B.class.getDeclaredMethod("m_a$$Startup$");
+    all_methods[27] = B.class.getDeclaredMethod("m_a$Hot$Startup$");
+    all_methods[28] = B.class.getDeclaredMethod("m_a$$$Poststartup");
+    all_methods[29] = B.class.getDeclaredMethod("m_a$Hot$$Poststartup");
+    all_methods[30] = B.class.getDeclaredMethod("m_a$$Startup$Poststartup");
+    all_methods[31] = B.class.getDeclaredMethod("m_a$Hot$Startup$Poststartup");
+    all_methods[32] = B.class.getDeclaredMethod("m_b$$$");
+    all_methods[33] = B.class.getDeclaredMethod("m_b$Hot$$");
+    all_methods[34] = B.class.getDeclaredMethod("m_b$$Startup$");
+    all_methods[35] = B.class.getDeclaredMethod("m_b$Hot$Startup$");
+    all_methods[36] = B.class.getDeclaredMethod("m_b$$$Poststartup");
+    all_methods[37] = B.class.getDeclaredMethod("m_b$Hot$$Poststartup");
+    all_methods[38] = B.class.getDeclaredMethod("m_b$$Startup$Poststartup");
+    all_methods[39] = B.class.getDeclaredMethod("m_b$Hot$Startup$Poststartup");
+    all_methods[40] = B.class.getDeclaredMethod("m_c$$$");
+    all_methods[41] = B.class.getDeclaredMethod("m_c$Hot$$");
+    all_methods[42] = B.class.getDeclaredMethod("m_c$$Startup$");
+    all_methods[43] = B.class.getDeclaredMethod("m_c$Hot$Startup$");
+    all_methods[44] = B.class.getDeclaredMethod("m_c$$$Poststartup");
+    all_methods[45] = B.class.getDeclaredMethod("m_c$Hot$$Poststartup");
+    all_methods[46] = B.class.getDeclaredMethod("m_c$$Startup$Poststartup");
+    all_methods[47] = B.class.getDeclaredMethod("m_c$Hot$Startup$Poststartup");
+    all_methods[48] = C.class.getDeclaredMethod("m_a$$$");
+    all_methods[49] = C.class.getDeclaredMethod("m_a$Hot$$");
+    all_methods[50] = C.class.getDeclaredMethod("m_a$$Startup$");
+    all_methods[51] = C.class.getDeclaredMethod("m_a$Hot$Startup$");
+    all_methods[52] = C.class.getDeclaredMethod("m_a$$$Poststartup");
+    all_methods[53] = C.class.getDeclaredMethod("m_a$Hot$$Poststartup");
+    all_methods[54] = C.class.getDeclaredMethod("m_a$$Startup$Poststartup");
+    all_methods[55] = C.class.getDeclaredMethod("m_a$Hot$Startup$Poststartup");
+    all_methods[56] = C.class.getDeclaredMethod("m_b$$$");
+    all_methods[57] = C.class.getDeclaredMethod("m_b$Hot$$");
+    all_methods[58] = C.class.getDeclaredMethod("m_b$$Startup$");
+    all_methods[59] = C.class.getDeclaredMethod("m_b$Hot$Startup$");
+    all_methods[60] = C.class.getDeclaredMethod("m_b$$$Poststartup");
+    all_methods[61] = C.class.getDeclaredMethod("m_b$Hot$$Poststartup");
+    all_methods[62] = C.class.getDeclaredMethod("m_b$$Startup$Poststartup");
+    all_methods[63] = C.class.getDeclaredMethod("m_b$Hot$Startup$Poststartup");
+    all_methods[64] = C.class.getDeclaredMethod("m_c$$$");
+    all_methods[65] = C.class.getDeclaredMethod("m_c$Hot$$");
+    all_methods[66] = C.class.getDeclaredMethod("m_c$$Startup$");
+    all_methods[67] = C.class.getDeclaredMethod("m_c$Hot$Startup$");
+    all_methods[68] = C.class.getDeclaredMethod("m_c$$$Poststartup");
+    all_methods[69] = C.class.getDeclaredMethod("m_c$Hot$$Poststartup");
+    all_methods[70] = C.class.getDeclaredMethod("m_c$$Startup$Poststartup");
+    all_methods[71] = C.class.getDeclaredMethod("m_c$Hot$Startup$Poststartup");
+    return all_methods;
+  }
+}
+
diff --git a/test/707-checker-invalid-profile/check b/test/707-checker-invalid-profile/check
new file mode 100755
index 0000000..976afc4
--- /dev/null
+++ b/test/707-checker-invalid-profile/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# When profile verification fails, dex2oat logs an error. The following
+# command strips out the error message.
+grep -v -f $1 $2 > $1
+
+./default-check "$@"
diff --git a/test/707-checker-invalid-profile/expected.txt b/test/707-checker-invalid-profile/expected.txt
index e69de29..4d84c96 100644
--- a/test/707-checker-invalid-profile/expected.txt
+++ b/test/707-checker-invalid-profile/expected.txt
@@ -0,0 +1 @@
+Invalid inline cache in profile file.
diff --git a/test/911-get-stack-trace/src/art/PrintThread.java b/test/911-get-stack-trace/src/art/PrintThread.java
index fee5ba0..d8b3cbc 100644
--- a/test/911-get-stack-trace/src/art/PrintThread.java
+++ b/test/911-get-stack-trace/src/art/PrintThread.java
@@ -42,7 +42,7 @@
   // may not exist depending on the environment.
   public final static String IGNORE_THREAD_NAME_REGEX =
       "Binder:|RenderThread|hwuiTask|Jit thread pool worker|Instr:|JDWP|Profile Saver|main|" +
-      "queued-work-looper";
+      "queued-work-looper|InstrumentationConnectionThread";
   public final static Matcher IGNORE_THREADS =
       Pattern.compile(IGNORE_THREAD_NAME_REGEX).matcher("");
 
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 9dcc5f9..7ad5d60 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -56,7 +56,7 @@
 boot <- 1+2 (A,B)
 [class A, class B, class java.lang.Object]
 
-[37, 0]
+[35, 0]
 
 B, false
 Load: LB; on ClassEvents
diff --git a/test/912-classes/src-art/art/Test912.java b/test/912-classes/src-art/art/Test912.java
index 2e41c26..ddfadf3 100644
--- a/test/912-classes/src-art/art/Test912.java
+++ b/test/912-classes/src-art/art/Test912.java
@@ -19,8 +19,10 @@
 import java.lang.ref.Reference;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Proxy;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.Comparator;
 
 public class Test912 {
@@ -214,8 +216,34 @@
     }
   }
 
-  private static void testClassVersion() {
-    System.out.println(Arrays.toString(getClassVersion(Main.class)));
+  /**
+   * base64 encoded class/dex file for
+   * class Transform {
+   *   public void sayHi() {
+   *    System.out.println("Goodbye");
+   *   }
+   * }
+   */
+  private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+    "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+    "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+    "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
+    "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+    "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
+    "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+    "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
+    "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
+    "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
+    "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
+    "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+    "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+    "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
+  private static void testClassVersion() throws Exception {
+    Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader");
+    Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class);
+    Class target = ((ClassLoader)ctor.newInstance(
+        ByteBuffer.wrap(DEX_BYTES), Test912.class.getClassLoader())).loadClass("Transform");
+    System.out.println(Arrays.toString(getClassVersion(target)));
   }
 
   private static void testClassEvents() throws Exception {
diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt
index 1eb2e1b..e529559 100644
--- a/test/924-threads/expected.txt
+++ b/test/924-threads/expected.txt
@@ -26,6 +26,15 @@
 class dalvik.system.PathClassLoader
 5
 5
+Thread type is class java.lang.Thread
+0 = NEW
+191 = ALIVE|WAITING_INDEFINITELY|WAITING|IN_OBJECT_WAIT
+1a1 = ALIVE|WAITING_WITH_TIMEOUT|WAITING|IN_OBJECT_WAIT
+401 = ALIVE|BLOCKED_ON_MONITOR_ENTER
+e1 = ALIVE|WAITING_WITH_TIMEOUT|SLEEPING|WAITING
+5 = ALIVE|RUNNABLE
+2 = TERMINATED
+Thread type is class art.Test924$ExtThread
 0 = NEW
 191 = ALIVE|WAITING_INDEFINITELY|WAITING|IN_OBJECT_WAIT
 1a1 = ALIVE|WAITING_WITH_TIMEOUT|WAITING|IN_OBJECT_WAIT
diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java
index b73eb30..1ff2c3f 100644
--- a/test/924-threads/src/art/Test924.java
+++ b/test/924-threads/src/art/Test924.java
@@ -21,6 +21,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.concurrent.CountDownLatch;
+import java.util.function.Function;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -76,7 +77,9 @@
     };
     printThreadInfo(t4);
 
-    doStateTests();
+    doCurrentThreadStateTests();
+    doStateTests(Thread::new);
+    doStateTests(ExtThread::new);
 
     doAllThreadsTests();
 
@@ -85,14 +88,20 @@
     doTestEvents();
   }
 
+  private static final class ExtThread extends Thread {
+    public ExtThread(Runnable r) { super(r); }
+  }
+
   private static class Holder {
     volatile boolean flag = false;
   }
 
-  private static void doStateTests() throws Exception {
+  private static void doCurrentThreadStateTests() throws Exception {
     System.out.println(Integer.toHexString(getThreadState(null)));
     System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
+  }
 
+  private static void doStateTests(Function<Runnable, Thread> mkThread) throws Exception {
     final CountDownLatch cdl1 = new CountDownLatch(1);
     final CountDownLatch cdl2 = new CountDownLatch(1);
     final CountDownLatch cdl3_1 = new CountDownLatch(1);
@@ -133,7 +142,8 @@
       }
     };
 
-    Thread t = new Thread(r);
+    Thread t = mkThread.apply(r);
+    System.out.println("Thread type is " + t.getClass());
     printThreadState(t);
     t.start();
 
diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check
index 07b21b3..6f1e709 100755
--- a/test/980-redefine-object/check
+++ b/test/980-redefine-object/check
@@ -17,4 +17,7 @@
 # The number of paused background threads (and therefore InterruptedExceptions)
 # can change so we will just delete their lines from the log.
 
-sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
+cat "$2" \
+  | sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" \
+  | sed "/Object allocated of type 'java\.lang\.Long'/d" \
+  | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/Android.bp b/test/Android.bp
index d56c0b5..38d0651 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -420,7 +420,8 @@
         "642-fp-callees/fp_callees.cc",
         "647-jni-get-field-id/get_field_id.cc",
         "656-annotation-lookup-generic-jni/test.cc",
-	"664-aget-verifier/aget-verifier.cc",
+        "661-oat-writer-layout/oat_writer_layout.cc",
+        "664-aget-verifier/aget-verifier.cc",
         "708-jit-cache-churn/jit.cc"
     ],
     shared_libs: [
diff --git a/test/GetMethodSignature/GetMethodSignature.java b/test/GetMethodSignature/GetMethodSignature.java
index c2ba948..d2f96bb 100644
--- a/test/GetMethodSignature/GetMethodSignature.java
+++ b/test/GetMethodSignature/GetMethodSignature.java
@@ -17,4 +17,13 @@
 class GetMethodSignature {
     Float m1(int a, double b, long c, Object d) { return null; }
     GetMethodSignature m2(boolean x, short y, char z) { return null; }
+    void m3() { }
+    void m4(int i) { }
+    void m5(int i, int j) { }
+    void m6(int i, int j, int[][] array1) { }
+    void m7(int i, int j, int[][] array1, Object o) { }
+    void m8(int i, int j, int[][] array1, Object o, Object[][] array2) { }
+    int m9() { return 0; }
+    int[][] mA() { return null; }
+    Object[][] mB() { return null; }
 }
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 252d13a..df24c7d 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -366,167 +366,20 @@
         "variant": "speed-profile"
     },
     {
-        "tests": [
-            "004-checker-UnsafeTest18",
-            "127-checker-secondarydex",
-            "441-checker-inliner",
-            "442-checker-constant-folding",
-            "444-checker-nce",
-            "445-checker-licm",
-            "446-checker-inliner2",
-            "447-checker-inliner3",
-            "449-checker-bce",
-            "450-checker-types",
-            "455-checker-gvn",
-            "458-checker-instruct-simplification",
-            "462-checker-inlining-dex-files",
-            "463-checker-boolean-simplifier",
-            "464-checker-inline-sharpen-calls",
-            "465-checker-clinit-gvn",
-            "468-checker-bool-simplif-regression",
-            "473-checker-inliner-constants",
-            "474-checker-boolean-input",
-            "476-checker-ctor-memory-barrier",
-            "477-checker-bound-type",
-            "478-checker-clinit-check-pruning",
-            "478-checker-inline-noreturn",
-            "478-checker-inliner-nested-loop",
-            "480-checker-dead-blocks",
-            "482-checker-loop-back-edge-use",
-            "484-checker-register-hints",
-            "485-checker-dce-loop-update",
-            "485-checker-dce-switch",
-            "486-checker-must-do-null-check",
-            "487-checker-inline-calls",
-            "488-checker-inline-recursive-calls",
-            "490-checker-inline",
-            "492-checker-inline-invoke-interface",
-            "493-checker-inline-invoke-interface",
-            "494-checker-instanceof-tests",
-            "495-checker-checkcast-tests",
-            "496-checker-inlining-class-loader",
-            "508-checker-disassembly",
-            "510-checker-try-catch",
-            "517-checker-builder-fallthrough",
-            "521-checker-array-set-null",
-            "522-checker-regression-monitor-exit",
-            "523-checker-can-throw-regression",
-            "525-checker-arrays-fields1",
-            "525-checker-arrays-fields2",
-            "526-checker-caller-callee-regs",
-            "527-checker-array-access-split",
-            "529-checker-unresolved",
-            "530-checker-loops1",
-            "530-checker-loops2",
-            "530-checker-loops3",
-            "530-checker-loops4",
-            "530-checker-loops5",
-            "530-checker-lse",
-            "530-checker-lse2",
-            "530-checker-regression-reftyp-final",
-            "532-checker-nonnull-arrayset",
-            "534-checker-bce-deoptimization",
-            "536-checker-intrinsic-optimization",
-            "536-checker-needs-access-check",
-            "537-checker-arraycopy",
-            "537-checker-debuggable",
-            "537-checker-inline-and-unverified",
-            "537-checker-jump-over-jump",
-            "538-checker-embed-constants",
-            "540-checker-rtp-bug",
-            "543-checker-dce-trycatch",
-            "548-checker-inlining-and-dce",
-            "549-checker-types-merge",
-            "550-checker-multiply-accumulate",
-            "550-checker-regression-wide-store",
-            "551-checker-clinit",
-            "551-checker-shifter-operand",
-            "552-checker-primitive-typeprop",
-            "552-checker-sharpening",
-            "554-checker-rtp-checkcast",
-            "557-checker-instruct-simplifier-ror",
-            "557-checker-ref-equivalent",
-            "559-checker-irreducible-loop",
-            "559-checker-rtp-ifnotnull",
-            "562-checker-no-intermediate",
-            "563-checker-fakestring",
-            "563-checker-invoke-super",
-            "564-checker-bitcount",
-            "564-checker-inline-loop",
-            "564-checker-irreducible-loop",
-            "564-checker-negbitwise",
-            "565-checker-condition-liveness",
-            "565-checker-doublenegbitwise",
-            "565-checker-irreducible-loop",
-            "565-checker-rotate",
-            "566-checker-codegen-select",
-            "566-checker-signum",
-            "567-checker-compare",
-            "568-checker-onebit",
-            "569-checker-pattern-replacement",
-            "570-checker-osr",
-            "570-checker-select",
-            "572-checker-array-get-regression",
-            "573-checker-checkcast-regression",
-            "575-checker-isnan",
-            "575-checker-string-init-alias",
-            "577-checker-fp2int",
-            "580-checker-round",
-            "580-checker-string-fact-intrinsics",
-            "582-checker-bce-length",
-            "583-checker-zero",
-            "584-checker-div-bool",
-            "586-checker-null-array-get",
-            "588-checker-irreducib-lifetime-hole",
-            "590-checker-arr-set-null-regression",
-            "591-checker-regression-dead-loop",
-            "592-checker-regression-bool-input",
-            "593-checker-boolean-2-integral-conv",
-            "593-checker-long-2-float-regression",
-            "593-checker-shift-and-simplifier",
-            "594-checker-array-alias",
-            "594-checker-irreducible-linorder",
-            "596-checker-dead-phi",
-            "598-checker-irreducible-dominance",
-            "599-checker-irreducible-loop",
-            "603-checker-instanceof",
-            "608-checker-unresolved-lse",
-            "609-checker-inline-interface",
-            "609-checker-x86-bounds-check",
-            "611-checker-simplify-if",
-            "614-checker-dump-constant-location",
-            "615-checker-arm64-store-zero",
-            "618-checker-induction",
-            "619-checker-current-method",
-            "620-checker-bce-intrinsics",
-            "622-checker-bce-regressions",
-            "623-checker-loop-regressions",
-            "624-checker-stringops",
-            "625-checker-licm-regressions",
-            "626-checker-arm64-scratch-register",
-            "627-checker-unroll",
-            "631-checker-fp-abs",
-            "631-checker-get-class",
-            "632-checker-char-at-bounds",
-            "633-checker-rtp-getclass",
-            "635-checker-arm64-volatile-load-cc",
-            "637-checker-throw-inline",
-            "638-checker-inline-caches",
-            "639-checker-code-sinking",
-            "640-checker-boolean-simd",
-            "640-checker-byte-simd",
-            "640-checker-char-simd",
-            "640-checker-double-simd",
-            "640-checker-float-simd",
-            "640-checker-integer-valueof",
-            "640-checker-int-simd",
-            "640-checker-long-simd",
-            "640-checker-short-simd",
-            "641-checker-arraycopy",
-            "643-checker-bogus-ic",
-            "645-checker-abs-simd",
-            "663-checker-select-generator",
-            "706-checker-scheduler"],
+        "test_patterns": ["616-cha.*"],
+        "description": ["cha tests rely on knowing more about the state of the JIT then is possible with jvmti-stress"],
+        "variant": "jvmti-stress & jit | redefine-stress & jit"
+    },
+    {
+        "tests": [ "663-odd-dex-size",
+                   "663-odd-dex-size2",
+                   "663-odd-dex-size3",
+                   "663-odd-dex-size4" ],
+        "description": ["All the odd-dex-size tests cause slicer to emit warnings."],
+        "variant": "jvmti-stress | redefine-stress"
+    },
+    {
+        "test_patterns": ["[0-9]*-checker-.*"],
         "description": ["Checker tests are not compatible with jvmti."],
         "variant": "jvmti-stress | redefine-stress | trace-stress | field-stress | step-stress"
     },
@@ -539,20 +392,34 @@
         "variant": "jvmti-stress | redefine-stress | trace-stress | step-stress"
     },
     {
+        "tests": ["082-inline-execute"],
+        "description": ["speed-profile seems to cause the agent to be given an invalid dex file" ],
+        "bug": "b/65452964",
+        "variant": "redefine-stress & speed-profile | jvmti-stress & speed-profile"
+    },
+    {
+        "tests": ["701-easy-div-rem",
+                  "303-verification-stress"],
+        "description": ["speed-profile leads to dex files that slicer emits warnings about"],
+        "variant": "redefine-stress & speed-profile | jvmti-stress & speed-profile"
+    },
+    {
         "tests": [
             "950-redefine-intrinsic",
             "951-threaded-obsolete",
             "952-invoke-custom",
+            "952-invoke-custom-kinds",
             "953-invoke-polymorphic-compiler",
             "954-invoke-polymorphic-verifier",
             "955-methodhandles-smali",
             "956-methodhandles",
             "957-methodhandle-transforms",
             "958-methodhandle-stackframe",
-            "959-invoke-polymorphic-accessors"
+            "959-invoke-polymorphic-accessors",
+            "990-method-handle-and-mr"
         ],
         "description": [
-            "Tests that use dex version 38 which is not yet supported by",
+            "Tests that use invoke-polymorphic/invoke-custom which is not yet supported by",
             "dexter/slicer."
         ],
         "bug": "b/37272822",
@@ -620,6 +487,13 @@
         "variant": "jvmti-stress | redefine-stress"
     },
     {
+        "tests": [ "1911-get-local-var-table" ],
+        "description": [
+            "Test that relies on knowing the exact layout of a dex file"
+        ],
+        "variant": "jvmti-stress | redefine-stress"
+    },
+    {
         "tests": [
             "536-checker-needs-access-check",
             "537-checker-inline-and-unverified",
@@ -729,9 +603,9 @@
     },
     {
         "tests": "660-clinit",
-        "variant": "no-image | no-dex2oat | no-prebuild",
-        "description": ["Tests <clinit> for app images, which --no-image, --no-prebuild and",
-                        "--no-dex2oat do not create"]
+        "variant": "no-image | no-dex2oat | no-prebuild | jvmti-stress | redefine-stress",
+        "description": ["Tests <clinit> for app images, which --no-image, --no-prebuild, ",
+                        "--no-dex2oat, and --redefine-stress do not create"]
     },
     {
         "tests": ["961-default-iface-resolution-gen",
@@ -744,5 +618,10 @@
         "tests": "664-aget-verifier",
         "description": ["Aget on potentially null array fails verification."],
         "bug": "b/64683522"
+    },
+    {
+        "tests": "661-oat-writer-layout",
+        "variant": "interp-ac | interpreter | jit | no-dex2oat | no-prebuild | no-image | trace",
+        "description": ["Test is designed to only check --compiler-filter=speed"]
     }
 ]
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index d45d009..cc19afc 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -115,82 +115,9 @@
 # Keep going after encountering a test failure?
 ART_TEST_KEEP_GOING = _getEnvBoolean('ART_TEST_KEEP_GOING', True)
 
-# Do you want all tests, even those that are time consuming?
-ART_TEST_FULL = _getEnvBoolean('ART_TEST_FULL', False)
-
-# Do you want interpreter tests run?
-ART_TEST_INTERPRETER = _getEnvBoolean('ART_TEST_INTERPRETER', ART_TEST_FULL)
-ART_TEST_INTERPRETER_ACCESS_CHECKS = _getEnvBoolean('ART_TEST_INTERPRETER_ACCESS_CHECKS',
-                                                   ART_TEST_FULL)
-
-# Do you want JIT tests run?
-ART_TEST_JIT = _getEnvBoolean('ART_TEST_JIT', ART_TEST_FULL)
-
-# Do you want optimizing compiler tests run?
-ART_TEST_OPTIMIZING = _getEnvBoolean('ART_TEST_OPTIMIZING', ART_TEST_FULL)
-
-# Do you want to test the optimizing compiler with graph coloring register allocation?
-ART_TEST_OPTIMIZING_GRAPH_COLOR = _getEnvBoolean('ART_TEST_OPTIMIZING_GRAPH_COLOR', ART_TEST_FULL)
-
-# Do you want to do run-tests with profiles?
-ART_TEST_SPEED_PROFILE = _getEnvBoolean('ART_TEST_SPEED_PROFILE', ART_TEST_FULL)
-
-# Do we want to test PIC-compiled tests ("apps")?
-ART_TEST_PIC_TEST = _getEnvBoolean('ART_TEST_PIC_TEST', ART_TEST_FULL)
-# Do you want tracing tests run?
-ART_TEST_TRACE = _getEnvBoolean('ART_TEST_TRACE', ART_TEST_FULL)
-
-# Do you want tracing tests (streaming mode) run?
-ART_TEST_TRACE_STREAM = _getEnvBoolean('ART_TEST_TRACE_STREAM', ART_TEST_FULL)
-
-# Do you want tests with GC verification enabled run?
-ART_TEST_GC_VERIFY = _getEnvBoolean('ART_TEST_GC_VERIFY', ART_TEST_FULL)
-
-# Do you want tests with the GC stress mode enabled run?
-ART_TEST_GC_STRESS = _getEnvBoolean('ART_TEST_GC_STRESS', ART_TEST_FULL)
-
-# Do you want tests with the JNI forcecopy mode enabled run?
-ART_TEST_JNI_FORCECOPY = _getEnvBoolean('ART_TEST_JNI_FORCECOPY', ART_TEST_FULL)
-
-# Do you want run-tests with relocation disabled run?
-ART_TEST_RUN_TEST_RELOCATE = _getEnvBoolean('ART_TEST_RUN_TEST_RELOCATE', ART_TEST_FULL)
-
-# Do you want run-tests with prebuilding?
-ART_TEST_RUN_TEST_PREBUILD = _getEnvBoolean('ART_TEST_RUN_TEST_PREBUILD', ART_TEST_FULL)
-
-# Do you want run-tests with no prebuilding enabled run?
-ART_TEST_RUN_TEST_NO_PREBUILD = _getEnvBoolean('ART_TEST_RUN_TEST_NO_PREBUILD', ART_TEST_FULL)
-
-# Do you want run-tests with a pregenerated core.art?
-ART_TEST_RUN_TEST_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_IMAGE', ART_TEST_FULL)
-
-# Do you want run-tests without a pregenerated core.art?
-ART_TEST_RUN_TEST_NO_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_NO_IMAGE', ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled but patchoat failing?
-ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT = _getEnvBoolean('ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT',
-                                                       ART_TEST_FULL)
-
-# Do you want run-tests without a dex2oat?
-ART_TEST_RUN_TEST_NO_DEX2OAT = _getEnvBoolean('ART_TEST_RUN_TEST_NO_DEX2OAT', ART_TEST_FULL)
-
-# Do you want run-tests with libartd.so?
-ART_TEST_RUN_TEST_DEBUG = _getEnvBoolean('ART_TEST_RUN_TEST_DEBUG', ART_TEST_FULL)
-
-# Do you want run-tests with libart.so?
-ART_TEST_RUN_TEST_NDEBUG = _getEnvBoolean('ART_TEST_RUN_TEST_NDEBUG', ART_TEST_FULL)
-
 # Do you want failed tests to have their artifacts cleaned up?
 ART_TEST_RUN_TEST_ALWAYS_CLEAN = _getEnvBoolean('ART_TEST_RUN_TEST_ALWAYS_CLEAN', True)
 
-# Do you want run-tests with the --debuggable flag
-ART_TEST_RUN_TEST_DEBUGGABLE = _getEnvBoolean('ART_TEST_RUN_TEST_DEBUGGABLE', ART_TEST_FULL)
-
-# Do you want to test multi-part boot-image functionality?
-ART_TEST_RUN_TEST_MULTI_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_MULTI_IMAGE', ART_TEST_FULL)
-
-ART_TEST_DEBUG_GC = _getEnvBoolean('ART_TEST_DEBUG_GC', False)
-
 ART_TEST_BISECTION = _getEnvBoolean('ART_TEST_BISECTION', False)
 
 DEX2OAT_HOST_INSTRUCTION_SET_FEATURES = _env.get('DEX2OAT_HOST_INSTRUCTION_SET_FEATURES')
@@ -217,8 +144,6 @@
 # Note: ART_2ND_PHONY_TEST_HOST_SUFFIX is 2ND_ART_PHONY_HOST_TARGET_SUFFIX in .mk files
 # Python does not let us have variable names starting with a digit, so it has differ.
 
-ART_TEST_RUN_TEST_JVMTI_STRESS = _getEnvBoolean('ART_TEST_RUN_TEST_JVMTI_STRESS', ART_TEST_FULL)
-
 if TARGET_2ND_ARCH:
   if "64" in TARGET_ARCH:
     ART_PHONY_TEST_TARGET_SUFFIX = "64"
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index f425097..2a772ff 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -45,6 +45,7 @@
 
 """
 import argparse
+import collections
 import fnmatch
 import itertools
 import json
@@ -60,21 +61,6 @@
 import env
 from target_config import target_config
 
-TARGET_TYPES = set()
-RUN_TYPES = set()
-PREBUILD_TYPES = set()
-COMPILER_TYPES = set()
-RELOCATE_TYPES = set()
-TRACE_TYPES = set()
-GC_TYPES = set()
-JNI_TYPES = set()
-IMAGE_TYPES = set()
-PICTEST_TYPES = set()
-DEBUGGABLE_TYPES = set()
-ADDRESS_SIZES = set()
-OPTIMIZING_COMPILER_TYPES = set()
-JVMTI_TYPES = set()
-ADDRESS_SIZES_TARGET = {'host': set(), 'target': set()}
 # timeout for individual tests.
 # TODO: make it adjustable per tests and for buildbots
 timeout = 3000 # 50 minutes
@@ -128,6 +114,12 @@
 gdb_arg = ''
 stop_testrunner = False
 dex2oat_jobs = -1   # -1 corresponds to default threads for dex2oat
+run_all_configs = False
+
+# Dict to store user requested test variants.
+# key: variant_type.
+# value: set of variants user wants to run of type <key>.
+_user_input_variants = collections.defaultdict(set)
 
 def gather_test_info():
   """The method gathers test information about the test to be run which includes
@@ -151,7 +143,7 @@
   VARIANT_TYPE_DICT['jvmti'] = {'no-jvmti', 'jvmti-stress', 'redefine-stress', 'trace-stress',
                                 'field-stress', 'step-stress'}
   VARIANT_TYPE_DICT['compiler'] = {'interp-ac', 'interpreter', 'jit', 'optimizing',
-                              'regalloc_gc', 'speed-profile'}
+                                   'regalloc_gc', 'speed-profile'}
 
   for v_type in VARIANT_TYPE_DICT:
     TOTAL_VARIANTS_SET = TOTAL_VARIANTS_SET.union(VARIANT_TYPE_DICT.get(v_type))
@@ -173,106 +165,75 @@
     # Bisection search writes to standard output.
     env.ART_TEST_QUIET = False
 
-  if not TARGET_TYPES:
-    TARGET_TYPES.add('host')
-    TARGET_TYPES.add('target')
+  global _user_input_variants
+  global run_all_configs
+  if run_all_configs:
+    target_types = _user_input_variants['target']
+    _user_input_variants = VARIANT_TYPE_DICT
+    _user_input_variants['target'] = target_types
 
-  if env.ART_TEST_RUN_TEST_NO_PREBUILD:
-    PREBUILD_TYPES.add('no-prebuild')
-  if env.ART_TEST_RUN_TEST_NO_DEX2OAT:
-    PREBUILD_TYPES.add('no-dex2oat')
-  if env.ART_TEST_RUN_TEST_PREBUILD or not PREBUILD_TYPES: # Default
-    PREBUILD_TYPES.add('prebuild')
+  if not _user_input_variants['target']:
+    _user_input_variants['target'].add('host')
+    _user_input_variants['target'].add('target')
 
-  if env.ART_TEST_INTERPRETER_ACCESS_CHECKS:
-    COMPILER_TYPES.add('interp-ac')
-  if env.ART_TEST_INTERPRETER:
-    COMPILER_TYPES.add('interpreter')
-  if env.ART_TEST_JIT:
-    COMPILER_TYPES.add('jit')
-  if env.ART_TEST_OPTIMIZING_GRAPH_COLOR:
-    COMPILER_TYPES.add('regalloc_gc')
-    OPTIMIZING_COMPILER_TYPES.add('regalloc_gc')
-  if env.ART_TEST_OPTIMIZING:
-    COMPILER_TYPES.add('optimizing')
-    OPTIMIZING_COMPILER_TYPES.add('optimizing')
-  if env.ART_TEST_SPEED_PROFILE:
-    COMPILER_TYPES.add('speed-profile')
+  if not _user_input_variants['prebuild']: # Default
+    _user_input_variants['prebuild'].add('prebuild')
 
   # By default only run without jvmti
-  if not JVMTI_TYPES:
-    JVMTI_TYPES.add('no-jvmti')
+  if not _user_input_variants['jvmti']:
+    _user_input_variants['jvmti'].add('no-jvmti')
 
   # By default we run all 'compiler' variants.
-  if not COMPILER_TYPES:
-    COMPILER_TYPES.add('optimizing')
-    COMPILER_TYPES.add('jit')
-    COMPILER_TYPES.add('interpreter')
-    COMPILER_TYPES.add('interp-ac')
-    COMPILER_TYPES.add('speed-profile')
-    OPTIMIZING_COMPILER_TYPES.add('optimizing')
+  if not _user_input_variants['compiler']:
+    _user_input_variants['compiler'].add('optimizing')
+    _user_input_variants['compiler'].add('jit')
+    _user_input_variants['compiler'].add('interpreter')
+    _user_input_variants['compiler'].add('interp-ac')
+    _user_input_variants['compiler'].add('speed-profile')
 
-  if env.ART_TEST_RUN_TEST_RELOCATE:
-    RELOCATE_TYPES.add('relocate')
-  if env.ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT:
-    RELOCATE_TYPES.add('relocate-npatchoat')
-  if not RELOCATE_TYPES: # Default
-    RELOCATE_TYPES.add('no-relocate')
+  if not _user_input_variants['relocate']: # Default
+    _user_input_variants['relocate'].add('no-relocate')
 
-  if env.ART_TEST_TRACE:
-    TRACE_TYPES.add('trace')
-  if env.ART_TEST_TRACE_STREAM:
-    TRACE_TYPES.add('stream')
-  if not TRACE_TYPES: # Default
-    TRACE_TYPES.add('ntrace')
+  if not _user_input_variants['trace']: # Default
+    _user_input_variants['trace'].add('ntrace')
 
-  if env.ART_TEST_GC_STRESS:
-    GC_TYPES.add('gcstress')
-  if env.ART_TEST_GC_VERIFY:
-    GC_TYPES.add('gcverify')
-  if not GC_TYPES: # Default
-    GC_TYPES.add('cms')
+  if not _user_input_variants['gc']: # Default
+    _user_input_variants['gc'].add('cms')
 
-  if env.ART_TEST_JNI_FORCECOPY:
-    JNI_TYPES.add('forcecopy')
-  if not JNI_TYPES: # Default
-    JNI_TYPES.add('checkjni')
+  if not _user_input_variants['jni']: # Default
+    _user_input_variants['jni'].add('checkjni')
 
-  if env.ART_TEST_RUN_TEST_NO_IMAGE:
-    IMAGE_TYPES.add('no-image')
-  if env.ART_TEST_RUN_TEST_MULTI_IMAGE:
-    IMAGE_TYPES.add('multipicimage')
-  if env.ART_TEST_RUN_TEST_IMAGE or not IMAGE_TYPES: # Default
-    IMAGE_TYPES.add('picimage')
+  if not _user_input_variants['image']: # Default
+    _user_input_variants['image'].add('picimage')
 
-  if env.ART_TEST_PIC_TEST:
-    PICTEST_TYPES.add('pictest')
-  if not PICTEST_TYPES: # Default
-    PICTEST_TYPES.add('npictest')
 
-  if env.ART_TEST_RUN_TEST_NDEBUG:
-    RUN_TYPES.add('ndebug')
-  if env.ART_TEST_RUN_TEST_DEBUG or not RUN_TYPES: # Default
-    RUN_TYPES.add('debug')
+  if not _user_input_variants['pictest']: # Default
+    _user_input_variants['pictest'].add('npictest')
 
-  if env.ART_TEST_RUN_TEST_DEBUGGABLE:
-    DEBUGGABLE_TYPES.add('debuggable')
-  if not DEBUGGABLE_TYPES: # Default
-    DEBUGGABLE_TYPES.add('ndebuggable')
+  if not _user_input_variants['debuggable']: # Default
+    _user_input_variants['debuggable'].add('ndebuggable')
 
-  if not ADDRESS_SIZES:
-    ADDRESS_SIZES_TARGET['target'].add(env.ART_PHONY_TEST_TARGET_SUFFIX)
-    ADDRESS_SIZES_TARGET['host'].add(env.ART_PHONY_TEST_HOST_SUFFIX)
+  if not _user_input_variants['run']: # Default
+    _user_input_variants['run'].add('debug')
+
+  _user_input_variants['address_sizes_target'] = collections.defaultdict(set)
+  if not _user_input_variants['address_sizes']:
+    _user_input_variants['address_sizes_target']['target'].add(
+        env.ART_PHONY_TEST_TARGET_SUFFIX)
+    _user_input_variants['address_sizes_target']['host'].add(
+        env.ART_PHONY_TEST_HOST_SUFFIX)
     if env.ART_TEST_RUN_TEST_2ND_ARCH:
-      ADDRESS_SIZES_TARGET['host'].add(env.ART_2ND_PHONY_TEST_HOST_SUFFIX)
-      ADDRESS_SIZES_TARGET['target'].add(env.ART_2ND_PHONY_TEST_TARGET_SUFFIX)
+      _user_input_variants['address_sizes_target']['host'].add(
+          env.ART_2ND_PHONY_TEST_HOST_SUFFIX)
+      _user_input_variants['address_sizes_target']['target'].add(
+          env.ART_2ND_PHONY_TEST_TARGET_SUFFIX)
   else:
-    ADDRESS_SIZES_TARGET['host'] = ADDRESS_SIZES_TARGET['host'].union(ADDRESS_SIZES)
-    ADDRESS_SIZES_TARGET['target'] = ADDRESS_SIZES_TARGET['target'].union(ADDRESS_SIZES)
+    _user_input_variants['address_sizes_target']['host'] = _user_input_variants['address_sizes']
+    _user_input_variants['address_sizes_target']['target'] = _user_input_variants['address_sizes']
 
   global n_thread
   if n_thread is -1:
-    if 'target' in TARGET_TYPES:
+    if 'target' in _user_input_variants['target']:
       n_thread = get_default_threads('target')
     else:
       n_thread = get_default_threads('host')
@@ -308,20 +269,12 @@
   options_all = ''
   global total_test_count
   total_test_count = len(tests)
-  total_test_count *= len(RUN_TYPES)
-  total_test_count *= len(PREBUILD_TYPES)
-  total_test_count *= len(RELOCATE_TYPES)
-  total_test_count *= len(TRACE_TYPES)
-  total_test_count *= len(GC_TYPES)
-  total_test_count *= len(JNI_TYPES)
-  total_test_count *= len(IMAGE_TYPES)
-  total_test_count *= len(PICTEST_TYPES)
-  total_test_count *= len(DEBUGGABLE_TYPES)
-  total_test_count *= len(COMPILER_TYPES)
-  total_test_count *= len(JVMTI_TYPES)
+  for variant_type in VARIANT_TYPE_DICT:
+    if not (variant_type == 'target' or 'address_sizes' in variant_type):
+      total_test_count *= len(_user_input_variants[variant_type])
   target_address_combinations = 0
-  for target in TARGET_TYPES:
-    for address_size in ADDRESS_SIZES_TARGET[target]:
+  for target in _user_input_variants['target']:
+    for address_size in _user_input_variants['address_sizes_target'][target]:
       target_address_combinations += 1
   total_test_count *= target_address_combinations
 
@@ -345,14 +298,16 @@
   if dex2oat_jobs != -1:
     options_all += ' --dex2oat-jobs ' + str(dex2oat_jobs)
 
-  config = itertools.product(tests, TARGET_TYPES, RUN_TYPES, PREBUILD_TYPES,
-                             COMPILER_TYPES, RELOCATE_TYPES, TRACE_TYPES,
-                             GC_TYPES, JNI_TYPES, IMAGE_TYPES, PICTEST_TYPES,
-                             DEBUGGABLE_TYPES, JVMTI_TYPES)
+  config = itertools.product(tests, _user_input_variants['target'], _user_input_variants['run'],
+                             _user_input_variants['prebuild'], _user_input_variants['compiler'],
+                             _user_input_variants['relocate'], _user_input_variants['trace'],
+                             _user_input_variants['gc'], _user_input_variants['jni'],
+                             _user_input_variants['image'], _user_input_variants['pictest'],
+                             _user_input_variants['debuggable'], _user_input_variants['jvmti'])
 
   for test, target, run, prebuild, compiler, relocate, trace, gc, \
       jni, image, pictest, debuggable, jvmti in config:
-    for address_size in ADDRESS_SIZES_TARGET[target]:
+    for address_size in _user_input_variants['address_sizes_target'][target]:
       if stop_testrunner:
         # When ART_TEST_KEEP_GOING is set to false, then as soon as a test
         # fails, stop_testrunner is set to True. When this happens, the method
@@ -577,11 +532,10 @@
       total_test_count)
 
     if result == 'FAIL' or result == 'TIMEOUT':
-      info += ('%s %s %s\n%s\n') % (
+      info += ('%s %s %s\n') % (
         progress_info,
         test_name,
-        COLOR_ERROR + result + COLOR_NORMAL,
-        failed_test_info)
+        COLOR_ERROR + result + COLOR_NORMAL)
     else:
       result_text = ''
       if result == 'PASS':
@@ -617,6 +571,7 @@
 def verify_knownfailure_entry(entry):
   supported_field = {
       'tests' : (list, str),
+      'test_patterns' : (list,),
       'description' : (list, str),
       'bug' : (str,),
       'variant' : (str,),
@@ -650,6 +605,11 @@
     tests = failure.get('tests', [])
     if isinstance(tests, str):
       tests = [tests]
+    patterns = failure.get("test_patterns", [])
+    if (not isinstance(patterns, list)):
+      raise ValueError("test_patters is not a list in %s" % failure)
+
+    tests += [f for f in RUN_TEST_SET if any(re.match(pat, f) is not None for pat in patterns)]
     variants = parse_variants(failure.get('variant'))
     env_vars = failure.get('env_vars')
 
@@ -804,19 +764,19 @@
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
   match = re.match(regex, test_name)
   if match:
-    TARGET_TYPES.add(match.group(1))
-    RUN_TYPES.add(match.group(2))
-    PREBUILD_TYPES.add(match.group(3))
-    COMPILER_TYPES.add(match.group(4))
-    RELOCATE_TYPES.add(match.group(5))
-    TRACE_TYPES.add(match.group(6))
-    GC_TYPES.add(match.group(7))
-    JNI_TYPES.add(match.group(8))
-    IMAGE_TYPES.add(match.group(9))
-    PICTEST_TYPES.add(match.group(10))
-    DEBUGGABLE_TYPES.add(match.group(11))
-    JVMTI_TYPES.add(match.group(12))
-    ADDRESS_SIZES.add(match.group(14))
+    _user_input_variants['target'].add(match.group(1))
+    _user_input_variants['run'].add(match.group(2))
+    _user_input_variants['prebuild'].add(match.group(3))
+    _user_input_variants['compiler'].add(match.group(4))
+    _user_input_variants['relocate'].add(match.group(5))
+    _user_input_variants['trace'].add(match.group(6))
+    _user_input_variants['gc'].add(match.group(7))
+    _user_input_variants['jni'].add(match.group(8))
+    _user_input_variants['image'].add(match.group(9))
+    _user_input_variants['pictest'].add(match.group(10))
+    _user_input_variants['debuggable'].add(match.group(11))
+    _user_input_variants['jvmti'].add(match.group(12))
+    _user_input_variants['address_sizes'].add(match.group(14))
     return {match.group(13)}
   raise ValueError(test_name + " is not a valid test")
 
@@ -865,6 +825,7 @@
   global gdb_arg
   global timeout
   global dex2oat_jobs
+  global run_all_configs
 
   parser = argparse.ArgumentParser(description="Runs all or a subset of the ART test suite.")
   parser.add_argument('-t', '--test', dest='test', help='name of the test')
@@ -872,10 +833,7 @@
   parser.add_argument('--timeout', default=timeout, type=int, dest='timeout')
   for variant in TOTAL_VARIANTS_SET:
     flag = '--' + variant
-    flag_dest = variant.replace('-', '_')
-    if variant == '32' or variant == '64':
-      flag_dest = 'n' + flag_dest
-    parser.add_argument(flag, action='store_true', dest=flag_dest)
+    parser.add_argument(flag, action='store_true', dest=variant)
   parser.add_argument('--verbose', '-v', action='store_true', dest='verbose')
   parser.add_argument('--dry-run', action='store_true', dest='dry_run')
   parser.add_argument("--skip", action="append", dest="skips", default=[],
@@ -894,6 +852,8 @@
   parser.add_argument('--gdb-arg', dest='gdb_arg')
   parser.add_argument('--dex2oat-jobs', type=int, dest='dex2oat_jobs',
                       help='Number of dex2oat jobs')
+  parser.add_argument('-a', '--all', action='store_true', dest='run_all',
+                      help="Run all the possible configurations for the input test set")
 
   options = vars(parser.parse_args())
   if options['build_target']:
@@ -904,82 +864,12 @@
   env.EXTRA_DISABLED_TESTS.update(set(options['skips']))
   if options['test']:
     test = parse_test_name(options['test'])
-  if options['pictest']:
-    PICTEST_TYPES.add('pictest')
-  if options['ndebug']:
-    RUN_TYPES.add('ndebug')
-  if options['interp_ac']:
-    COMPILER_TYPES.add('interp-ac')
-  if options['picimage']:
-    IMAGE_TYPES.add('picimage')
-  if options['n64']:
-    ADDRESS_SIZES.add('64')
-  if options['interpreter']:
-    COMPILER_TYPES.add('interpreter')
-  if options['jni']:
-    JNI_TYPES.add('jni')
-  if options['relocate_npatchoat']:
-    RELOCATE_TYPES.add('relocate-npatchoat')
-  if options['no_prebuild']:
-    PREBUILD_TYPES.add('no-prebuild')
-  if options['npictest']:
-    PICTEST_TYPES.add('npictest')
-  if options['no_dex2oat']:
-    PREBUILD_TYPES.add('no-dex2oat')
-  if options['jit']:
-    COMPILER_TYPES.add('jit')
-  if options['relocate']:
-    RELOCATE_TYPES.add('relocate')
-  if options['ndebuggable']:
-    DEBUGGABLE_TYPES.add('ndebuggable')
-  if options['no_image']:
-    IMAGE_TYPES.add('no-image')
-  if options['optimizing']:
-    COMPILER_TYPES.add('optimizing')
-  if options['speed_profile']:
-    COMPILER_TYPES.add('speed-profile')
-  if options['trace']:
-    TRACE_TYPES.add('trace')
-  if options['gcstress']:
-    GC_TYPES.add('gcstress')
-  if options['no_relocate']:
-    RELOCATE_TYPES.add('no-relocate')
-  if options['target']:
-    TARGET_TYPES.add('target')
-  if options['forcecopy']:
-    JNI_TYPES.add('forcecopy')
-  if options['n32']:
-    ADDRESS_SIZES.add('32')
-  if options['host']:
-    TARGET_TYPES.add('host')
-  if options['gcverify']:
-    GC_TYPES.add('gcverify')
-  if options['debuggable']:
-    DEBUGGABLE_TYPES.add('debuggable')
-  if options['prebuild']:
-    PREBUILD_TYPES.add('prebuild')
-  if options['debug']:
-    RUN_TYPES.add('debug')
-  if options['checkjni']:
-    JNI_TYPES.add('checkjni')
-  if options['ntrace']:
-    TRACE_TYPES.add('ntrace')
-  if options['cms']:
-    GC_TYPES.add('cms')
-  if options['multipicimage']:
-    IMAGE_TYPES.add('multipicimage')
-  if options['jvmti_stress']:
-    JVMTI_TYPES.add('jvmti-stress')
-  if options['redefine_stress']:
-    JVMTI_TYPES.add('redefine-stress')
-  if options['field_stress']:
-    JVMTI_TYPES.add('field-stress')
-  if options['step_stress']:
-    JVMTI_TYPES.add('step-stress')
-  if options['trace_stress']:
-    JVMTI_TYPES.add('trace-stress')
-  if options['no_jvmti']:
-    JVMTI_TYPES.add('no-jvmti')
+
+  for variant_type in VARIANT_TYPE_DICT:
+    for variant in VARIANT_TYPE_DICT[variant_type]:
+      if options.get(variant):
+        _user_input_variants[variant_type].add(variant)
+
   if options['verbose']:
     verbose = True
   if options['n_thread']:
@@ -996,6 +886,8 @@
   timeout = options['timeout']
   if options['dex2oat_jobs']:
     dex2oat_jobs = options['dex2oat_jobs']
+  if options['run_all']:
+    run_all_configs = True
 
   return test
 
@@ -1005,9 +897,9 @@
   setup_test_env()
   if build:
     build_targets = ''
-    if 'host' in TARGET_TYPES:
+    if 'host' in _user_input_variants['target']:
       build_targets += 'test-art-host-run-test-dependencies'
-    if 'target' in TARGET_TYPES:
+    if 'target' in _user_input_variants['target']:
       build_targets += 'test-art-target-run-test-dependencies'
     build_command = 'make'
     build_command += ' -j'
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 2ce61cf..cf31e2e 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -22,10 +22,7 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_JAR_MANIFEST := src/manifest.txt
-LOCAL_JAVA_RESOURCE_FILES := \
-  $(LOCAL_PATH)/src/style.css
-
-LOCAL_STATIC_JAVA_LIBRARIES := perflib-prebuilt guavalib trove-prebuilt
+LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/src/style.css
 LOCAL_IS_HOST_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ahat
@@ -43,17 +40,11 @@
 LOCAL_SRC_FILES := ahat
 include $(BUILD_PREBUILT)
 
-# --- ahat-tests.jar --------------
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, test)
-LOCAL_JAR_MANIFEST := test/manifest.txt
-LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := ahat-tests
-include $(BUILD_HOST_JAVA_LIBRARY)
-AHAT_TEST_JAR := $(LOCAL_BUILT_MODULE)
-
+# The ahat tests rely on running ART to generate a heap dump for test, but ART
+# doesn't run on darwin. Only build and run the tests for linux.
+# There are also issues with running under instrumentation.
+ifeq ($(HOST_OS),linux)
+ifneq ($(EMMA_INSTRUMENT),true)
 # --- ahat-test-dump.jar --------------
 include $(CLEAR_VARS)
 LOCAL_MODULE := ahat-test-dump
@@ -69,7 +60,13 @@
 AHAT_TEST_DUMP_JAR := $(LOCAL_BUILT_MODULE)
 AHAT_TEST_DUMP_HPROF := $(intermediates.COMMON)/test-dump.hprof
 AHAT_TEST_DUMP_BASE_HPROF := $(intermediates.COMMON)/test-dump-base.hprof
-AHAT_TEST_DUMP_PROGUARD_MAP := $(proguard_dictionary)
+AHAT_TEST_DUMP_PROGUARD_MAP := $(intermediates.COMMON)/test-dump.map
+
+# Generate the proguard map in the desired location by copying it from
+# wherever the build system generates it by default.
+$(AHAT_TEST_DUMP_PROGUARD_MAP): PRIVATE_AHAT_SOURCE_PROGUARD_MAP := $(proguard_dictionary)
+$(AHAT_TEST_DUMP_PROGUARD_MAP): $(proguard_dictionary)
+	cp $(PRIVATE_AHAT_SOURCE_PROGUARD_MAP) $@
 
 # Run ahat-test-dump.jar to generate test-dump.hprof and test-dump-base.hprof
 AHAT_TEST_DUMP_DEPENDENCIES := \
@@ -80,23 +77,38 @@
 
 $(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
 $(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
-$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_DEPENDENCIES := $(AHAT_TEST_DUMP_DEPENDENCIES)
 $(AHAT_TEST_DUMP_HPROF): $(AHAT_TEST_DUMP_JAR) $(AHAT_TEST_DUMP_DEPENDENCIES)
 	$(PRIVATE_AHAT_TEST_ART) -cp $(PRIVATE_AHAT_TEST_DUMP_JAR) Main $@
 
 $(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
 $(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
-$(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_DUMP_DEPENDENCIES := $(AHAT_TEST_DUMP_DEPENDENCIES)
 $(AHAT_TEST_DUMP_BASE_HPROF): $(AHAT_TEST_DUMP_JAR) $(AHAT_TEST_DUMP_DEPENDENCIES)
 	$(PRIVATE_AHAT_TEST_ART) -cp $(PRIVATE_AHAT_TEST_DUMP_JAR) Main $@ --base
 
+# --- ahat-tests.jar --------------
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, test)
+LOCAL_JAR_MANIFEST := test/manifest.txt
+LOCAL_JAVA_RESOURCE_FILES := \
+  $(AHAT_TEST_DUMP_HPROF) \
+  $(AHAT_TEST_DUMP_BASE_HPROF) \
+  $(AHAT_TEST_DUMP_PROGUARD_MAP) \
+  $(LOCAL_PATH)/test-dump/L.hprof \
+  $(LOCAL_PATH)/test-dump/O.hprof \
+  $(LOCAL_PATH)/test-dump/RI.hprof
+LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := ahat-tests
+include $(BUILD_HOST_JAVA_LIBRARY)
+AHAT_TEST_JAR := $(LOCAL_BUILT_MODULE)
+
 .PHONY: ahat-test
-ahat-test: PRIVATE_AHAT_TEST_DUMP_HPROF := $(AHAT_TEST_DUMP_HPROF)
-ahat-test: PRIVATE_AHAT_TEST_DUMP_BASE_HPROF := $(AHAT_TEST_DUMP_BASE_HPROF)
 ahat-test: PRIVATE_AHAT_TEST_JAR := $(AHAT_TEST_JAR)
-ahat-test: PRIVATE_AHAT_PROGUARD_MAP := $(AHAT_TEST_DUMP_PROGUARD_MAP)
-ahat-test: $(AHAT_TEST_JAR) $(AHAT_TEST_DUMP_HPROF) $(AHAT_TEST_DUMP_BASE_HPROF)
-	java -enableassertions -Dahat.test.dump.hprof=$(PRIVATE_AHAT_TEST_DUMP_HPROF) -Dahat.test.dump.base.hprof=$(PRIVATE_AHAT_TEST_DUMP_BASE_HPROF) -Dahat.test.dump.map=$(PRIVATE_AHAT_PROGUARD_MAP) -jar $(PRIVATE_AHAT_TEST_JAR)
+ahat-test: $(AHAT_TEST_JAR)
+	java -enableassertions -jar $(PRIVATE_AHAT_TEST_JAR)
+endif # EMMA_INSTRUMENT
+endif # linux
 
 # Clean up local variables.
 AHAT_TEST_JAR :=
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index 4471c0a..ed40cb7 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -55,25 +55,6 @@
 Reported Issues:
  * Request to be able to sort tables by size.
 
-Perflib Requests:
- * Class objects should have java.lang.Class as their class object, not null.
- * ArrayInstance should have asString() to get the string, without requiring a
-   length function.
- * Document that getHeapIndex returns -1 for no such heap.
- * Look up totalRetainedSize for a heap by Heap object, not by a separate heap
-   index.
- * What's the difference between getId and getUniqueId?
- * I see objects with duplicate references.
- * A way to get overall retained size by heap.
- * A method Instance.isReachable()
-
-Things to move to perflib:
- * Extracting the string from a String Instance.
- * Extracting bitmap data from bitmap instances.
- * Adding up allocations by stack frame.
- * Computing, for each instance, the other instances it dominates.
- * Instance.isRoot and Instance.getRootTypes.
-
 Release History:
  1.4 Pending
 
diff --git a/tools/ahat/src/DocString.java b/tools/ahat/src/DocString.java
index 7970bf8..76e9e80 100644
--- a/tools/ahat/src/DocString.java
+++ b/tools/ahat/src/DocString.java
@@ -16,7 +16,6 @@
 
 package com.android.ahat;
 
-import com.google.common.html.HtmlEscapers;
 import java.net.URI;
 import java.net.URISyntaxException;
 
@@ -67,7 +66,7 @@
    * Returns this object.
    */
   public DocString append(String text) {
-    mStringBuilder.append(HtmlEscapers.htmlEscaper().escape(text));
+    mStringBuilder.append(HtmlEscaper.escape(text));
     return this;
   }
 
@@ -185,7 +184,7 @@
 
   public DocString appendImage(URI uri, String alt) {
     mStringBuilder.append("<img alt=\"");
-    mStringBuilder.append(HtmlEscapers.htmlEscaper().escape(alt));
+    mStringBuilder.append(HtmlEscaper.escape(alt));
     mStringBuilder.append("\" src=\"");
     mStringBuilder.append(uri.toASCIIString());
     mStringBuilder.append("\" />");
@@ -194,7 +193,7 @@
 
   public DocString appendThumbnail(URI uri, String alt) {
     mStringBuilder.append("<img height=\"16\" alt=\"");
-    mStringBuilder.append(HtmlEscapers.htmlEscaper().escape(alt));
+    mStringBuilder.append(HtmlEscaper.escape(alt));
     mStringBuilder.append("\" src=\"");
     mStringBuilder.append(uri.toASCIIString());
     mStringBuilder.append("\" />");
diff --git a/tools/ahat/src/HtmlEscaper.java b/tools/ahat/src/HtmlEscaper.java
new file mode 100644
index 0000000..75a6827
--- /dev/null
+++ b/tools/ahat/src/HtmlEscaper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+public class HtmlEscaper {
+  /**
+   * Escape html characters in the input string.
+   */
+  public static String escape(String text) {
+    String specials = "&<>\'\"";
+    String[] replacements = new String[]{"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"};
+    StringBuilder sb = null;
+    int low = 0;
+    for (int i = 0; i < text.length(); ++i) {
+      int s = specials.indexOf(text.charAt(i));
+      if (s != -1) {
+        if (sb == null) {
+          sb = new StringBuilder();
+        }
+        sb.append(text.substring(low, i));
+        sb.append(replacements[s]);
+        low = i + 1;
+      }
+    }
+    if (sb == null) {
+      return text;
+    }
+
+    sb.append(text.substring(low));
+    return sb.toString();
+  }
+}
+
+
diff --git a/tools/ahat/src/Main.java b/tools/ahat/src/Main.java
index 7cda035..623a865 100644
--- a/tools/ahat/src/Main.java
+++ b/tools/ahat/src/Main.java
@@ -18,7 +18,8 @@
 
 import com.android.ahat.heapdump.AhatSnapshot;
 import com.android.ahat.heapdump.Diff;
-import com.android.tools.perflib.heap.ProguardMap;
+import com.android.ahat.heapdump.Parser;
+import com.android.ahat.proguard.ProguardMap;
 import com.sun.net.httpserver.HttpServer;
 import java.io.File;
 import java.io.IOException;
@@ -46,7 +47,7 @@
     out.println("");
   }
 
-  public static void main(String[] args) throws IOException {
+  public static void main(String[] args) throws Exception {
     int port = 7100;
     for (String arg : args) {
       if (arg.equals("--help")) {
@@ -110,11 +111,11 @@
     HttpServer server = HttpServer.create(addr, 0);
 
     System.out.println("Processing hprof file...");
-    AhatSnapshot ahat = AhatSnapshot.fromHprof(hprof, map);
+    AhatSnapshot ahat = Parser.parseHeapDump(hprof, map);
 
     if (hprofbase != null) {
       System.out.println("Processing baseline hprof file...");
-      AhatSnapshot base = AhatSnapshot.fromHprof(hprofbase, mapbase);
+      AhatSnapshot base = Parser.parseHeapDump(hprofbase, mapbase);
 
       System.out.println("Diffing hprof files...");
       Diff.snapshots(ahat, base);
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index f4926aa..79f8b76 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -25,6 +25,7 @@
 import com.android.ahat.heapdump.DiffedFieldValue;
 import com.android.ahat.heapdump.FieldValue;
 import com.android.ahat.heapdump.PathElement;
+import com.android.ahat.heapdump.RootType;
 import com.android.ahat.heapdump.Site;
 import com.android.ahat.heapdump.Value;
 import java.io.IOException;
@@ -74,13 +75,13 @@
 
     doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
 
-    Collection<String> rootTypes = inst.getRootTypes();
+    Collection<RootType> rootTypes = inst.getRootTypes();
     if (rootTypes != null) {
       DocString types = new DocString();
       String comma = "";
-      for (String type : rootTypes) {
+      for (RootType type : rootTypes) {
         types.append(comma);
-        types.append(type);
+        types.append(type.toString());
         comma = ", ";
       }
       doc.description(DocString.text("Root Types"), types);
@@ -175,21 +176,21 @@
       was.append(Summarizer.summarize(previous));
       switch (field.status) {
         case ADDED:
-          doc.row(DocString.text(field.type),
+          doc.row(DocString.text(field.type.name),
                   DocString.text(field.name),
                   Summarizer.summarize(field.current),
                   DocString.added("new"));
           break;
 
         case MATCHED:
-          doc.row(DocString.text(field.type),
+          doc.row(DocString.text(field.type.name),
                   DocString.text(field.name),
                   Summarizer.summarize(field.current),
                   Objects.equals(field.current, previous) ? new DocString() : was);
           break;
 
         case DELETED:
-          doc.row(DocString.text(field.type),
+          doc.row(DocString.text(field.type.name),
                   DocString.text(field.name),
                   DocString.removed("del"),
                   was);
diff --git a/tools/ahat/src/StaticHandler.java b/tools/ahat/src/StaticHandler.java
index b2805d6..4a68f1c 100644
--- a/tools/ahat/src/StaticHandler.java
+++ b/tools/ahat/src/StaticHandler.java
@@ -16,7 +16,6 @@
 
 package com.android.ahat;
 
-import com.google.common.io.ByteStreams;
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpHandler;
 import java.io.IOException;
@@ -49,7 +48,12 @@
       exchange.getResponseHeaders().add("Content-Type", mContentType);
       exchange.sendResponseHeaders(200, 0);
       OutputStream os = exchange.getResponseBody();
-      ByteStreams.copy(is, os);
+      int read;
+      byte[] buf = new byte[4096];
+      while ((read = is.read(buf)) >= 0) {
+        os.write(buf, 0, read);
+      }
+      is.close();
       os.close();
     }
   }
diff --git a/tools/ahat/src/heapdump/AhatArrayInstance.java b/tools/ahat/src/heapdump/AhatArrayInstance.java
index 8d23276..50a4805 100644
--- a/tools/ahat/src/heapdump/AhatArrayInstance.java
+++ b/tools/ahat/src/heapdump/AhatArrayInstance.java
@@ -16,20 +16,20 @@
 
 package com.android.ahat.heapdump;
 
-import com.android.tools.perflib.heap.ArrayInstance;
-import com.android.tools.perflib.heap.Instance;
 import java.nio.charset.StandardCharsets;
 import java.util.AbstractList;
 import java.util.Collections;
 import java.util.List;
 
 public class AhatArrayInstance extends AhatInstance {
-  // To save space, we store byte, character, and object arrays directly as
-  // byte, character, and AhatInstance arrays respectively. This is especially
-  // important for large byte arrays, such as bitmaps. All other array types
-  // are stored as an array of objects, though we could potentially save space
-  // by specializing those too. mValues is a list view of the underlying
-  // array.
+  // To save space, we store arrays as primitive arrays or AhatInstance arrays
+  // and provide a wrapper over the arrays to expose a list of Values.
+  // This is especially important for large byte arrays, such as bitmaps.
+  // We keep a separate pointer to the underlying array in the case of byte or
+  // char arrays because they are sometimes useful to have.
+  // TODO: Have different subtypes of AhatArrayInstance to avoid the overhead
+  // of these extra pointers and cost in getReferences when the array type is
+  // not relevant?
   private List<Value> mValues;
   private byte[] mByteArray;    // null if not a byte array.
   private char[] mCharArray;    // null if not a char array.
@@ -38,72 +38,151 @@
     super(id);
   }
 
-  @Override void initialize(AhatSnapshot snapshot, Instance inst, Site site) {
-    super.initialize(snapshot, inst, site);
+  /**
+   * Initialize the array elements for a primitive boolean array.
+   */
+  void initialize(final boolean[] bools) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return bools.length;
+      }
 
-    ArrayInstance array = (ArrayInstance)inst;
-    switch (array.getArrayType()) {
-      case OBJECT:
-        Object[] objects = array.getValues();
-        final AhatInstance[] insts = new AhatInstance[objects.length];
-        for (int i = 0; i < objects.length; i++) {
-          if (objects[i] != null) {
-            Instance ref = (Instance)objects[i];
-            insts[i] = snapshot.findInstance(ref.getId());
-          }
-        }
-        mValues = new AbstractList<Value>() {
-          @Override public int size() {
-            return insts.length;
-          }
+      @Override public Value get(int index) {
+        return Value.pack(bools[index]);
+      }
+    };
+  }
 
-          @Override public Value get(int index) {
-            return Value.pack(insts[index]);
-          }
-        };
-        break;
+  /**
+   * Initialize the array elements for a primitive char array.
+   */
+  void initialize(final char[] chars) {
+    mCharArray = chars;
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return chars.length;
+      }
 
-      case CHAR:
-        final char[] chars = array.asCharArray(0, array.getLength());
-        mCharArray = chars;
-        mValues = new AbstractList<Value>() {
-          @Override public int size() {
-            return chars.length;
-          }
+      @Override public Value get(int index) {
+        return Value.pack(chars[index]);
+      }
+    };
+  }
 
-          @Override public Value get(int index) {
-            return Value.pack(chars[index]);
-          }
-        };
-        break;
+  /**
+   * Initialize the array elements for a primitive float array.
+   */
+  void initialize(final float[] floats) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return floats.length;
+      }
 
-      case BYTE:
-        final byte[] bytes = array.asRawByteArray(0, array.getLength());
-        mByteArray = bytes;
-        mValues = new AbstractList<Value>() {
-          @Override public int size() {
-            return bytes.length;
-          }
+      @Override public Value get(int index) {
+        return Value.pack(floats[index]);
+      }
+    };
+  }
 
-          @Override public Value get(int index) {
-            return Value.pack(bytes[index]);
-          }
-        };
-        break;
+  /**
+   * Initialize the array elements for a primitive double array.
+   */
+  void initialize(final double[] doubles) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return doubles.length;
+      }
 
-      default:
-        final Object[] values = array.getValues();
-        mValues = new AbstractList<Value>() {
-          @Override public int size() {
-            return values.length;
-          }
+      @Override public Value get(int index) {
+        return Value.pack(doubles[index]);
+      }
+    };
+  }
 
-          @Override public Value get(int index) {
-            return Value.pack(values[index]);
-          }
-        };
-        break;
+  /**
+   * Initialize the array elements for a primitive byte array.
+   */
+  void initialize(final byte[] bytes) {
+    mByteArray = bytes;
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return bytes.length;
+      }
+
+      @Override public Value get(int index) {
+        return Value.pack(bytes[index]);
+      }
+    };
+  }
+
+  /**
+   * Initialize the array elements for a primitive short array.
+   */
+  void initialize(final short[] shorts) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return shorts.length;
+      }
+
+      @Override public Value get(int index) {
+        return Value.pack(shorts[index]);
+      }
+    };
+  }
+
+  /**
+   * Initialize the array elements for a primitive int array.
+   */
+  void initialize(final int[] ints) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return ints.length;
+      }
+
+      @Override public Value get(int index) {
+        return Value.pack(ints[index]);
+      }
+    };
+  }
+
+  /**
+   * Initialize the array elements for a primitive long array.
+   */
+  void initialize(final long[] longs) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return longs.length;
+      }
+
+      @Override public Value get(int index) {
+        return Value.pack(longs[index]);
+      }
+    };
+  }
+
+  /**
+   * Initialize the array elements for an instance array.
+   */
+  void initialize(final AhatInstance[] insts) {
+    mValues = new AbstractList<Value>() {
+      @Override public int size() {
+        return insts.length;
+      }
+
+      @Override public Value get(int index) {
+        return Value.pack(insts[index]);
+      }
+    };
+  }
+
+  @Override
+  protected long getExtraJavaSize() {
+    int length = getLength();
+    if (length == 0) {
+      return 0;
     }
+
+    return Value.getType(mValues.get(0)).size * getLength();
   }
 
   /**
diff --git a/tools/ahat/src/heapdump/AhatClassInstance.java b/tools/ahat/src/heapdump/AhatClassInstance.java
index f7d8431..94efa50 100644
--- a/tools/ahat/src/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/heapdump/AhatClassInstance.java
@@ -16,11 +16,8 @@
 
 package com.android.ahat.heapdump;
 
-import com.android.tools.perflib.heap.ClassInstance;
-import com.android.tools.perflib.heap.Instance;
 import java.awt.image.BufferedImage;
 import java.util.Iterator;
-import java.util.List;
 import java.util.NoSuchElementException;
 
 public class AhatClassInstance extends AhatInstance {
@@ -34,15 +31,13 @@
     super(id);
   }
 
-  @Override void initialize(AhatSnapshot snapshot, Instance inst, Site site) {
-    super.initialize(snapshot, inst, site);
+  void initialize(Value[] fields) {
+    mFields = fields;
+  }
 
-    ClassInstance classInst = (ClassInstance)inst;
-    List<ClassInstance.FieldValue> fieldValues = classInst.getValues();
-    mFields = new Value[fieldValues.size()];
-    for (int i = 0; i < mFields.length; i++) {
-      mFields[i] = snapshot.getValue(fieldValues.get(i).getValue());
-    }
+  @Override
+  protected long getExtraJavaSize() {
+    return 0;
   }
 
   @Override public Value getField(String fieldName) {
@@ -123,7 +118,7 @@
     }
 
     Value value = getField("value");
-    if (!value.isAhatInstance()) {
+    if (value == null || !value.isAhatInstance()) {
       return null;
     }
 
@@ -248,6 +243,49 @@
     return bitmap;
   }
 
+  @Override
+  public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+    if (!isInstanceOfClass("sun.misc.Cleaner")) {
+      return null;
+    }
+
+    Value vthunk = getField("thunk");
+    if (vthunk == null || !vthunk.isAhatInstance()) {
+      return null;
+    }
+
+    AhatClassInstance thunk = vthunk.asAhatInstance().asClassInstance();
+    if (thunk == null
+        || !thunk.isInstanceOfClass("libcore.util.NativeAllocationRegistry$CleanerThunk")) {
+      return null;
+    }
+
+    Value vregistry = thunk.getField("this$0");
+    if (vregistry == null || !vregistry.isAhatInstance()) {
+      return null;
+    }
+
+    AhatClassInstance registry = vregistry.asAhatInstance().asClassInstance();
+    if (registry == null || !registry.isInstanceOfClass("libcore.util.NativeAllocationRegistry")) {
+      return null;
+    }
+
+    Value size = registry.getField("size");
+    if (!size.isLong()) {
+      return null;
+    }
+
+    Value referent = getField("referent");
+    if (referent == null || !referent.isAhatInstance()) {
+      return null;
+    }
+
+    RegisteredNativeAllocation rna = new RegisteredNativeAllocation();
+    rna.referent = referent.asAhatInstance();
+    rna.size = size.asLong();
+    return rna;
+  }
+
   private static class InstanceFieldIterator implements Iterable<FieldValue>,
                                                         Iterator<FieldValue> {
     // The complete list of instance field values to iterate over, including
diff --git a/tools/ahat/src/heapdump/AhatClassObj.java b/tools/ahat/src/heapdump/AhatClassObj.java
index 08c7097..be0f713 100644
--- a/tools/ahat/src/heapdump/AhatClassObj.java
+++ b/tools/ahat/src/heapdump/AhatClassObj.java
@@ -16,13 +16,9 @@
 
 package com.android.ahat.heapdump;
 
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Instance;
 import java.util.AbstractList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 public class AhatClassObj extends AhatInstance {
   private String mClassName;
@@ -30,43 +26,32 @@
   private AhatInstance mClassLoader;
   private FieldValue[] mStaticFieldValues;
   private Field[] mInstanceFields;
+  private long mStaticFieldsSize;
+  private long mInstanceSize;
 
-  public AhatClassObj(long id) {
+  public AhatClassObj(long id, String className) {
     super(id);
+    mClassName = className;
   }
 
-  @Override void initialize(AhatSnapshot snapshot, Instance inst, Site site) {
-    super.initialize(snapshot, inst, site);
+  void initialize(AhatClassObj superClass,
+                  long instanceSize,
+                  Field[] instanceFields,
+                  long staticFieldsSize) {
+    mSuperClassObj = superClass;
+    mInstanceSize = instanceSize;
+    mInstanceFields = instanceFields;
+    mStaticFieldsSize = staticFieldsSize;
+  }
 
-    ClassObj classObj = (ClassObj)inst;
-    mClassName = classObj.getClassName();
+  void initialize(AhatInstance classLoader, FieldValue[] staticFields) {
+    mClassLoader = classLoader;
+    mStaticFieldValues = staticFields;
+  }
 
-    ClassObj superClassObj = classObj.getSuperClassObj();
-    if (superClassObj != null) {
-      mSuperClassObj = snapshot.findClassObj(superClassObj.getId());
-    }
-
-    Instance loader = classObj.getClassLoader();
-    if (loader != null) {
-      mClassLoader = snapshot.findInstance(loader.getId());
-    }
-
-    Collection<Map.Entry<com.android.tools.perflib.heap.Field, Object>> fieldValues
-      = classObj.getStaticFieldValues().entrySet();
-    mStaticFieldValues = new FieldValue[fieldValues.size()];
-    int index = 0;
-    for (Map.Entry<com.android.tools.perflib.heap.Field, Object> field : fieldValues) {
-      String name = field.getKey().getName();
-      String type = field.getKey().getType().toString();
-      Value value = snapshot.getValue(field.getValue());
-      mStaticFieldValues[index++] = new FieldValue(name, type, value);
-    }
-
-    com.android.tools.perflib.heap.Field[] fields = classObj.getFields();
-    mInstanceFields = new Field[fields.length];
-    for (int i = 0; i < fields.length; i++) {
-      mInstanceFields[i] = new Field(fields[i].getName(), fields[i].getType().toString());
-    }
+  @Override
+  protected long getExtraJavaSize() {
+    return mStaticFieldsSize;
   }
 
   /**
@@ -91,6 +76,14 @@
   }
 
   /**
+   * Returns the size of instances of this object, as reported in the heap
+   * dump.
+   */
+  public long getInstanceSize() {
+    return mInstanceSize;
+  }
+
+  /**
    * Returns the static field values for this class object.
    */
   public List<FieldValue> getStaticFieldValues() {
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index 0e78558..c044487 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -17,8 +17,6 @@
 package com.android.ahat.heapdump;
 
 import com.android.ahat.dominators.DominatorsComputation;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Instance;
 import java.awt.image.BufferedImage;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -34,14 +32,15 @@
   private final long mId;
 
   // Fields initialized in initialize().
-  private Size mSize;
   private AhatHeap mHeap;
   private AhatClassObj mClassObj;
   private Site mSite;
 
-  // If this instance is a root, mRootTypes contains a set of the root types.
-  // If this instance is not a root, mRootTypes is null.
-  private List<String> mRootTypes;
+  // Bit vector of the root types of this object.
+  private int mRootTypes;
+
+  // Field initialized via addRegisterednativeSize.
+  private long mRegisteredNativeSize = 0;
 
   // Fields initialized in computeReverseReferences().
   private AhatInstance mNextInstanceToGcRoot;
@@ -55,33 +54,29 @@
   private AhatInstance mImmediateDominator;
   private List<AhatInstance> mDominated = new ArrayList<AhatInstance>();
   private Size[] mRetainedSizes;
-  private Object mDominatorsComputationState;
 
   // The baseline instance for purposes of diff.
   private AhatInstance mBaseline;
 
+  // temporary user data associated with this instance. This is used for a
+  // couple different purposes:
+  // 1. During parsing of instances, to store temporary field data.
+  // 2. During dominators computation, to store the dominators computation state.
+  private Object mTemporaryUserData;
+
   public AhatInstance(long id) {
     mId = id;
     mBaseline = this;
   }
 
   /**
-   * Initializes this AhatInstance based on the given perflib instance.
-   * The AhatSnapshot should be used to look up AhatInstances and AhatHeaps.
-   * There is no guarantee that the AhatInstances returned by
-   * snapshot.findInstance have been initialized yet.
+   * Initialize this AhatInstance based on the the given info.
    */
-  void initialize(AhatSnapshot snapshot, Instance inst, Site site) {
-    site.addInstance(this);
-    mSize = new Size(inst.getSize(), 0);
-    mHeap = snapshot.getHeap(inst.getHeap().getName());
-
-    ClassObj clsObj = inst.getClassObj();
-    if (clsObj != null) {
-      mClassObj = snapshot.findClassObj(clsObj.getId());
-    }
-
+  void initialize(AhatHeap heap, Site site, AhatClassObj classObj) {
+    mHeap = heap;
     mSite = site;
+    site.addInstance(this);
+    mClassObj = classObj;
   }
 
   /**
@@ -95,10 +90,20 @@
    * Returns the shallow number of bytes this object takes up.
    */
   public Size getSize() {
-    return mSize;
+    return new Size(mClassObj.getInstanceSize() + getExtraJavaSize(), mRegisteredNativeSize);
   }
 
   /**
+   * Returns the number of bytes taken up by this object on the Java heap
+   * beyond the standard instance size as recorded by the class of this
+   * instance.
+   *
+   * For example, class objects will have extra size for static fields and
+   * array objects will have extra size for the array elements.
+   */
+  protected abstract long getExtraJavaSize();
+
+  /**
    * Returns the number of bytes belonging to the given heap that this instance
    * retains.
    */
@@ -127,7 +132,7 @@
    * Increment the number of registered native bytes tied to this object.
    */
   void addRegisteredNativeSize(long size) {
-    mSize = mSize.plusRegisteredNativeSize(size);
+    mRegisteredNativeSize += size;
   }
 
   /**
@@ -154,27 +159,32 @@
    * Returns true if this instance is marked as a root instance.
    */
   public boolean isRoot() {
-    return mRootTypes != null;
+    return mRootTypes != 0;
   }
 
   /**
    * Marks this instance as being a root of the given type.
    */
-  void addRootType(String type) {
-    if (mRootTypes == null) {
-      mRootTypes = new ArrayList<String>();
-      mRootTypes.add(type);
-    } else if (!mRootTypes.contains(type)) {
-      mRootTypes.add(type);
-    }
+  void addRootType(RootType type) {
+    mRootTypes |= type.mask;
   }
 
   /**
-   * Returns a list of string descriptions of the root types of this object.
+   * Returns a list of the root types of this object.
    * Returns null if this object is not a root.
    */
-  public Collection<String> getRootTypes() {
-    return mRootTypes;
+  public Collection<RootType> getRootTypes() {
+    if (!isRoot()) {
+      return null;
+    }
+
+    List<RootType> types = new ArrayList<RootType>();
+    for (RootType type : RootType.values()) {
+      if ((mRootTypes & type.mask) != 0) {
+        types.add(type);
+      }
+    }
+    return types;
   }
 
   /**
@@ -363,6 +373,19 @@
     return null;
   }
 
+  public static class RegisteredNativeAllocation {
+    public AhatInstance referent;
+    public long size;
+  };
+
+  /**
+   * Return the registered native allocation that this instance represents, if
+   * any. This is relevant for instances of sun.misc.Cleaner.
+   */
+  public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+    return null;
+  }
+
   /**
    * Returns a sample path from a GC root to this instance.
    * This instance is included as the last element of the path with an empty
@@ -433,6 +456,14 @@
     return new AhatPlaceHolderInstance(this);
   }
 
+  public void setTemporaryUserData(Object state) {
+    mTemporaryUserData = state;
+  }
+
+  public Object getTemporaryUserData() {
+    return mTemporaryUserData;
+  }
+
   /**
    * Initialize the reverse reference fields of this instance and all other
    * instances reachable from it. Initializes the following fields:
@@ -498,7 +529,7 @@
         }
         if (!(inst instanceof SuperRoot)) {
           inst.mRetainedSizes[inst.mHeap.getIndex()] =
-            inst.mRetainedSizes[inst.mHeap.getIndex()].plus(inst.mSize);
+            inst.mRetainedSizes[inst.mHeap.getIndex()].plus(inst.getSize());
         }
         deque.push(inst);
         for (AhatInstance dominated : inst.mDominated) {
@@ -516,12 +547,12 @@
 
   @Override
   public void setDominatorsComputationState(Object state) {
-    mDominatorsComputationState = state;
+    setTemporaryUserData(state);
   }
 
   @Override
   public Object getDominatorsComputationState() {
-    return mDominatorsComputationState;
+    return getTemporaryUserData();
   }
 
   @Override
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
index 8b4c679..07f5b50 100644
--- a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
+++ b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
@@ -24,11 +24,15 @@
  */
 public class AhatPlaceHolderClassObj extends AhatClassObj {
   AhatPlaceHolderClassObj(AhatClassObj baseline) {
-    super(-1);
+    super(-1, baseline.getClassName());
     setBaseline(baseline);
     baseline.setBaseline(this);
   }
 
+  @Override public Size getSize() {
+    return Size.ZERO;
+  }
+
   @Override public Size getRetainedSize(AhatHeap heap) {
     return Size.ZERO;
   }
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java b/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
index 9abc952..8849403 100644
--- a/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
+++ b/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
@@ -36,6 +36,10 @@
     return Size.ZERO;
   }
 
+  @Override protected long getExtraJavaSize() {
+    return 0;
+  }
+
   @Override public Size getRetainedSize(AhatHeap heap) {
     return Size.ZERO;
   }
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/heapdump/AhatSnapshot.java
index 1b2cf3c..945966c 100644
--- a/tools/ahat/src/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/heapdump/AhatSnapshot.java
@@ -17,158 +17,43 @@
 package com.android.ahat.heapdump;
 
 import com.android.ahat.dominators.DominatorsComputation;
-import com.android.tools.perflib.captures.DataBuffer;
-import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
-import com.android.tools.perflib.heap.ArrayInstance;
-import com.android.tools.perflib.heap.ClassInstance;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Heap;
-import com.android.tools.perflib.heap.Instance;
-import com.android.tools.perflib.heap.ProguardMap;
-import com.android.tools.perflib.heap.RootObj;
-import com.android.tools.perflib.heap.Snapshot;
-import com.android.tools.perflib.heap.StackFrame;
-import com.android.tools.perflib.heap.StackTrace;
-import gnu.trove.TObjectProcedure;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 
 public class AhatSnapshot implements Diffable<AhatSnapshot> {
-  private final Site mRootSite = new Site("ROOT");
+  private final Site mRootSite;
 
-  // Collection of objects whose immediate dominator is the SENTINEL_ROOT.
-  private final List<AhatInstance> mRooted;
+  private final SuperRoot mSuperRoot;
 
-  // List of all ahat instances stored in increasing order by id.
-  private final List<AhatInstance> mInstances = new ArrayList<AhatInstance>();
+  // List of all ahat instances.
+  private final Instances<AhatInstance> mInstances;
 
-  private final List<AhatHeap> mHeaps = new ArrayList<AhatHeap>();
+  private List<AhatHeap> mHeaps;
 
   private AhatSnapshot mBaseline = this;
 
-  /**
-   * Create an AhatSnapshot from an hprof file.
-   */
-  public static AhatSnapshot fromHprof(File hprof, ProguardMap map) throws IOException {
-    return fromDataBuffer(new MemoryMappedFileBuffer(hprof), map);
-  }
+  AhatSnapshot(SuperRoot root,
+               Instances<AhatInstance> instances,
+               List<AhatHeap> heaps,
+               Site rootSite) {
+    mSuperRoot = root;
+    mInstances = instances;
+    mHeaps = heaps;
+    mRootSite = rootSite;
 
-  /**
-   * Create an AhatSnapshot from an in-memory data buffer.
-   */
-  public static AhatSnapshot fromDataBuffer(DataBuffer buffer, ProguardMap map) throws IOException {
-    AhatSnapshot snapshot = new AhatSnapshot(buffer, map);
-
-    // Request a GC now to clean up memory used by perflib. This helps to
-    // avoid a noticable pause when visiting the first interesting page in
-    // ahat.
-    System.gc();
-
-    return snapshot;
-  }
-
-  /**
-   * Constructs an AhatSnapshot for the given hprof binary data.
-   */
-  private AhatSnapshot(DataBuffer buffer, ProguardMap map) throws IOException {
-    Snapshot snapshot = Snapshot.createSnapshot(buffer, map);
-
-    // Properly label the class of class objects in the perflib snapshot.
-    final ClassObj javaLangClass = snapshot.findClass("java.lang.Class");
-    if (javaLangClass != null) {
-      for (Heap heap : snapshot.getHeaps()) {
-        Collection<ClassObj> classes = heap.getClasses();
-        for (ClassObj clsObj : classes) {
-          if (clsObj.getClassObj() == null) {
-            clsObj.setClassId(javaLangClass.getId());
-          }
-        }
+    // Update registered native allocation size.
+    for (AhatInstance cleaner : mInstances) {
+      AhatInstance.RegisteredNativeAllocation nra = cleaner.asRegisteredNativeAllocation();
+      if (nra != null) {
+        nra.referent.addRegisteredNativeSize(nra.size);
       }
     }
 
-    // Create mappings from id to ahat instance and heaps.
-    Collection<Heap> heaps = snapshot.getHeaps();
-    for (Heap heap : heaps) {
-      // Note: mHeaps will not be in index order if snapshot.getHeaps does not
-      // return heaps in index order. That's fine, because we don't rely on
-      // mHeaps being in index order.
-      mHeaps.add(new AhatHeap(heap.getName(), snapshot.getHeapIndex(heap)));
-      TObjectProcedure<Instance> doCreate = new TObjectProcedure<Instance>() {
-        @Override
-        public boolean execute(Instance inst) {
-          long id = inst.getId();
-          if (inst instanceof ClassInstance) {
-            mInstances.add(new AhatClassInstance(id));
-          } else if (inst instanceof ArrayInstance) {
-            mInstances.add(new AhatArrayInstance(id));
-          } else if (inst instanceof ClassObj) {
-            AhatClassObj classObj = new AhatClassObj(id);
-            mInstances.add(classObj);
-          }
-          return true;
-        }
-      };
-      for (Instance instance : heap.getClasses()) {
-        doCreate.execute(instance);
-      }
-      heap.forEachInstance(doCreate);
-    }
+    AhatInstance.computeReverseReferences(mSuperRoot);
+    DominatorsComputation.computeDominators(mSuperRoot);
+    AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size());
 
-    // Sort the instances by id so we can use binary search to lookup
-    // instances by id.
-    mInstances.sort(new Comparator<AhatInstance>() {
-      @Override
-      public int compare(AhatInstance a, AhatInstance b) {
-        return Long.compare(a.getId(), b.getId());
-      }
-    });
-
-    Map<Instance, Long> registeredNative = Perflib.getRegisteredNativeAllocations(snapshot);
-
-    // Initialize ahat snapshot and instances based on the perflib snapshot
-    // and instances.
-    for (AhatInstance ahat : mInstances) {
-      Instance inst = snapshot.findInstance(ahat.getId());
-
-      StackFrame[] frames = null;
-      StackTrace stack = inst.getStack();
-      if (stack != null) {
-        frames = stack.getFrames();
-      }
-      ahat.initialize(this, inst, mRootSite.getSite(frames));
-
-      Long registeredNativeSize = registeredNative.get(inst);
-      if (registeredNativeSize != null) {
-        ahat.addRegisteredNativeSize(registeredNativeSize);
-      }
-    }
-
-    // Record the roots and their types.
-    SuperRoot superRoot = new SuperRoot();
-    for (RootObj root : snapshot.getGCRoots()) {
-      Instance inst = root.getReferredInstance();
-      if (inst != null) {
-        AhatInstance ahat = findInstance(inst.getId());
-        if (!ahat.isRoot()) {
-          superRoot.addRoot(ahat);
-        }
-        ahat.addRootType(root.getRootType().toString());
-      }
-    }
-    snapshot.dispose();
-
-    AhatInstance.computeReverseReferences(superRoot);
-    DominatorsComputation.computeDominators(superRoot);
-    AhatInstance.computeRetainedSize(superRoot, mHeaps.size());
-
-    mRooted = superRoot.getDominated();
     for (AhatHeap heap : mHeaps) {
-      heap.addToSize(superRoot.getRetainedSize(heap));
+      heap.addToSize(mSuperRoot.getRetainedSize(heap));
     }
 
     mRootSite.prepareForUse(0, mHeaps.size());
@@ -179,22 +64,7 @@
    * Returns null if no instance with the given id is found.
    */
   public AhatInstance findInstance(long id) {
-    // Binary search over the sorted instances.
-    int start = 0;
-    int end = mInstances.size();
-    while (start < end) {
-      int mid = start + ((end - start) / 2);
-      AhatInstance midInst = mInstances.get(mid);
-      long midId = midInst.getId();
-      if (id == midId) {
-        return midInst;
-      } else if (id < midId) {
-        end = mid;
-      } else {
-        start = mid + 1;
-      }
-    }
-    return null;
+    return mInstances.get(id);
   }
 
   /**
@@ -235,7 +105,7 @@
    * SENTINEL_ROOT.
    */
   public List<AhatInstance> getRooted() {
-    return mRooted;
+    return mSuperRoot.getDominated();
   }
 
   /**
@@ -252,14 +122,6 @@
     return site == null ? mRootSite : site;
   }
 
-  // Return the Value for the given perflib value object.
-  Value getValue(Object value) {
-    if (value instanceof Instance) {
-      value = findInstance(((Instance)value).getId());
-    }
-    return Value.pack(value);
-  }
-
   public void setBaseline(AhatSnapshot baseline) {
     mBaseline = baseline;
   }
diff --git a/tools/ahat/src/heapdump/DiffedFieldValue.java b/tools/ahat/src/heapdump/DiffedFieldValue.java
index e2dcf3e..3cd273e 100644
--- a/tools/ahat/src/heapdump/DiffedFieldValue.java
+++ b/tools/ahat/src/heapdump/DiffedFieldValue.java
@@ -23,7 +23,7 @@
  */
 public class DiffedFieldValue {
   public final String name;
-  public final String type;
+  public final Type type;
   public final Value current;
   public final Value baseline;
 
@@ -60,7 +60,7 @@
     return new DiffedFieldValue(baseline.name, baseline.type, null, baseline.value, Status.DELETED);
   }
 
-  private DiffedFieldValue(String name, String type, Value current, Value baseline, Status status) {
+  private DiffedFieldValue(String name, Type type, Value current, Value baseline, Status status) {
     this.name = name;
     this.type = type;
     this.current = current;
diff --git a/tools/ahat/src/heapdump/Field.java b/tools/ahat/src/heapdump/Field.java
index 01f87c7..dff4017 100644
--- a/tools/ahat/src/heapdump/Field.java
+++ b/tools/ahat/src/heapdump/Field.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
 
 public class Field {
   public final String name;
-  public final String type;
+  public final Type type;
 
-  public Field(String name, String type) {
+  public Field(String name, Type type) {
     this.name = name;
     this.type = type;
   }
diff --git a/tools/ahat/src/heapdump/FieldValue.java b/tools/ahat/src/heapdump/FieldValue.java
index 6d72595..20e6da7 100644
--- a/tools/ahat/src/heapdump/FieldValue.java
+++ b/tools/ahat/src/heapdump/FieldValue.java
@@ -18,10 +18,10 @@
 
 public class FieldValue {
   public final String name;
-  public final String type;
+  public final Type type;
   public final Value value;
 
-  public FieldValue(String name, String type, Value value) {
+  public FieldValue(String name, Type type, Value value) {
     this.name = name;
     this.type = type;
     this.value = value;
diff --git a/tools/ahat/src/heapdump/HprofFormatException.java b/tools/ahat/src/heapdump/HprofFormatException.java
new file mode 100644
index 0000000..55e8958
--- /dev/null
+++ b/tools/ahat/src/heapdump/HprofFormatException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.heapdump;
+
+public class HprofFormatException extends Exception {
+  public HprofFormatException(String msg) {
+    super(msg);
+  }
+}
diff --git a/tools/ahat/src/heapdump/Instances.java b/tools/ahat/src/heapdump/Instances.java
new file mode 100644
index 0000000..0851446
--- /dev/null
+++ b/tools/ahat/src/heapdump/Instances.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.heapdump;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A collection of instances that can be searched for by id.
+ */
+class Instances<T extends AhatInstance> implements Iterable<T> {
+
+  private final List<T> mInstances;
+
+  /**
+   * Create a collection of instances that can be looked up by id.
+   * Note: this takes ownership of the given list of instances.
+   */
+  public Instances(List<T> instances) {
+    mInstances = instances;
+
+    // Sort the instances by id so we can use binary search to lookup
+    // instances by id.
+    instances.sort(new Comparator<AhatInstance>() {
+      @Override
+      public int compare(AhatInstance a, AhatInstance b) {
+        return Long.compare(a.getId(), b.getId());
+      }
+    });
+  }
+
+  /**
+   * Look up an instance by id.
+   * Returns null if no instance with the given id is found.
+   */
+  public T get(long id) {
+    // Binary search over the sorted instances.
+    int start = 0;
+    int end = mInstances.size();
+    while (start < end) {
+      int mid = start + ((end - start) / 2);
+      T midInst = mInstances.get(mid);
+      long midId = midInst.getId();
+      if (id == midId) {
+        return midInst;
+      } else if (id < midId) {
+        end = mid;
+      } else {
+        start = mid + 1;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public Iterator<T> iterator() {
+    return mInstances.iterator();
+  }
+}
+
diff --git a/tools/ahat/src/heapdump/Parser.java b/tools/ahat/src/heapdump/Parser.java
new file mode 100644
index 0000000..3d5f95f
--- /dev/null
+++ b/tools/ahat/src/heapdump/Parser.java
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.heapdump;
+
+import com.android.ahat.proguard.ProguardMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class Parser {
+  private static final int ID_SIZE = 4;
+
+  /**
+   * Parse the given heap dump using the given proguard map for deobfuscation.
+   * We make the following assumptions about valid heap dumps:
+   * Class serial numbers, stack frames, and stack traces
+   * individually satisfy the following:
+   *  - all elements are defined before they are referenced.
+   *  - ids are densely packed in some range [a, b] where a is not
+   *    necessarily 0.
+   *  - there are not more than 2^31 elements defined.
+   * All classes are defined via a LOAD CLASS record before the first heap
+   * dump segment.
+   * The ID size used in the heap dump is 4 bytes.
+   */
+  public static AhatSnapshot parseHeapDump(File hprof, ProguardMap map)
+    throws IOException, HprofFormatException {
+    return parseHeapDump(new HprofBuffer(hprof), map);
+  }
+
+  /**
+   * Parse a heap dump from a byte buffer.
+   */
+  public static AhatSnapshot parseHeapDump(ByteBuffer hprof, ProguardMap map)
+    throws IOException, HprofFormatException {
+    return parseHeapDump(new HprofBuffer(hprof), map);
+  }
+
+  private static AhatSnapshot parseHeapDump(HprofBuffer hprof, ProguardMap map)
+    throws IOException, HprofFormatException {
+    // Read, and mostly ignore, the hprof header info.
+    {
+      StringBuilder format = new StringBuilder();
+      int b;
+      while ((b = hprof.getU1()) != 0) {
+        format.append((char)b);
+      }
+
+      int idSize = hprof.getU4();
+      if (idSize != ID_SIZE) {
+        throw new HprofFormatException("Id size " + idSize + " not supported.");
+      }
+      int hightime = hprof.getU4();
+      int lowtime = hprof.getU4();
+    }
+
+    // First pass: Read through all the heap dump records. Construct the
+    // AhatInstances, initialize them as much as possible and save any
+    // additional temporary data we need to complete their initialization in
+    // the fixup pass.
+    Site rootSite = new Site("ROOT");
+    List<AhatInstance> instances = new ArrayList<AhatInstance>();
+    List<RootData> roots = new ArrayList<RootData>();
+    HeapList heaps = new HeapList();
+    {
+      // Note: Strings do not satisfy the DenseMap requirements on heap dumps
+      // from Android K.
+      UnDenseMap<String> strings = new UnDenseMap<String>("String");
+      DenseMap<ProguardMap.Frame> frames = new DenseMap<ProguardMap.Frame>("Stack Frame");
+      DenseMap<Site> sites = new DenseMap<Site>("Stack Trace");
+      DenseMap<String> classNamesBySerial = new DenseMap<String>("Class Serial Number");
+      AhatClassObj javaLangClass = null;
+      AhatClassObj[] primArrayClasses = new AhatClassObj[Type.values().length];
+      ArrayList<AhatClassObj> classes = new ArrayList<AhatClassObj>();
+      Instances<AhatClassObj> classById = null;
+
+      while (hprof.hasRemaining()) {
+        int tag = hprof.getU1();
+        int time = hprof.getU4();
+        int recordLength = hprof.getU4();
+        switch (tag) {
+          case 0x01: { // STRING
+            long id = hprof.getId();
+            byte[] bytes = new byte[recordLength - ID_SIZE];
+            hprof.getBytes(bytes);
+            String str = new String(bytes, StandardCharsets.UTF_8);
+            strings.put(id, str);
+            break;
+          }
+
+          case 0x02: { // LOAD CLASS
+            int classSerialNumber = hprof.getU4();
+            long objectId = hprof.getId();
+            int stackSerialNumber = hprof.getU4();
+            long classNameStringId = hprof.getId();
+            String obfClassName = strings.get(classNameStringId);
+            String clrClassName = map.getClassName(obfClassName);
+            AhatClassObj classObj = new AhatClassObj(objectId, clrClassName);
+            classNamesBySerial.put(classSerialNumber, clrClassName);
+            classes.add(classObj);
+
+            // Check whether this class is one of the special classes we are
+            // interested in, and if so, save it for later use.
+            if ("java.lang.Class".equals(clrClassName)) {
+              javaLangClass = classObj;
+            }
+
+            for (Type type : Type.values()) {
+              if (clrClassName.equals(type.name + "[]")) {
+                primArrayClasses[type.ordinal()] = classObj;
+              }
+            }
+            break;
+          }
+
+          case 0x04: { // STACK FRAME
+            long frameId = hprof.getId();
+            long methodNameStringId = hprof.getId();
+            long methodSignatureStringId = hprof.getId();
+            long methodFileNameStringId = hprof.getId();
+            int classSerialNumber = hprof.getU4();
+            int lineNumber = hprof.getU4();
+
+            ProguardMap.Frame frame = map.getFrame(
+                classNamesBySerial.get(classSerialNumber),
+                strings.get(methodNameStringId),
+                strings.get(methodSignatureStringId),
+                strings.get(methodFileNameStringId),
+                lineNumber);
+            frames.put(frameId, frame);
+            break;
+          }
+
+          case 0x05: { // STACK TRACE
+            int stackSerialNumber = hprof.getU4();
+            int threadSerialNumber = hprof.getU4();
+            int numFrames = hprof.getU4();
+            ProguardMap.Frame[] trace = new ProguardMap.Frame[numFrames];
+            for (int i = 0; i < numFrames; i++) {
+              long frameId = hprof.getId();
+              trace[i] = frames.get(frameId);
+            }
+            sites.put(stackSerialNumber, rootSite.getSite(trace));
+            break;
+          }
+
+          case 0x1C: { // HEAP DUMP SEGMENT
+            if (classById == null) {
+              classById = new Instances<AhatClassObj>(classes);
+            }
+            int subtag;
+            while (!isEndOfHeapDumpSegment(subtag = hprof.getU1())) {
+              switch (subtag) {
+                case 0x01: { // ROOT JNI GLOBAL
+                  long objectId = hprof.getId();
+                  long refId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.JNI_GLOBAL));
+                  break;
+                }
+
+                case 0x02: { // ROOT JNI LOCAL
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  int frameNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.JNI_LOCAL));
+                  break;
+                }
+
+                case 0x03: { // ROOT JAVA FRAME
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  int frameNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.JAVA_FRAME));
+                  break;
+                }
+
+                case 0x04: { // ROOT NATIVE STACK
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.NATIVE_STACK));
+                  break;
+                }
+
+                case 0x05: { // ROOT STICKY CLASS
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.STICKY_CLASS));
+                  break;
+                }
+
+                case 0x06: { // ROOT THREAD BLOCK
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.THREAD_BLOCK));
+                  break;
+                }
+
+                case 0x07: { // ROOT MONITOR USED
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.MONITOR));
+                  break;
+                }
+
+                case 0x08: { // ROOT THREAD OBJECT
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  int stackSerialNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.THREAD));
+                  break;
+                }
+
+                case 0x20: { // CLASS DUMP
+                  ClassObjData data = new ClassObjData();
+                  long objectId = hprof.getId();
+                  int stackSerialNumber = hprof.getU4();
+                  long superClassId = hprof.getId();
+                  data.classLoaderId = hprof.getId();
+                  long signersId = hprof.getId();
+                  long protectionId = hprof.getId();
+                  long reserved1 = hprof.getId();
+                  long reserved2 = hprof.getId();
+                  int instanceSize = hprof.getU4();
+                  int constantPoolSize = hprof.getU2();
+                  for (int i = 0; i < constantPoolSize; ++i) {
+                    int index = hprof.getU2();
+                    Type type = hprof.getType();
+                    hprof.skip(type.size);
+                  }
+                  int numStaticFields = hprof.getU2();
+                  data.staticFields = new FieldValue[numStaticFields];
+                  AhatClassObj obj = classById.get(objectId);
+                  String clrClassName = obj.getName();
+                  long staticFieldsSize = 0;
+                  for (int i = 0; i < numStaticFields; ++i) {
+                    String obfName = strings.get(hprof.getId());
+                    String clrName = map.getFieldName(clrClassName, obfName);
+                    Type type = hprof.getType();
+                    Value value = hprof.getDeferredValue(type);
+                    staticFieldsSize += type.size;
+                    data.staticFields[i] = new FieldValue(clrName, type, value);
+                  }
+                  AhatClassObj superClass = classById.get(superClassId);
+                  int numInstanceFields = hprof.getU2();
+                  Field[] ifields = new Field[numInstanceFields];
+                  for (int i = 0; i < numInstanceFields; ++i) {
+                    String name = map.getFieldName(obj.getName(), strings.get(hprof.getId()));
+                    ifields[i] = new Field(name, hprof.getType());
+                  }
+                  Site site = sites.get(stackSerialNumber);
+
+                  if (javaLangClass == null) {
+                    throw new HprofFormatException("No class definition found for java.lang.Class");
+                  }
+                  obj.initialize(heaps.getCurrentHeap(), site, javaLangClass);
+                  obj.initialize(superClass, instanceSize, ifields, staticFieldsSize);
+                  obj.setTemporaryUserData(data);
+                  break;
+                }
+
+                case 0x21: { // INSTANCE DUMP
+                  long objectId = hprof.getId();
+                  int stackSerialNumber = hprof.getU4();
+                  long classId = hprof.getId();
+                  int numBytes = hprof.getU4();
+                  ClassInstData data = new ClassInstData(hprof.tell());
+                  hprof.skip(numBytes);
+
+                  Site site = sites.get(stackSerialNumber);
+                  AhatClassObj classObj = classById.get(classId);
+                  AhatClassInstance obj = new AhatClassInstance(objectId);
+                  obj.initialize(heaps.getCurrentHeap(), site, classObj);
+                  obj.setTemporaryUserData(data);
+                  instances.add(obj);
+                  break;
+                }
+
+                case 0x22: { // OBJECT ARRAY DUMP
+                  long objectId = hprof.getId();
+                  int stackSerialNumber = hprof.getU4();
+                  int length = hprof.getU4();
+                  long classId = hprof.getId();
+                  ObjArrayData data = new ObjArrayData(length, hprof.tell());
+                  hprof.skip(length * ID_SIZE);
+
+                  Site site = sites.get(stackSerialNumber);
+                  AhatClassObj classObj = classById.get(classId);
+                  AhatArrayInstance obj = new AhatArrayInstance(objectId);
+                  obj.initialize(heaps.getCurrentHeap(), site, classObj);
+                  obj.setTemporaryUserData(data);
+                  instances.add(obj);
+                  break;
+                }
+
+                case 0x23: { // PRIMITIVE ARRAY DUMP
+                  long objectId = hprof.getId();
+                  int stackSerialNumber = hprof.getU4();
+                  int length = hprof.getU4();
+                  Type type = hprof.getPrimitiveType();
+                  Site site = sites.get(stackSerialNumber);
+
+                  AhatClassObj classObj = primArrayClasses[type.ordinal()];
+                  if (classObj == null) {
+                    throw new HprofFormatException(
+                        "No class definition found for " + type.name + "[]");
+                  }
+
+                  AhatArrayInstance obj = new AhatArrayInstance(objectId);
+                  obj.initialize(heaps.getCurrentHeap(), site, classObj);
+                  instances.add(obj);
+                  switch (type) {
+                    case BOOLEAN: {
+                      boolean[] data = new boolean[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getBool();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case CHAR: {
+                      char[] data = new char[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getChar();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case FLOAT: {
+                      float[] data = new float[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getFloat();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case DOUBLE: {
+                      double[] data = new double[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getDouble();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case BYTE: {
+                      byte[] data = new byte[length];
+                      hprof.getBytes(data);
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case SHORT: {
+                      short[] data = new short[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getShort();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case INT: {
+                      int[] data = new int[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getInt();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+
+                    case LONG: {
+                      long[] data = new long[length];
+                      for (int i = 0; i < length; ++i) {
+                        data[i] = hprof.getLong();
+                      }
+                      obj.initialize(data);
+                      break;
+                    }
+                  }
+                  break;
+                }
+
+                case 0x89: { // ROOT INTERNED STRING (ANDROID)
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.INTERNED_STRING));
+                  break;
+                }
+
+                case 0x8b: { // ROOT DEBUGGER (ANDROID)
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.DEBUGGER));
+                  break;
+                }
+
+                case 0x8d: { // ROOT VM INTERNAL (ANDROID)
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.VM_INTERNAL));
+                  break;
+                }
+
+                case 0x8e: { // ROOT JNI MONITOR (ANDROID)
+                  long objectId = hprof.getId();
+                  int threadSerialNumber = hprof.getU4();
+                  int frameNumber = hprof.getU4();
+                  roots.add(new RootData(objectId, RootType.JNI_MONITOR));
+                  break;
+                }
+
+                case 0xfe: { // HEAP DUMP INFO (ANDROID)
+                  int type = hprof.getU4();
+                  long stringId = hprof.getId();
+                  heaps.setCurrentHeap(strings.get(stringId));
+                  break;
+                }
+
+                case 0xff: { // ROOT UNKNOWN
+                  long objectId = hprof.getId();
+                  roots.add(new RootData(objectId, RootType.UNKNOWN));
+                  break;
+                }
+
+                default:
+                  throw new HprofFormatException(
+                      String.format("Unsupported heap dump sub tag 0x%02x", subtag));
+              }
+            }
+
+            // Reset the file pointer back because we read the first byte into
+            // the next record.
+            hprof.skip(-1);
+            break;
+          }
+
+          default:
+            // Ignore any other tags that we either don't know about or don't
+            // care about.
+            hprof.skip(recordLength);
+            break;
+        }
+      }
+
+      instances.addAll(classes);
+    }
+
+    // Sort roots and instances by id in preparation for the fixup pass.
+    Instances<AhatInstance> mInstances = new Instances<AhatInstance>(instances);
+    roots.sort(new Comparator<RootData>() {
+      @Override
+      public int compare(RootData a, RootData b) {
+        return Long.compare(a.id, b.id);
+      }
+    });
+    roots.add(null);
+
+    // Fixup pass: Label the root instances and fix up references to instances
+    // that we couldn't previously resolve.
+    SuperRoot superRoot = new SuperRoot();
+    {
+      Iterator<RootData> ri = roots.iterator();
+      RootData root = ri.next();
+      for (AhatInstance inst : mInstances) {
+        long id = inst.getId();
+
+        // Skip past any roots that don't have associated instances.
+        // It's not clear why there would be a root without an associated
+        // instance dump, but it does happen in practice, for example when
+        // taking heap dumps using the RI.
+        while (root != null && root.id < id) {
+          root = ri.next();
+        }
+
+        // Check if this instance is a root, and if so, update its root types.
+        if (root != null && root.id == id) {
+          superRoot.addRoot(inst);
+          while (root != null && root.id == id) {
+            inst.addRootType(root.type);
+            root = ri.next();
+          }
+        }
+
+        // Fixup the instance based on its type using the temporary data we
+        // saved during the first pass over the heap dump.
+        if (inst instanceof AhatClassInstance) {
+          ClassInstData data = (ClassInstData)inst.getTemporaryUserData();
+          inst.setTemporaryUserData(null);
+
+          // Compute the size of the fields array in advance to avoid
+          // extra allocations and copies that would come from using an array
+          // list to collect the field values.
+          int numFields = 0;
+          for (AhatClassObj cls = inst.getClassObj(); cls != null; cls = cls.getSuperClassObj()) {
+            numFields += cls.getInstanceFields().length;
+          }
+
+          Value[] fields = new Value[numFields];
+          int i = 0;
+          hprof.seek(data.position);
+          for (AhatClassObj cls = inst.getClassObj(); cls != null; cls = cls.getSuperClassObj()) {
+            for (Field field : cls.getInstanceFields()) {
+              fields[i++] = hprof.getValue(field.type, mInstances);
+            }
+          }
+          ((AhatClassInstance)inst).initialize(fields);
+        } else if (inst instanceof AhatClassObj) {
+          ClassObjData data = (ClassObjData)inst.getTemporaryUserData();
+          inst.setTemporaryUserData(null);
+          AhatInstance loader = mInstances.get(data.classLoaderId);
+          for (int i = 0; i < data.staticFields.length; ++i) {
+            FieldValue field = data.staticFields[i];
+            if (field.value instanceof DeferredInstanceValue) {
+              DeferredInstanceValue deferred = (DeferredInstanceValue)field.value;
+              data.staticFields[i] = new FieldValue(
+                  field.name, field.type, Value.pack(mInstances.get(deferred.getId())));
+            }
+          }
+          ((AhatClassObj)inst).initialize(loader, data.staticFields);
+        } else if (inst instanceof AhatArrayInstance && inst.getTemporaryUserData() != null) {
+          // TODO: Have specialized object array instance and check for that
+          // rather than checking for the presence of user data?
+          ObjArrayData data = (ObjArrayData)inst.getTemporaryUserData();
+          inst.setTemporaryUserData(null);
+          AhatInstance[] array = new AhatInstance[data.length];
+          hprof.seek(data.position);
+          for (int i = 0; i < data.length; i++) {
+            array[i] = mInstances.get(hprof.getId());
+          }
+          ((AhatArrayInstance)inst).initialize(array);
+        }
+      }
+    }
+
+    hprof = null;
+    roots = null;
+    return new AhatSnapshot(superRoot, mInstances, heaps.heaps, rootSite);
+  }
+
+  private static boolean isEndOfHeapDumpSegment(int subtag) {
+    return subtag == 0x1C || subtag == 0x2C;
+  }
+
+  private static class RootData {
+    public long id;
+    public RootType type;
+
+    public RootData(long id, RootType type) {
+      this.id = id;
+      this.type = type;
+    }
+  }
+
+  private static class ClassInstData {
+    // The byte position in the hprof file where instance field data starts.
+    public int position;
+
+    public ClassInstData(int position) {
+      this.position = position;
+    }
+  }
+
+  private static class ObjArrayData {
+    public int length;          // Number of array elements.
+    public int position;        // Position in hprof file containing element data.
+
+    public ObjArrayData(int length, int position) {
+      this.length = length;
+      this.position = position;
+    }
+  }
+
+  private static class ClassObjData {
+    public long classLoaderId;
+    public FieldValue[] staticFields; // Contains DeferredInstanceValues.
+  }
+
+  /**
+   * Dummy value representing a reference to an instance that has not yet been
+   * resolved.
+   * When first initializing class static fields, we don't yet know what kinds
+   * of objects Object references refer to. We use DeferredInstanceValue as
+   * a dummy kind of value to store the id of an object. In the fixup pass we
+   * resolve all the DeferredInstanceValues into their proper InstanceValues.
+   */
+  private static class DeferredInstanceValue extends Value {
+    private long mId;
+
+    public DeferredInstanceValue(long id) {
+      mId = id;
+    }
+
+    public long getId() {
+      return mId;
+    }
+
+    @Override
+    protected Type getType() {
+      return Type.OBJECT;
+    }
+
+    @Override
+    public String toString() {
+      return String.format("0x%08x", mId);
+    }
+
+    @Override public boolean equals(Object other) {
+      if (other instanceof DeferredInstanceValue) {
+        DeferredInstanceValue value = (DeferredInstanceValue)other;
+        return mId == value.mId;
+      }
+      return false;
+    }
+  }
+
+  /**
+   * A convenient abstraction for lazily building up the list of heaps seen in
+   * the heap dump.
+   */
+  private static class HeapList {
+    public List<AhatHeap> heaps = new ArrayList<AhatHeap>();
+    private AhatHeap current;
+
+    public AhatHeap getCurrentHeap() {
+      if (current == null) {
+        setCurrentHeap("default");
+      }
+      return current;
+    }
+
+    public void setCurrentHeap(String name) {
+      for (AhatHeap heap : heaps) {
+        if (name.equals(heap.getName())) {
+          current = heap;
+          return;
+        }
+      }
+
+      current = new AhatHeap(name, heaps.size());
+      heaps.add(current);
+    }
+  }
+
+  /**
+   * A mapping from id to elements, where certain conditions are
+   * satisfied. The conditions are:
+   *  - all elements are defined before they are referenced.
+   *  - ids are densely packed in some range [a, b] where a is not
+   *    necessarily 0.
+   *  - there are not more than 2^31 elements defined.
+   */
+  private static class DenseMap<T> {
+    private String mElementType;
+
+    // mValues behaves like a circular buffer.
+    // mKeyAt0 is the key corresponding to index 0 of mValues. Values with
+    // smaller keys will wrap around to the end of the mValues buffer. The
+    // buffer is expanded when it is no longer big enough to hold all the keys
+    // from mMinKey to mMaxKey.
+    private Object[] mValues;
+    private long mKeyAt0;
+    private long mMaxKey;
+    private long mMinKey;
+
+    /**
+     * Constructs a DenseMap.
+     * @param elementType Human readable name describing the type of
+     *                    elements for error message if the required
+     *                    conditions are found not to hold.
+     */
+    public DenseMap(String elementType) {
+      mElementType = elementType;
+    }
+
+    public void put(long key, T value) {
+      if (mValues == null) {
+        mValues = new Object[8];
+        mValues[0] = value;
+        mKeyAt0 = key;
+        mMaxKey = key;
+        mMinKey = key;
+        return;
+      }
+
+      long max = Math.max(mMaxKey, key);
+      long min = Math.min(mMinKey, key);
+      int count = (int)(max + 1 - min);
+      if (count > mValues.length) {
+        Object[] values = new Object[2 * count];
+
+        // Copy over the values into the newly allocated larger buffer. It is
+        // convenient to move the value with mMinKey to index 0 when we make
+        // the copy.
+        for (int i = 0; i < mValues.length; ++i) {
+          values[i] = mValues[indexOf(i + mMinKey)];
+        }
+        mValues = values;
+        mKeyAt0 = mMinKey;
+      }
+      mMinKey = min;
+      mMaxKey = max;
+      mValues[indexOf(key)] = value;
+    }
+
+    /**
+     * Returns the value for the given key.
+     * @throws HprofFormatException if there is no value with the key in the
+     *         given map.
+     */
+    public T get(long key) throws HprofFormatException {
+      T value = null;
+      if (mValues != null && key >= mMinKey && key <= mMaxKey) {
+        value = (T)mValues[indexOf(key)];
+      }
+
+      if (value == null) {
+        throw new HprofFormatException(String.format(
+              "%s with id 0x%x referenced before definition", mElementType, key));
+      }
+      return value;
+    }
+
+    private int indexOf(long key) {
+      return ((int)(key - mKeyAt0) + mValues.length) % mValues.length;
+    }
+  }
+
+  /**
+   * A mapping from id to elements, where we don't have nice conditions to
+   * work with.
+   */
+  private static class UnDenseMap<T> {
+    private String mElementType;
+    private Map<Long, T> mValues = new HashMap<Long, T>();
+
+    /**
+     * Constructs an UnDenseMap.
+     * @param elementType Human readable name describing the type of
+     *                    elements for error message if the required
+     *                    conditions are found not to hold.
+     */
+    public UnDenseMap(String elementType) {
+      mElementType = elementType;
+    }
+
+    public void put(long key, T value) {
+      mValues.put(key, value);
+    }
+
+    /**
+     * Returns the value for the given key.
+     * @throws HprofFormatException if there is no value with the key in the
+     *         given map.
+     */
+    public T get(long key) throws HprofFormatException {
+      T value = mValues.get(key);
+      if (value == null) {
+        throw new HprofFormatException(String.format(
+              "%s with id 0x%x referenced before definition", mElementType, key));
+      }
+      return value;
+    }
+  }
+
+  /**
+   * Wrapper around a ByteBuffer that presents a uniform interface for
+   * accessing data from an hprof file.
+   */
+  private static class HprofBuffer {
+    private ByteBuffer mBuffer;
+
+    public HprofBuffer(File path) throws IOException {
+      FileChannel channel = FileChannel.open(path.toPath(), StandardOpenOption.READ);
+      mBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
+      channel.close();
+    }
+
+    public HprofBuffer(ByteBuffer buffer) {
+      mBuffer = buffer;
+    }
+
+    public boolean hasRemaining() {
+      return mBuffer.hasRemaining();
+    }
+
+    /**
+     * Return the current absolution position in the file.
+     */
+    public int tell() {
+      return mBuffer.position();
+    }
+
+    /**
+     * Seek to the given absolution position in the file.
+     */
+    public void seek(int position) {
+      mBuffer.position(position);
+    }
+
+    /**
+     * Skip ahead in the file by the given delta bytes. Delta may be negative
+     * to skip backwards in the file.
+     */
+    public void skip(int delta) {
+      seek(tell() + delta);
+    }
+
+    public int getU1() {
+      return mBuffer.get() & 0xFF;
+    }
+
+    public int getU2() {
+      return mBuffer.getShort() & 0xFFFF;
+    }
+
+    public int getU4() {
+      return mBuffer.getInt();
+    }
+
+    public long getId() {
+      return mBuffer.getInt();
+    }
+
+    public boolean getBool() {
+      return mBuffer.get() != 0;
+    }
+
+    public char getChar() {
+      return mBuffer.getChar();
+    }
+
+    public float getFloat() {
+      return mBuffer.getFloat();
+    }
+
+    public double getDouble() {
+      return mBuffer.getDouble();
+    }
+
+    public byte getByte() {
+      return mBuffer.get();
+    }
+
+    public void getBytes(byte[] bytes) {
+      mBuffer.get(bytes);
+    }
+
+    public short getShort() {
+      return mBuffer.getShort();
+    }
+
+    public int getInt() {
+      return mBuffer.getInt();
+    }
+
+    public long getLong() {
+      return mBuffer.getLong();
+    }
+
+    private static Type[] TYPES = new Type[] {
+      null, null, Type.OBJECT, null,
+        Type.BOOLEAN, Type.CHAR, Type.FLOAT, Type.DOUBLE,
+        Type.BYTE, Type.SHORT, Type.INT, Type.LONG
+    };
+
+    public Type getType() throws HprofFormatException {
+      int id = getU1();
+      Type type = id < TYPES.length ? TYPES[id] : null;
+      if (type == null) {
+        throw new HprofFormatException("Invalid basic type id: " + id);
+      }
+      return type;
+    }
+
+    public Type getPrimitiveType() throws HprofFormatException {
+      Type type = getType();
+      if (type == Type.OBJECT) {
+        throw new HprofFormatException("Expected primitive type, but found type 'Object'");
+      }
+      return type;
+    }
+
+    /**
+     * Get a value from the hprof file, using the given instances map to
+     * convert instance ids to their corresponding AhatInstance objects.
+     */
+    public Value getValue(Type type, Instances instances) {
+      switch (type) {
+        case OBJECT:  return Value.pack(instances.get(getId()));
+        case BOOLEAN: return Value.pack(getBool());
+        case CHAR: return Value.pack(getChar());
+        case FLOAT: return Value.pack(getFloat());
+        case DOUBLE: return Value.pack(getDouble());
+        case BYTE: return Value.pack(getByte());
+        case SHORT: return Value.pack(getShort());
+        case INT: return Value.pack(getInt());
+        case LONG: return Value.pack(getLong());
+        default: throw new AssertionError("unsupported enum member");
+      }
+    }
+
+    /**
+     * Get a value from the hprof file. AhatInstance values are returned as
+     * DefferredInstanceValues rather than their corresponding AhatInstance
+     * objects.
+     */
+    public Value getDeferredValue(Type type) {
+      switch (type) {
+        case OBJECT: return new DeferredInstanceValue(getId());
+        case BOOLEAN: return Value.pack(getBool());
+        case CHAR: return Value.pack(getChar());
+        case FLOAT: return Value.pack(getFloat());
+        case DOUBLE: return Value.pack(getDouble());
+        case BYTE: return Value.pack(getByte());
+        case SHORT: return Value.pack(getShort());
+        case INT: return Value.pack(getInt());
+        case LONG: return Value.pack(getLong());
+        default: throw new AssertionError("unsupported enum member");
+      }
+    }
+  }
+}
diff --git a/tools/ahat/src/heapdump/Perflib.java b/tools/ahat/src/heapdump/Perflib.java
deleted file mode 100644
index d0264a3..0000000
--- a/tools/ahat/src/heapdump/Perflib.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ahat.heapdump;
-
-import com.android.tools.perflib.heap.ClassInstance;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Instance;
-import com.android.tools.perflib.heap.Snapshot;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Collection of utilities that may be suitable to have in perflib instead of
- * ahat.
- */
-public class Perflib {
-  /**
-   * Return a collection of instances in the given snapshot that are tied to
-   * registered native allocations and their corresponding registered native
-   * sizes.
-   */
-  public static Map<Instance, Long> getRegisteredNativeAllocations(Snapshot snapshot) {
-    Map<Instance, Long> allocs = new HashMap<Instance, Long>();
-    ClassObj cleanerClass = snapshot.findClass("sun.misc.Cleaner");
-    if (cleanerClass != null) {
-      for (Instance cleanerInst : cleanerClass.getInstancesList()) {
-        ClassInstance cleaner = (ClassInstance)cleanerInst;
-        Object referent = getField(cleaner, "referent");
-        if (referent instanceof Instance) {
-          Instance inst = (Instance)referent;
-          Object thunkValue = getField(cleaner, "thunk");
-          if (thunkValue instanceof ClassInstance) {
-            ClassInstance thunk = (ClassInstance)thunkValue;
-            ClassObj thunkClass = thunk.getClassObj();
-            String cleanerThunkClassName = "libcore.util.NativeAllocationRegistry$CleanerThunk";
-            if (thunkClass != null && cleanerThunkClassName.equals(thunkClass.getClassName())) {
-              for (ClassInstance.FieldValue thunkField : thunk.getValues()) {
-                if (thunkField.getValue() instanceof ClassInstance) {
-                  ClassInstance registry = (ClassInstance)thunkField.getValue();
-                  ClassObj registryClass = registry.getClassObj();
-                  String registryClassName = "libcore.util.NativeAllocationRegistry";
-                  if (registryClass != null
-                      && registryClassName.equals(registryClass.getClassName())) {
-                    Object sizeValue = getField(registry, "size");
-                    if (sizeValue instanceof Long) {
-                      long size = (Long)sizeValue;
-                      if (size > 0) {
-                        Long old = allocs.get(inst);
-                        allocs.put(inst, old == null ? size : old + size);
-                      }
-                    }
-                    break;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-    return allocs;
-  }
-
-  /**
-   * Helper function to read a single field from a perflib class instance.
-   * Returns null if field not found. Note there is no way to distinguish
-   * between field not found an a field value of null.
-   */
-  private static Object getField(ClassInstance cls, String name) {
-    for (ClassInstance.FieldValue field : cls.getValues()) {
-      if (name.equals(field.getField().getName())) {
-        return field.getValue();
-      }
-    }
-    return null;
-  }
-}
diff --git a/tools/ahat/src/heapdump/RootType.java b/tools/ahat/src/heapdump/RootType.java
new file mode 100644
index 0000000..7165b83
--- /dev/null
+++ b/tools/ahat/src/heapdump/RootType.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.heapdump;
+
+public enum RootType {
+  JNI_GLOBAL      (1 <<  0),
+  JNI_LOCAL       (1 <<  1),
+  JAVA_FRAME      (1 <<  2),
+  NATIVE_STACK    (1 <<  3),
+  STICKY_CLASS    (1 <<  4),
+  THREAD_BLOCK    (1 <<  5),
+  MONITOR         (1 <<  6),
+  THREAD          (1 <<  7),
+  INTERNED_STRING (1 <<  8),
+  DEBUGGER        (1 <<  9),
+  VM_INTERNAL     (1 << 10),
+  UNKNOWN         (1 << 11),
+  JNI_MONITOR     (1 << 12);
+
+  public final int mask;
+
+  RootType(int mask) {
+    this.mask = mask;
+  }
+}
diff --git a/tools/ahat/src/heapdump/Site.java b/tools/ahat/src/heapdump/Site.java
index 82931f0..821493f 100644
--- a/tools/ahat/src/heapdump/Site.java
+++ b/tools/ahat/src/heapdump/Site.java
@@ -16,7 +16,7 @@
 
 package com.android.ahat.heapdump;
 
-import com.android.tools.perflib.heap.StackFrame;
+import com.android.ahat.proguard.ProguardMap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -127,27 +127,27 @@
    *                 inner-most frame. May be null, in which case this site is
    *                 returned.
    */
-  Site getSite(StackFrame frames[]) {
+  Site getSite(ProguardMap.Frame[] frames) {
     return frames == null ? this : getSite(this, frames);
   }
 
-  private static Site getSite(Site site, StackFrame frames[]) {
+  private static Site getSite(Site site, ProguardMap.Frame[] frames) {
     for (int s = frames.length - 1; s >= 0; --s) {
-      StackFrame frame = frames[s];
+      ProguardMap.Frame frame = frames[s];
       Site child = null;
       for (int i = 0; i < site.mChildren.size(); i++) {
         Site curr = site.mChildren.get(i);
-        if (curr.mLineNumber == frame.getLineNumber()
-            && curr.mMethodName.equals(frame.getMethodName())
-            && curr.mSignature.equals(frame.getSignature())
-            && curr.mFilename.equals(frame.getFilename())) {
+        if (curr.mLineNumber == frame.line
+            && curr.mMethodName.equals(frame.method)
+            && curr.mSignature.equals(frame.signature)
+            && curr.mFilename.equals(frame.filename)) {
           child = curr;
           break;
         }
       }
       if (child == null) {
-        child = new Site(site, frame.getMethodName(), frame.getSignature(),
-            frame.getFilename(), frame.getLineNumber());
+        child = new Site(site, frame.method, frame.signature,
+            frame.filename, frame.line);
         site.mChildren.add(child);
       }
       site = child;
diff --git a/tools/ahat/src/heapdump/SuperRoot.java b/tools/ahat/src/heapdump/SuperRoot.java
index d377113..a2adbd2 100644
--- a/tools/ahat/src/heapdump/SuperRoot.java
+++ b/tools/ahat/src/heapdump/SuperRoot.java
@@ -34,6 +34,11 @@
   }
 
   @Override
+  protected long getExtraJavaSize() {
+    return 0;
+  }
+
+  @Override
   public String toString() {
     return "SUPER_ROOT";
   }
diff --git a/tools/ahat/src/heapdump/Type.java b/tools/ahat/src/heapdump/Type.java
new file mode 100644
index 0000000..726bc47
--- /dev/null
+++ b/tools/ahat/src/heapdump/Type.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.heapdump;
+
+public enum Type {
+  OBJECT("Object", 4),
+  BOOLEAN("boolean", 1),
+  CHAR("char", 2),
+  FLOAT("float", 4),
+  DOUBLE("double", 8),
+  BYTE("byte", 1),
+  SHORT("short", 2),
+  INT("int", 4),
+  LONG("long", 8);
+
+  public final String name;
+  public final int size;
+
+  Type(String name, int size) {
+    this.name = name;
+    this.size = size;
+  }
+
+  @Override
+  public String toString() {
+    return name;
+  }
+}
diff --git a/tools/ahat/src/heapdump/Value.java b/tools/ahat/src/heapdump/Value.java
index 7f86c01..01fd250 100644
--- a/tools/ahat/src/heapdump/Value.java
+++ b/tools/ahat/src/heapdump/Value.java
@@ -25,37 +25,6 @@
     return value == null ? null : new InstanceValue(value);
   }
 
-  /**
-   * Constructs a value from a generic Java Object.
-   * The Object must either be a boxed Java primitive type or a subclass of
-   * AhatInstance. The object must not be null.
-   */
-  public static Value pack(Object object) {
-    if (object == null) {
-      return null;
-    } else if (object instanceof AhatInstance) {
-      return Value.pack((AhatInstance)object);
-    } else if (object instanceof Boolean) {
-      return Value.pack(((Boolean)object).booleanValue());
-    } else if (object instanceof Character) {
-      return Value.pack(((Character)object).charValue());
-    } else if (object instanceof Float) {
-      return Value.pack(((Float)object).floatValue());
-    } else if (object instanceof Double) {
-      return Value.pack(((Double)object).doubleValue());
-    } else if (object instanceof Byte) {
-      return Value.pack(((Byte)object).byteValue());
-    } else if (object instanceof Short) {
-      return Value.pack(((Short)object).shortValue());
-    } else if (object instanceof Integer) {
-      return Value.pack(((Integer)object).intValue());
-    } else if (object instanceof Long) {
-      return Value.pack(((Long)object).longValue());
-    }
-    throw new IllegalArgumentException(
-        "AhatInstance or primitive type required, but got: " + object.toString());
-  }
-
   public static Value pack(boolean value) {
     return new BooleanValue(value);
   }
@@ -89,6 +58,18 @@
   }
 
   /**
+   * Return the type of the given value.
+   */
+  public static Type getType(Value value) {
+    return value == null ? Type.OBJECT : value.getType();
+  }
+
+  /**
+   * Return the type of the given value.
+   */
+  protected abstract Type getType();
+
+  /**
    * Returns true if the Value is an AhatInstance, as opposed to a Java
    * primitive value.
    */
@@ -172,6 +153,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.BOOLEAN;
+    }
+
+    @Override
     public String toString() {
       return Boolean.toString(mBool);
     }
@@ -198,6 +184,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.BYTE;
+    }
+
+    @Override
     public String toString() {
       return Byte.toString(mByte);
     }
@@ -224,6 +215,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.CHAR;
+    }
+
+    @Override
     public String toString() {
       return Character.toString(mChar);
     }
@@ -245,6 +241,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.DOUBLE;
+    }
+
+    @Override
     public String toString() {
       return Double.toString(mDouble);
     }
@@ -266,6 +267,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.FLOAT;
+    }
+
+    @Override
     public String toString() {
       return Float.toString(mFloat);
     }
@@ -298,6 +304,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.OBJECT;
+    }
+
+    @Override
     public String toString() {
       return mInstance.toString();
     }
@@ -334,6 +345,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.INT;
+    }
+
+    @Override
     public String toString() {
       return Integer.toString(mInt);
     }
@@ -365,6 +381,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.LONG;
+    }
+
+    @Override
     public String toString() {
       return Long.toString(mLong);
     }
@@ -386,6 +407,11 @@
     }
 
     @Override
+    protected Type getType() {
+      return Type.SHORT;
+    }
+
+    @Override
     public String toString() {
       return Short.toString(mShort);
     }
diff --git a/tools/ahat/src/proguard/ProguardMap.java b/tools/ahat/src/proguard/ProguardMap.java
new file mode 100644
index 0000000..50c110a
--- /dev/null
+++ b/tools/ahat/src/proguard/ProguardMap.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.proguard;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+
+// Class used to deobfuscate classes, fields, and stack frames.
+public class ProguardMap {
+
+  private static final String ARRAY_SYMBOL = "[]";
+
+  private static class FrameData {
+    public FrameData(String clearMethodName, int lineDelta) {
+      this.clearMethodName = clearMethodName;
+      this.lineDelta = lineDelta;
+    }
+
+    public final String clearMethodName;
+    public final int lineDelta;   // lineDelta = obfuscatedLine - clearLine
+  }
+
+  private static class ClassData {
+    private final String mClearName;
+
+    // Mapping from obfuscated field name to clear field name.
+    private final Map<String, String> mFields = new HashMap<String, String>();
+
+    // obfuscatedMethodName + clearSignature -> FrameData
+    private final Map<String, FrameData> mFrames = new HashMap<String, FrameData>();
+
+    // Constructs a ClassData object for a class with the given clear name.
+    public ClassData(String clearName) {
+      mClearName = clearName;
+    }
+
+    // Returns the clear name of the class.
+    public String getClearName() {
+      return mClearName;
+    }
+
+    public void addField(String obfuscatedName, String clearName) {
+      mFields.put(obfuscatedName, clearName);
+    }
+
+    // Get the clear name for the field in this class with the given
+    // obfuscated name. Returns the original obfuscated name if a clear
+    // name for the field could not be determined.
+    // TODO: Do we need to take into account the type of the field to
+    // propery determine the clear name?
+    public String getField(String obfuscatedName) {
+      String clearField = mFields.get(obfuscatedName);
+      return clearField == null ? obfuscatedName : clearField;
+    }
+
+    // TODO: Does this properly interpret the meaning of line numbers? Is
+    // it possible to have multiple frame entries for the same method
+    // name and signature that differ only by line ranges?
+    public void addFrame(String obfuscatedMethodName, String clearMethodName,
+        String clearSignature, int obfuscatedLine, int clearLine) {
+      String key = obfuscatedMethodName + clearSignature;
+      mFrames.put(key, new FrameData(clearMethodName, obfuscatedLine - clearLine));
+    }
+
+    public Frame getFrame(String clearClassName, String obfuscatedMethodName,
+        String clearSignature, String obfuscatedFilename, int obfuscatedLine) {
+      String key = obfuscatedMethodName + clearSignature;
+      FrameData frame = mFrames.get(key);
+      if (frame == null) {
+        return new Frame(obfuscatedMethodName, clearSignature,
+            obfuscatedFilename, obfuscatedLine);
+      }
+      return new Frame(frame.clearMethodName, clearSignature,
+          getFileName(clearClassName, frame.clearMethodName),
+          obfuscatedLine - frame.lineDelta);
+    }
+  }
+
+  private Map<String, ClassData> mClassesFromClearName = new HashMap<String, ClassData>();
+  private Map<String, ClassData> mClassesFromObfuscatedName = new HashMap<String, ClassData>();
+
+  public static class Frame {
+    public Frame(String method, String signature, String filename, int line) {
+      this.method = method;
+      this.signature = signature;
+      this.filename = filename;
+      this.line = line;
+    }
+
+    public final String method;
+    public final String signature;
+    public final String filename;
+    public final int line;
+  }
+
+  private static void parseException(String msg) throws ParseException {
+    throw new ParseException(msg, 0);
+  }
+
+  // Read in proguard mapping information from the given file.
+  public void readFromFile(File mapFile)
+    throws FileNotFoundException, IOException, ParseException {
+    readFromReader(new FileReader(mapFile));
+  }
+
+  // Read in proguard mapping information from the given Reader.
+  public void readFromReader(Reader mapReader) throws IOException, ParseException {
+    BufferedReader reader = new BufferedReader(mapReader);
+    String line = reader.readLine();
+    while (line != null) {
+      // Class lines are of the form:
+      //   'clear.class.name -> obfuscated_class_name:'
+      int sep = line.indexOf(" -> ");
+      if (sep == -1 || sep + 5 >= line.length()) {
+        parseException("Error parsing class line: '" + line + "'");
+      }
+      String clearClassName = line.substring(0, sep);
+      String obfuscatedClassName = line.substring(sep + 4, line.length() - 1);
+
+      ClassData classData = new ClassData(clearClassName);
+      mClassesFromClearName.put(clearClassName, classData);
+      mClassesFromObfuscatedName.put(obfuscatedClassName, classData);
+
+      // After the class line comes zero or more field/method lines of the form:
+      //   '    type clearName -> obfuscatedName'
+      line = reader.readLine();
+      while (line != null && line.startsWith("    ")) {
+        String trimmed = line.trim();
+        int ws = trimmed.indexOf(' ');
+        sep = trimmed.indexOf(" -> ");
+        if (ws == -1 || sep == -1) {
+          parseException("Error parse field/method line: '" + line + "'");
+        }
+
+        String type = trimmed.substring(0, ws);
+        String clearName = trimmed.substring(ws + 1, sep);
+        String obfuscatedName = trimmed.substring(sep + 4, trimmed.length());
+
+        // If the clearName contains '(', then this is for a method instead of a
+        // field.
+        if (clearName.indexOf('(') == -1) {
+          classData.addField(obfuscatedName, clearName);
+        } else {
+          // For methods, the type is of the form: [#:[#:]]<returnType>
+          int obfuscatedLine = 0;
+          int colon = type.indexOf(':');
+          if (colon != -1) {
+            obfuscatedLine = Integer.parseInt(type.substring(0, colon));
+            type = type.substring(colon + 1);
+          }
+          colon = type.indexOf(':');
+          if (colon != -1) {
+            type = type.substring(colon + 1);
+          }
+
+          // For methods, the clearName is of the form: <clearName><sig>[:#[:#]]
+          int op = clearName.indexOf('(');
+          int cp = clearName.indexOf(')');
+          if (op == -1 || cp == -1) {
+            parseException("Error parse method line: '" + line + "'");
+          }
+
+          String sig = clearName.substring(op, cp + 1);
+
+          int clearLine = obfuscatedLine;
+          colon = clearName.lastIndexOf(':');
+          if (colon != -1) {
+            clearLine = Integer.parseInt(clearName.substring(colon + 1));
+            clearName = clearName.substring(0, colon);
+          }
+
+          colon = clearName.lastIndexOf(':');
+          if (colon != -1) {
+            clearLine = Integer.parseInt(clearName.substring(colon + 1));
+            clearName = clearName.substring(0, colon);
+          }
+
+          clearName = clearName.substring(0, op);
+
+          String clearSig = fromProguardSignature(sig + type);
+          classData.addFrame(obfuscatedName, clearName, clearSig,
+              obfuscatedLine, clearLine);
+        }
+
+        line = reader.readLine();
+      }
+    }
+    reader.close();
+  }
+
+  // Returns the deobfuscated version of the given class name. If no
+  // deobfuscated version is known, the original string is returned.
+  public String getClassName(String obfuscatedClassName) {
+    // Class names for arrays may have trailing [] that need to be
+    // stripped before doing the lookup.
+    String baseName = obfuscatedClassName;
+    String arraySuffix = "";
+    while (baseName.endsWith(ARRAY_SYMBOL)) {
+      arraySuffix += ARRAY_SYMBOL;
+      baseName = baseName.substring(0, baseName.length() - ARRAY_SYMBOL.length());
+    }
+
+    ClassData classData = mClassesFromObfuscatedName.get(baseName);
+    String clearBaseName = classData == null ? baseName : classData.getClearName();
+    return clearBaseName + arraySuffix;
+  }
+
+  // Returns the deobfuscated version of the given field name for the given
+  // (clear) class name. If no deobfuscated version is known, the original
+  // string is returned.
+  public String getFieldName(String clearClass, String obfuscatedField) {
+    ClassData classData = mClassesFromClearName.get(clearClass);
+    if (classData == null) {
+      return obfuscatedField;
+    }
+    return classData.getField(obfuscatedField);
+  }
+
+  // Returns the deobfuscated frame for the given obfuscated frame and (clear)
+  // class name. As much of the frame is deobfuscated as can be.
+  public Frame getFrame(String clearClassName, String obfuscatedMethodName,
+      String obfuscatedSignature, String obfuscatedFilename, int obfuscatedLine) {
+    String clearSignature = getSignature(obfuscatedSignature);
+    ClassData classData = mClassesFromClearName.get(clearClassName);
+    if (classData == null) {
+      return new Frame(obfuscatedMethodName, clearSignature,
+          obfuscatedFilename, obfuscatedLine);
+    }
+    return classData.getFrame(clearClassName, obfuscatedMethodName, clearSignature,
+        obfuscatedFilename, obfuscatedLine);
+  }
+
+  // Converts a proguard-formatted method signature into a Java formatted
+  // method signature.
+  private static String fromProguardSignature(String sig) throws ParseException {
+    if (sig.startsWith("(")) {
+      int end = sig.indexOf(')');
+      if (end == -1) {
+        parseException("Error parsing signature: " + sig);
+      }
+
+      StringBuilder converted = new StringBuilder();
+      converted.append('(');
+      if (end > 1) {
+        for (String arg : sig.substring(1, end).split(",")) {
+          converted.append(fromProguardSignature(arg));
+        }
+      }
+      converted.append(')');
+      converted.append(fromProguardSignature(sig.substring(end + 1)));
+      return converted.toString();
+    } else if (sig.endsWith(ARRAY_SYMBOL)) {
+      return "[" + fromProguardSignature(sig.substring(0, sig.length() - 2));
+    } else if (sig.equals("boolean")) {
+      return "Z";
+    } else if (sig.equals("byte")) {
+      return "B";
+    } else if (sig.equals("char")) {
+      return "C";
+    } else if (sig.equals("short")) {
+      return "S";
+    } else if (sig.equals("int")) {
+      return "I";
+    } else if (sig.equals("long")) {
+      return "J";
+    } else if (sig.equals("float")) {
+      return "F";
+    } else if (sig.equals("double")) {
+      return "D";
+    } else if (sig.equals("void")) {
+      return "V";
+    } else {
+      return "L" + sig.replace('.', '/') + ";";
+    }
+  }
+
+  // Return a clear signature for the given obfuscated signature.
+  private String getSignature(String obfuscatedSig) {
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < obfuscatedSig.length(); i++) {
+      if (obfuscatedSig.charAt(i) == 'L') {
+        int e = obfuscatedSig.indexOf(';', i);
+        builder.append('L');
+        String cls = obfuscatedSig.substring(i + 1, e).replace('/', '.');
+        builder.append(getClassName(cls).replace('.', '/'));
+        builder.append(';');
+        i = e;
+      } else {
+        builder.append(obfuscatedSig.charAt(i));
+      }
+    }
+    return builder.toString();
+  }
+
+  // Return a file name for the given clear class name and method.
+  private static String getFileName(String clearClass, String method) {
+    int dot = method.lastIndexOf('.');
+    if (dot != -1) {
+      clearClass = method.substring(0, dot);
+    }
+
+    String filename = clearClass;
+    dot = filename.lastIndexOf('.');
+    if (dot != -1) {
+      filename = filename.substring(dot + 1);
+    }
+
+    int dollar = filename.indexOf('$');
+    if (dollar != -1) {
+      filename = filename.substring(0, dollar);
+    }
+    return filename + ".java";
+  }
+}
diff --git a/tools/ahat/test-dump/L.hprof b/tools/ahat/test-dump/L.hprof
new file mode 100644
index 0000000..cf82557
--- /dev/null
+++ b/tools/ahat/test-dump/L.hprof
Binary files differ
diff --git a/tools/ahat/test-dump/O.hprof b/tools/ahat/test-dump/O.hprof
new file mode 100644
index 0000000..d474c6c
--- /dev/null
+++ b/tools/ahat/test-dump/O.hprof
Binary files differ
diff --git a/tools/ahat/test-dump/README.txt b/tools/ahat/test-dump/README.txt
new file mode 100644
index 0000000..344271c
--- /dev/null
+++ b/tools/ahat/test-dump/README.txt
@@ -0,0 +1,5 @@
+
+Main.java - A program used to generate a heap dump used for tests.
+L.hprof - A version of the test dump generated on Android L.
+O.hprof - A version of the test dump generated on Android O.
+RI.hprof - A version of the test dump generated on the reference implementation.
diff --git a/tools/ahat/test-dump/RI.hprof b/tools/ahat/test-dump/RI.hprof
new file mode 100644
index 0000000..9482542
--- /dev/null
+++ b/tools/ahat/test-dump/RI.hprof
Binary files differ
diff --git a/tools/ahat/test/DiffFieldsTest.java b/tools/ahat/test/DiffFieldsTest.java
index 7dc519d..1939975 100644
--- a/tools/ahat/test/DiffFieldsTest.java
+++ b/tools/ahat/test/DiffFieldsTest.java
@@ -19,6 +19,7 @@
 import com.android.ahat.heapdump.DiffFields;
 import com.android.ahat.heapdump.DiffedFieldValue;
 import com.android.ahat.heapdump.FieldValue;
+import com.android.ahat.heapdump.Type;
 import com.android.ahat.heapdump.Value;
 import java.util.ArrayList;
 import java.util.List;
@@ -28,14 +29,25 @@
 import static org.junit.Assert.assertNull;
 
 public class DiffFieldsTest {
+  // Give more convenient abstract names for different types.
+  private static final Type t0 = Type.OBJECT;
+  private static final Type t1 = Type.BOOLEAN;
+  private static final Type t2 = Type.CHAR;
+  private static final Type t3 = Type.FLOAT;
+  private static final Type t4 = Type.DOUBLE;
+  private static final Type t5 = Type.BYTE;
+  private static final Type t6 = Type.SHORT;
+  private static final Type t7 = Type.INT;
+  private static final Type t8 = Type.LONG;
+
   @Test
   public void normalMatchedDiffedFieldValues() {
-    FieldValue normal1 = new FieldValue("name", "type", Value.pack(1));
-    FieldValue normal2 = new FieldValue("name", "type", Value.pack(2));
+    FieldValue normal1 = new FieldValue("name", t0, Value.pack(1));
+    FieldValue normal2 = new FieldValue("name", t0, Value.pack(2));
 
     DiffedFieldValue x = DiffedFieldValue.matched(normal1, normal2);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertEquals(Value.pack(1), x.current);
     assertEquals(Value.pack(2), x.baseline);
     assertEquals(DiffedFieldValue.Status.MATCHED, x.status);
@@ -43,19 +55,19 @@
 
   @Test
   public void nulledMatchedDiffedFieldValues() {
-    FieldValue normal = new FieldValue("name", "type", Value.pack(1));
-    FieldValue nulled = new FieldValue("name", "type", null);
+    FieldValue normal = new FieldValue("name", t0, Value.pack(1));
+    FieldValue nulled = new FieldValue("name", t0, null);
 
     DiffedFieldValue x = DiffedFieldValue.matched(normal, nulled);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertEquals(Value.pack(1), x.current);
     assertNull(x.baseline);
     assertEquals(DiffedFieldValue.Status.MATCHED, x.status);
 
     DiffedFieldValue y = DiffedFieldValue.matched(nulled, normal);
     assertEquals("name", y.name);
-    assertEquals("type", y.type);
+    assertEquals(t0, y.type);
     assertNull(y.current);
     assertEquals(Value.pack(1), y.baseline);
     assertEquals(DiffedFieldValue.Status.MATCHED, y.status);
@@ -63,44 +75,44 @@
 
   @Test
   public void normalAddedDiffedFieldValues() {
-    FieldValue normal = new FieldValue("name", "type", Value.pack(1));
+    FieldValue normal = new FieldValue("name", t0, Value.pack(1));
 
     DiffedFieldValue x = DiffedFieldValue.added(normal);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertEquals(Value.pack(1), x.current);
     assertEquals(DiffedFieldValue.Status.ADDED, x.status);
   }
 
   @Test
   public void nulledAddedDiffedFieldValues() {
-    FieldValue nulled = new FieldValue("name", "type", null);
+    FieldValue nulled = new FieldValue("name", t0, null);
 
     DiffedFieldValue x = DiffedFieldValue.added(nulled);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertNull(x.current);
     assertEquals(DiffedFieldValue.Status.ADDED, x.status);
   }
 
   @Test
   public void normalDeletedDiffedFieldValues() {
-    FieldValue normal = new FieldValue("name", "type", Value.pack(1));
+    FieldValue normal = new FieldValue("name", t0, Value.pack(1));
 
     DiffedFieldValue x = DiffedFieldValue.deleted(normal);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertEquals(Value.pack(1), x.baseline);
     assertEquals(DiffedFieldValue.Status.DELETED, x.status);
   }
 
   @Test
   public void nulledDeletedDiffedFieldValues() {
-    FieldValue nulled = new FieldValue("name", "type", null);
+    FieldValue nulled = new FieldValue("name", t0, null);
 
     DiffedFieldValue x = DiffedFieldValue.deleted(nulled);
     assertEquals("name", x.name);
-    assertEquals("type", x.type);
+    assertEquals(t0, x.type);
     assertNull(x.baseline);
     assertEquals(DiffedFieldValue.Status.DELETED, x.status);
   }
@@ -108,21 +120,21 @@
   @Test
   public void basicDiff() {
     List<FieldValue> a = new ArrayList<FieldValue>();
-    a.add(new FieldValue("n0", "t0", null));
-    a.add(new FieldValue("n2", "t2", null));
-    a.add(new FieldValue("n3", "t3", null));
-    a.add(new FieldValue("n4", "t4", null));
-    a.add(new FieldValue("n5", "t5", null));
-    a.add(new FieldValue("n6", "t6", null));
+    a.add(new FieldValue("n0", t0, null));
+    a.add(new FieldValue("n2", t2, null));
+    a.add(new FieldValue("n3", t3, null));
+    a.add(new FieldValue("n4", t4, null));
+    a.add(new FieldValue("n5", t5, null));
+    a.add(new FieldValue("n6", t6, null));
 
     List<FieldValue> b = new ArrayList<FieldValue>();
-    b.add(new FieldValue("n0", "t0", null));
-    b.add(new FieldValue("n1", "t1", null));
-    b.add(new FieldValue("n2", "t2", null));
-    b.add(new FieldValue("n3", "t3", null));
-    b.add(new FieldValue("n5", "t5", null));
-    b.add(new FieldValue("n6", "t6", null));
-    b.add(new FieldValue("n7", "t7", null));
+    b.add(new FieldValue("n0", t0, null));
+    b.add(new FieldValue("n1", t1, null));
+    b.add(new FieldValue("n2", t2, null));
+    b.add(new FieldValue("n3", t3, null));
+    b.add(new FieldValue("n5", t5, null));
+    b.add(new FieldValue("n6", t6, null));
+    b.add(new FieldValue("n7", t7, null));
 
     // Note: The expected result makes assumptions about the implementation of
     // field diff to match the order of the returned fields. If the
@@ -145,22 +157,22 @@
   @Test
   public void reorderedDiff() {
     List<FieldValue> a = new ArrayList<FieldValue>();
-    a.add(new FieldValue("n0", "t0", null));
-    a.add(new FieldValue("n1", "t1", null));
-    a.add(new FieldValue("n2", "t2", null));
-    a.add(new FieldValue("n3", "t3", null));
-    a.add(new FieldValue("n4", "t4", null));
-    a.add(new FieldValue("n5", "t5", null));
-    a.add(new FieldValue("n6", "t6", null));
+    a.add(new FieldValue("n0", t0, null));
+    a.add(new FieldValue("n1", t1, null));
+    a.add(new FieldValue("n2", t2, null));
+    a.add(new FieldValue("n3", t3, null));
+    a.add(new FieldValue("n4", t4, null));
+    a.add(new FieldValue("n5", t5, null));
+    a.add(new FieldValue("n6", t6, null));
 
     List<FieldValue> b = new ArrayList<FieldValue>();
-    b.add(new FieldValue("n4", "t4", null));
-    b.add(new FieldValue("n1", "t1", null));
-    b.add(new FieldValue("n3", "t3", null));
-    b.add(new FieldValue("n0", "t0", null));
-    b.add(new FieldValue("n5", "t5", null));
-    b.add(new FieldValue("n2", "t2", null));
-    b.add(new FieldValue("n6", "t6", null));
+    b.add(new FieldValue("n4", t4, null));
+    b.add(new FieldValue("n1", t1, null));
+    b.add(new FieldValue("n3", t3, null));
+    b.add(new FieldValue("n0", t0, null));
+    b.add(new FieldValue("n5", t5, null));
+    b.add(new FieldValue("n2", t2, null));
+    b.add(new FieldValue("n6", t6, null));
 
     // Note: The expected result makes assumptions about the implementation of
     // field diff to match the order of the returned fields. If the
diff --git a/tools/ahat/test/DiffTest.java b/tools/ahat/test/DiffTest.java
index d0349fd..585f29a 100644
--- a/tools/ahat/test/DiffTest.java
+++ b/tools/ahat/test/DiffTest.java
@@ -18,26 +18,7 @@
 
 import com.android.ahat.heapdump.AhatHeap;
 import com.android.ahat.heapdump.AhatInstance;
-import com.android.ahat.heapdump.AhatSnapshot;
-import com.android.ahat.heapdump.Diff;
-import com.android.tools.perflib.heap.hprof.HprofClassDump;
-import com.android.tools.perflib.heap.hprof.HprofConstant;
-import com.android.tools.perflib.heap.hprof.HprofDumpRecord;
-import com.android.tools.perflib.heap.hprof.HprofHeapDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceField;
-import com.android.tools.perflib.heap.hprof.HprofLoadClass;
-import com.android.tools.perflib.heap.hprof.HprofPrimitiveArrayDump;
-import com.android.tools.perflib.heap.hprof.HprofRecord;
-import com.android.tools.perflib.heap.hprof.HprofRootDebugger;
-import com.android.tools.perflib.heap.hprof.HprofStaticField;
-import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
-import com.android.tools.perflib.heap.hprof.HprofType;
-import com.google.common.io.ByteArrayDataOutput;
-import com.google.common.io.ByteStreams;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -93,39 +74,9 @@
   }
 
   @Test
-  public void nullClassObj() throws IOException {
-    // Set up a heap dump that has a null classObj.
-    // The heap dump is derived from the InstanceTest.asStringEmbedded test.
-    HprofStringBuilder strings = new HprofStringBuilder(0);
-    List<HprofRecord> records = new ArrayList<HprofRecord>();
-    List<HprofDumpRecord> dump = new ArrayList<HprofDumpRecord>();
-
-    final int stringClassObjectId = 1;
-    records.add(new HprofLoadClass(0, 0, stringClassObjectId, 0, strings.get("java.lang.String")));
-    dump.add(new HprofClassDump(stringClassObjectId, 0, 0, 0, 0, 0, 0, 0, 0,
-          new HprofConstant[0], new HprofStaticField[0],
-          new HprofInstanceField[]{
-            new HprofInstanceField(strings.get("count"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("hashCode"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("offset"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("value"), HprofType.TYPE_OBJECT)}));
-
-    dump.add(new HprofPrimitiveArrayDump(0x41, 0, HprofType.TYPE_CHAR,
-          new long[]{'n', 'o', 't', ' ', 'h', 'e', 'l', 'l', 'o', 'o', 'p'}));
-
-    ByteArrayDataOutput values = ByteStreams.newDataOutput();
-    values.writeInt(5);     // count
-    values.writeInt(0);     // hashCode
-    values.writeInt(4);     // offset
-    values.writeInt(0x41);  // value
-    dump.add(new HprofInstanceDump(0x42, 0, stringClassObjectId, values.toByteArray()));
-    dump.add(new HprofRootDebugger(stringClassObjectId));
-    dump.add(new HprofRootDebugger(0x42));
-
-    records.add(new HprofHeapDump(0, dump.toArray(new HprofDumpRecord[0])));
-    AhatSnapshot snapshot = SnapshotBuilder.makeSnapshot(strings, records);
-
-    // Diffing should not crash.
-    Diff.snapshots(snapshot, snapshot);
+  public void diffClassRemoved() throws IOException {
+    TestDump dump = TestDump.getTestDump("O.hprof", "L.hprof", null);
+    AhatHandler handler = new ObjectsHandler(dump.getAhatSnapshot());
+    TestHandler.testNoCrash(handler, "http://localhost:7100/objects?class=java.lang.Class");
   }
 }
diff --git a/tools/ahat/test/HtmlEscaperTest.java b/tools/ahat/test/HtmlEscaperTest.java
new file mode 100644
index 0000000..a36db35
--- /dev/null
+++ b/tools/ahat/test/HtmlEscaperTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class HtmlEscaperTest {
+  @Test
+  public void tests() {
+    assertEquals("nothing to escape", HtmlEscaper.escape("nothing to escape"));
+    assertEquals("a&lt;b&gt; &amp; &quot;c&apos;d&quot;e", HtmlEscaper.escape("a<b> & \"c\'d\"e"));
+    assertEquals("adjacent &lt;&lt;&gt;&gt; x", HtmlEscaper.escape("adjacent <<>> x"));
+    assertEquals("&lt; initial", HtmlEscaper.escape("< initial"));
+    assertEquals("ending &gt;", HtmlEscaper.escape("ending >"));
+  }
+}
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
index 63055db..49a21e2 100644
--- a/tools/ahat/test/InstanceTest.java
+++ b/tools/ahat/test/InstanceTest.java
@@ -23,23 +23,7 @@
 import com.android.ahat.heapdump.PathElement;
 import com.android.ahat.heapdump.Size;
 import com.android.ahat.heapdump.Value;
-import com.android.tools.perflib.heap.hprof.HprofClassDump;
-import com.android.tools.perflib.heap.hprof.HprofConstant;
-import com.android.tools.perflib.heap.hprof.HprofDumpRecord;
-import com.android.tools.perflib.heap.hprof.HprofHeapDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceField;
-import com.android.tools.perflib.heap.hprof.HprofLoadClass;
-import com.android.tools.perflib.heap.hprof.HprofPrimitiveArrayDump;
-import com.android.tools.perflib.heap.hprof.HprofRecord;
-import com.android.tools.perflib.heap.hprof.HprofRootDebugger;
-import com.android.tools.perflib.heap.hprof.HprofStaticField;
-import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
-import com.android.tools.perflib.heap.hprof.HprofType;
-import com.google.common.io.ByteArrayDataOutput;
-import com.google.common.io.ByteStreams;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 import org.junit.Test;
 
@@ -395,44 +379,63 @@
 
   @Test
   public void asStringEmbedded() throws IOException {
-    // Set up a heap dump with an instance of java.lang.String of
-    // "hello" with instance id 0x42 that is backed by a char array that is
-    // bigger. This is how ART used to represent strings, and we should still
-    // support it in case the heap dump is from a previous platform version.
-    HprofStringBuilder strings = new HprofStringBuilder(0);
-    List<HprofRecord> records = new ArrayList<HprofRecord>();
-    List<HprofDumpRecord> dump = new ArrayList<HprofDumpRecord>();
+    // On Android L, image strings were backed by a single big char array.
+    // Verify we show just the relative part of the string, not the entire
+    // char array.
+    TestDump dump = TestDump.getTestDump("L.hprof", null, null);
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
 
-    final int stringClassObjectId = 1;
-    records.add(new HprofLoadClass(0, 0, stringClassObjectId, 0, strings.get("java.lang.String")));
-    dump.add(new HprofClassDump(stringClassObjectId, 0, 0, 0, 0, 0, 0, 0, 0,
-          new HprofConstant[0], new HprofStaticField[0],
-          new HprofInstanceField[]{
-            new HprofInstanceField(strings.get("count"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("hashCode"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("offset"), HprofType.TYPE_INT),
-            new HprofInstanceField(strings.get("value"), HprofType.TYPE_OBJECT)}));
+    // java.lang.String@0x6fe17050 is an image string "char" backed by a
+    // shared char array.
+    AhatInstance str = snapshot.findInstance(0x6fe17050);
+    assertEquals("char", str.asString());
+  }
 
-    dump.add(new HprofPrimitiveArrayDump(0x41, 0, HprofType.TYPE_CHAR,
-          new long[]{'n', 'o', 't', ' ', 'h', 'e', 'l', 'l', 'o', 'o', 'p'}));
+  @Test
+  public void nonDefaultHeapRoot() throws IOException {
+    TestDump dump = TestDump.getTestDump("O.hprof", null, null);
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
 
-    ByteArrayDataOutput values = ByteStreams.newDataOutput();
-    values.writeInt(5);     // count
-    values.writeInt(0);     // hashCode
-    values.writeInt(4);     // offset
-    values.writeInt(0x41);  // value
-    dump.add(new HprofInstanceDump(0x42, 0, stringClassObjectId, values.toByteArray()));
-    dump.add(new HprofRootDebugger(stringClassObjectId));
-    dump.add(new HprofRootDebugger(0x42));
+    // java.util.HashMap@6004fdb8 is marked as a VM INTERNAL root.
+    // Previously we had a bug where roots not on the default heap were not
+    // properly treated as roots (b/65356532).
+    AhatInstance map = snapshot.findInstance(0x6004fdb8);
+    assertEquals("java.util.HashMap", map.getClassName());
+    assertTrue(map.isRoot());
+  }
 
-    records.add(new HprofHeapDump(0, dump.toArray(new HprofDumpRecord[0])));
-    AhatSnapshot snapshot = SnapshotBuilder.makeSnapshot(strings, records);
-    AhatInstance chars = snapshot.findInstance(0x41);
-    assertNotNull(chars);
-    assertEquals("not helloop", chars.asString());
+  @Test
+  public void threadRoot() throws IOException {
+    TestDump dump = TestDump.getTestDump("O.hprof", null, null);
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
 
-    AhatInstance stringInstance = snapshot.findInstance(0x42);
-    assertNotNull(stringInstance);
-    assertEquals("hello", stringInstance.asString());
+    // java.lang.Thread@12c03470 is marked as a thread root.
+    // Previously we had a bug where thread roots were not properly treated as
+    // roots (b/65356532).
+    AhatInstance thread = snapshot.findInstance(0x12c03470);
+    assertEquals("java.lang.Thread", thread.getClassName());
+    assertTrue(thread.isRoot());
+  }
+
+  @Test
+  public void classOfClass() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("anObject");
+    AhatClassObj cls = obj.getClassObj();
+    AhatClassObj clscls = cls.getClassObj();
+    assertNotNull(clscls);
+    assertEquals("java.lang.Class", clscls.getName());
+  }
+
+  @Test
+  public void nullValueString() throws IOException {
+    TestDump dump = TestDump.getTestDump("RI.hprof", null, null);
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+    // java.lang.String@500001a8 has a null 'value' field, which should not
+    // cause ahat to crash.
+    AhatInstance str = snapshot.findInstance(0x500001a8);
+    assertEquals("java.lang.String", str.getClassName());
+    assertNull(str.asString());
   }
 }
diff --git a/tools/ahat/test/ProguardMapTest.java b/tools/ahat/test/ProguardMapTest.java
new file mode 100644
index 0000000..ad40f45
--- /dev/null
+++ b/tools/ahat/test/ProguardMapTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.proguard.ProguardMap;
+import java.io.IOException;
+import java.io.StringReader;
+import java.text.ParseException;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+public class ProguardMapTest {
+  private static final String TEST_MAP =
+    "class.that.is.Empty -> a:\n"
+    + "class.that.is.Empty$subclass -> b:\n"
+    + "class.with.only.Fields -> c:\n"
+    + "    int prim_type_field -> a\n"
+    + "    int[] prim_array_type_field -> b\n"
+    + "    class.that.is.Empty class_type_field -> c\n"
+    + "    class.that.is.Empty[] array_type_field -> d\n"
+    + "    int longObfuscatedNameField -> abc\n"
+    + "class.with.Methods -> d:\n"
+    + "    int some_field -> a\n"
+    + "    12:23:void <clinit>() -> <clinit>\n"
+    + "    42:43:void boringMethod() -> m\n"
+    + "    45:48:void methodWithPrimArgs(int,float) -> m\n"
+    + "    49:50:void methodWithPrimArrArgs(int[],float) -> m\n"
+    + "    52:55:void methodWithClearObjArg(class.not.in.Map) -> m\n"
+    + "    57:58:void methodWithClearObjArrArg(class.not.in.Map[]) -> m\n"
+    + "    59:61:void methodWithObfObjArg(class.with.only.Fields) -> m\n"
+    + "    64:66:class.with.only.Fields methodWithObfRes() -> n\n"
+    + "    80:80:void lineObfuscatedMethod():8:8 -> o\n"
+    + "    90:90:void lineObfuscatedMethod2():9 -> p\n"
+    + "    120:121:void method.from.a.Superclass.supermethod() -> q\n"
+    ;
+
+  @Test
+  public void proguardMap() throws IOException, ParseException {
+    ProguardMap map = new ProguardMap();
+
+    // An empty proguard map should not deobfuscate anything.
+    assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge"));
+    assertEquals("fooBarSludge", map.getClassName("fooBarSludge"));
+    assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield"));
+    assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield"));
+    ProguardMap.Frame frame = map.getFrame(
+        "foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", "SourceFile.java", 123);
+    assertEquals("mymethod", frame.method);
+    assertEquals("(Lfoo/bar/Sludge;)V", frame.signature);
+    assertEquals("SourceFile.java", frame.filename);
+    assertEquals(123, frame.line);
+
+    // Read in the proguard map.
+    map.readFromReader(new StringReader(TEST_MAP));
+
+    // It should still not deobfuscate things that aren't in the map
+    assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge"));
+    assertEquals("fooBarSludge", map.getClassName("fooBarSludge"));
+    assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield"));
+    assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield"));
+    frame = map.getFrame("foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V",
+        "SourceFile.java", 123);
+    assertEquals("mymethod", frame.method);
+    assertEquals("(Lfoo/bar/Sludge;)V", frame.signature);
+    assertEquals("SourceFile.java", frame.filename);
+    assertEquals(123, frame.line);
+
+    // Test deobfuscation of class names
+    assertEquals("class.that.is.Empty", map.getClassName("a"));
+    assertEquals("class.that.is.Empty$subclass", map.getClassName("b"));
+    assertEquals("class.with.only.Fields", map.getClassName("c"));
+    assertEquals("class.with.Methods", map.getClassName("d"));
+
+    // Test deobfuscation of array classes.
+    assertEquals("class.with.Methods[]", map.getClassName("d[]"));
+    assertEquals("class.with.Methods[][]", map.getClassName("d[][]"));
+
+    // Test deobfuscation of methods
+    assertEquals("prim_type_field", map.getFieldName("class.with.only.Fields", "a"));
+    assertEquals("prim_array_type_field", map.getFieldName("class.with.only.Fields", "b"));
+    assertEquals("class_type_field", map.getFieldName("class.with.only.Fields", "c"));
+    assertEquals("array_type_field", map.getFieldName("class.with.only.Fields", "d"));
+    assertEquals("longObfuscatedNameField", map.getFieldName("class.with.only.Fields", "abc"));
+    assertEquals("some_field", map.getFieldName("class.with.Methods", "a"));
+
+    // Test deobfuscation of frames
+    frame = map.getFrame("class.with.Methods", "<clinit>", "()V", "SourceFile.java", 13);
+    assertEquals("<clinit>", frame.method);
+    assertEquals("()V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(13, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "()V", "SourceFile.java", 42);
+    assertEquals("boringMethod", frame.method);
+    assertEquals("()V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(42, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "(IF)V", "SourceFile.java", 45);
+    assertEquals("methodWithPrimArgs", frame.method);
+    assertEquals("(IF)V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(45, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "([IF)V", "SourceFile.java", 49);
+    assertEquals("methodWithPrimArrArgs", frame.method);
+    assertEquals("([IF)V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(49, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "(Lclass/not/in/Map;)V",
+        "SourceFile.java", 52);
+    assertEquals("methodWithClearObjArg", frame.method);
+    assertEquals("(Lclass/not/in/Map;)V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(52, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "([Lclass/not/in/Map;)V",
+        "SourceFile.java", 57);
+    assertEquals("methodWithClearObjArrArg", frame.method);
+    assertEquals("([Lclass/not/in/Map;)V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(57, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "m", "(Lc;)V", "SourceFile.java", 59);
+    assertEquals("methodWithObfObjArg", frame.method);
+    assertEquals("(Lclass/with/only/Fields;)V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(59, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "n", "()Lc;", "SourceFile.java", 64);
+    assertEquals("methodWithObfRes", frame.method);
+    assertEquals("()Lclass/with/only/Fields;", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(64, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 80);
+    assertEquals("lineObfuscatedMethod", frame.method);
+    assertEquals("()V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(8, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "p", "()V", "SourceFile.java", 94);
+    assertEquals("lineObfuscatedMethod2", frame.method);
+    assertEquals("()V", frame.signature);
+    assertEquals("Methods.java", frame.filename);
+    assertEquals(13, frame.line);
+
+    frame = map.getFrame("class.with.Methods", "q", "()V", "SourceFile.java", 120);
+    // TODO: Should this be "supermethod", instead of
+    // "method.from.a.Superclass.supermethod"?
+    assertEquals("method.from.a.Superclass.supermethod", frame.method);
+    assertEquals("()V", frame.signature);
+    assertEquals("Superclass.java", frame.filename);
+    assertEquals(120, frame.line);
+  }
+}
diff --git a/tools/ahat/test/SnapshotBuilder.java b/tools/ahat/test/SnapshotBuilder.java
deleted file mode 100644
index 0eea635..0000000
--- a/tools/ahat/test/SnapshotBuilder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ahat;
-
-import com.android.ahat.heapdump.AhatSnapshot;
-import com.android.tools.perflib.heap.ProguardMap;
-import com.android.tools.perflib.heap.hprof.Hprof;
-import com.android.tools.perflib.heap.hprof.HprofRecord;
-import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
-import com.android.tools.perflib.heap.io.InMemoryBuffer;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Class with utilities to help constructing snapshots for tests.
- */
-public class SnapshotBuilder {
-
-  // Helper function to make a snapshot with id size 4 given an
-  // HprofStringBuilder and list of HprofRecords
-  public static AhatSnapshot makeSnapshot(HprofStringBuilder strings, List<HprofRecord> records)
-    throws IOException {
-    // TODO: When perflib can handle the case where strings are referred to
-    // before they are defined, just add the string records to the records
-    // list.
-    List<HprofRecord> actualRecords = new ArrayList<HprofRecord>();
-    actualRecords.addAll(strings.getStringRecords());
-    actualRecords.addAll(records);
-
-    Hprof hprof = new Hprof("JAVA PROFILE 1.0.3", 4, new Date(), actualRecords);
-    ByteArrayOutputStream os = new ByteArrayOutputStream();
-    hprof.write(os);
-    InMemoryBuffer buffer = new InMemoryBuffer(os.toByteArray());
-    return AhatSnapshot.fromDataBuffer(buffer, new ProguardMap());
-  }
-}
diff --git a/tools/ahat/test/TestDump.java b/tools/ahat/test/TestDump.java
index db9b256..a0d1021 100644
--- a/tools/ahat/test/TestDump.java
+++ b/tools/ahat/test/TestDump.java
@@ -21,75 +21,124 @@
 import com.android.ahat.heapdump.AhatSnapshot;
 import com.android.ahat.heapdump.Diff;
 import com.android.ahat.heapdump.FieldValue;
+import com.android.ahat.heapdump.HprofFormatException;
+import com.android.ahat.heapdump.Parser;
 import com.android.ahat.heapdump.Site;
 import com.android.ahat.heapdump.Value;
-import com.android.tools.perflib.heap.ProguardMap;
-import java.io.File;
+import com.android.ahat.proguard.ProguardMap;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
 
 /**
- * The TestDump class is used to get an AhatSnapshot for the test-dump
- * program.
+ * The TestDump class is used to get the current and baseline AhatSnapshots
+ * for heap dumps generated by the test-dump program that are stored as
+ * resources in this jar file.
  */
 public class TestDump {
-  // It can take on the order of a second to parse and process the test-dump
-  // hprof. To avoid repeating this overhead for each test case, we cache the
-  // loaded instance of TestDump and reuse it when possible. In theory the
-  // test cases should not be able to modify the cached snapshot in a way that
-  // is visible to other test cases.
-  private static TestDump mCachedTestDump = null;
+  // It can take on the order of a second to parse and process test dumps.
+  // To avoid repeating this overhead for each test case, we provide a way to
+  // cache loaded instance of TestDump and reuse it when possible. In theory
+  // the test cases should not be able to modify the cached snapshot in a way
+  // that is visible to other test cases.
+  private static List<TestDump> mCachedTestDumps = new ArrayList<TestDump>();
+
+  // The name of the resources this test dump is loaded from.
+  private String mHprofResource;
+  private String mHprofBaseResource;
+  private String mMapResource;
 
   // If the test dump fails to load the first time, it will likely fail every
   // other test we try. Rather than having to wait a potentially very long
   // time for test dump loading to fail over and over again, record when it
   // fails and don't try to load it again.
-  private static boolean mTestDumpFailed = false;
+  private boolean mTestDumpFailed = true;
 
+  // The loaded heap dumps.
   private AhatSnapshot mSnapshot;
   private AhatSnapshot mBaseline;
+
+  // Cached reference to the 'Main' class object in the snapshot and baseline
+  // heap dumps.
   private AhatClassObj mMain;
   private AhatClassObj mBaselineMain;
 
   /**
-   * Load the test-dump.hprof and test-dump-base.hprof files.
-   * The location of the files are read from the system properties
-   * "ahat.test.dump.hprof" and "ahat.test.dump.base.hprof", which is expected
-   * to be set on the command line.
-   * The location of the proguard map for both hprof files is read from the
-   * system property "ahat.test.dump.map".  For example:
-   *   java -Dahat.test.dump.hprof=test-dump.hprof \
-   *        -Dahat.test.dump.base.hprof=test-dump-base.hprof \
-   *        -Dahat.test.dump.map=proguard.map \
-   *        -jar ahat-tests.jar
+   * Read the named resource into a ByteBuffer.
+   */
+  private static ByteBuffer dataBufferFromResource(String name) throws IOException {
+    ClassLoader loader = TestDump.class.getClassLoader();
+    InputStream is = loader.getResourceAsStream(name);
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    byte[] buf = new byte[4096];
+    int read;
+    while ((read = is.read(buf)) != -1) {
+      baos.write(buf, 0, read);
+    }
+    return ByteBuffer.wrap(baos.toByteArray());
+  }
+
+  /**
+   * Create a TestDump instance.
+   * The load() method should be called to load and process the heap dumps.
+   * The files are specified as names of resources compiled into the jar file.
+   * The baseline resouce may be null to indicate that no diffing should be
+   * performed.
+   * The map resource may be null to indicate no proguard map will be used.
    *
+   */
+  private TestDump(String hprofResource, String hprofBaseResource, String mapResource) {
+    mHprofResource = hprofResource;
+    mHprofBaseResource = hprofBaseResource;
+    mMapResource = mapResource;
+  }
+
+  /**
+   * Load the heap dumps for this TestDump.
    * An IOException is thrown if there is a failure reading the hprof files or
    * the proguard map.
    */
-  private TestDump() throws IOException {
-    // TODO: Make use of the baseline hprof for tests.
-    String hprof = System.getProperty("ahat.test.dump.hprof");
-    String hprofBase = System.getProperty("ahat.test.dump.base.hprof");
-
-    String mapfile = System.getProperty("ahat.test.dump.map");
+  private void load() throws IOException {
     ProguardMap map = new ProguardMap();
-    try {
-      map.readFromFile(new File(mapfile));
-    } catch (ParseException e) {
-      throw new IOException("Unable to load proguard map", e);
+    if (mMapResource != null) {
+      try {
+        ClassLoader loader = TestDump.class.getClassLoader();
+        InputStream is = loader.getResourceAsStream(mMapResource);
+        map.readFromReader(new InputStreamReader(is));
+      } catch (ParseException e) {
+        throw new IOException("Unable to load proguard map", e);
+      }
     }
 
-    mSnapshot = AhatSnapshot.fromHprof(new File(hprof), map);
-    mBaseline = AhatSnapshot.fromHprof(new File(hprofBase), map);
-    Diff.snapshots(mSnapshot, mBaseline);
+    try {
+      ByteBuffer hprof = dataBufferFromResource(mHprofResource);
+      mSnapshot = Parser.parseHeapDump(hprof, map);
+      mMain = findClass(mSnapshot, "Main");
+      assert(mMain != null);
+    } catch (HprofFormatException e) {
+      throw new IOException("Unable to parse heap dump", e);
+    }
 
-    mMain = findClass(mSnapshot, "Main");
-    assert(mMain != null);
+    if (mHprofBaseResource != null) {
+      try {
+        ByteBuffer hprofBase = dataBufferFromResource(mHprofBaseResource);
+        mBaseline = Parser.parseHeapDump(hprofBase, map);
+        mBaselineMain = findClass(mBaseline, "Main");
+        assert(mBaselineMain != null);
+      } catch (HprofFormatException e) {
+        throw new IOException("Unable to parse base heap dump", e);
+      }
+      Diff.snapshots(mSnapshot, mBaseline);
+    }
 
-    mBaselineMain = findClass(mBaseline, "Main");
-    assert(mBaselineMain != null);
+    mTestDumpFailed = false;
   }
 
   /**
@@ -182,22 +231,42 @@
   }
 
   /**
-   * Get the test dump.
+   * Get the default (cached) test dump.
    * An IOException is thrown if there is an error reading the test dump hprof
    * file.
    * To improve performance, this returns a cached instance of the TestDump
    * when possible.
    */
   public static synchronized TestDump getTestDump() throws IOException {
-    if (mTestDumpFailed) {
-      throw new RuntimeException("Test dump failed before, assuming it will again");
+    return getTestDump("test-dump.hprof", "test-dump-base.hprof", "test-dump.map");
+  }
+
+  /**
+   * Get a (cached) test dump.
+   * @param hprof - The string resouce name of the hprof file.
+   * @param base - The string resouce name of the baseline hprof, may be null.
+   * @param map - The string resouce name of the proguard map, may be null.
+   * An IOException is thrown if there is an error reading the test dump hprof
+   * file.
+   * To improve performance, this returns a cached instance of the TestDump
+   * when possible.
+   */
+  public static synchronized TestDump getTestDump(String hprof, String base, String map)
+    throws IOException {
+    for (TestDump loaded : mCachedTestDumps) {
+      if (Objects.equals(loaded.mHprofResource, hprof)
+          && Objects.equals(loaded.mHprofBaseResource, base)
+          && Objects.equals(loaded.mMapResource, map)) {
+        if (loaded.mTestDumpFailed) {
+          throw new IOException("Test dump failed before, assuming it will again");
+        }
+        return loaded;
+      }
     }
 
-    if (mCachedTestDump == null) {
-      mTestDumpFailed = true;
-      mCachedTestDump = new TestDump();
-      mTestDumpFailed = false;
-    }
-    return mCachedTestDump;
+    TestDump dump = new TestDump(hprof, base, map);
+    mCachedTestDumps.add(dump);
+    dump.load();
+    return dump;
   }
 }
diff --git a/tools/ahat/test/Tests.java b/tools/ahat/test/Tests.java
index cd33a90..0e70432 100644
--- a/tools/ahat/test/Tests.java
+++ b/tools/ahat/test/Tests.java
@@ -25,11 +25,13 @@
         "com.android.ahat.DiffFieldsTest",
         "com.android.ahat.DiffTest",
         "com.android.ahat.DominatorsTest",
+        "com.android.ahat.HtmlEscaperTest",
         "com.android.ahat.InstanceTest",
         "com.android.ahat.NativeAllocationTest",
         "com.android.ahat.ObjectHandlerTest",
         "com.android.ahat.OverviewHandlerTest",
         "com.android.ahat.PerformanceTest",
+        "com.android.ahat.ProguardMapTest",
         "com.android.ahat.RootedHandlerTest",
         "com.android.ahat.QueryTest",
         "com.android.ahat.SiteHandlerTest",
diff --git a/tools/libjdwp_art_failures.txt b/tools/libjdwp_art_failures.txt
new file mode 100644
index 0000000..6b5daec
--- /dev/null
+++ b/tools/libjdwp_art_failures.txt
@@ -0,0 +1,102 @@
+/*
+ * This file contains expectations for ART's buildbot. The purpose of this file is
+ * to temporarily list failing tests and not break the bots.
+ */
+[
+{
+  description: "Test fails due to unexpectedly getting the thread-groups of zombie threads",
+  result: EXEC_FAILED,
+  bug: 66906414,
+  name: "org.apache.harmony.jpda.tests.jdwp.ThreadReference.ThreadGroup002Test#testThreadGroup002"
+},
+{
+  description: "Test fails due to modifiers not including ACC_SUPER",
+  result: EXEC_FAILED,
+  bug: 66906055,
+  name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.ModifiersTest#testModifiers001"
+},
+{
+  description: "Test fails due to static values not being set correctly.",
+  result: EXEC_FAILED,
+  bug: 66905894,
+  name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues006Test#testGetValues006"
+},
+{
+  description: "Tests fail due to using the not yet supported interrupt thread functions",
+  result: EXEC_FAILED,
+  bug: 34415266,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.ThreadReference.CurrentContendedMonitorTest#testCurrentContendedMonitor001",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadReference.InterruptTest#testInterrupt001" ]
+},
+{
+  description: "Tests fail with assertion error on slot number",
+  result: EXEC_FAILED,
+  bug: 66905468,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableTest#testVariableTableTest001",
+           "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableWithGenericTest#testVariableTableWithGenericTest001" ]
+},
+{
+  description: "Test fails with assertion error 'Invalid Path' for class path.",
+  result: EXEC_FAILED,
+  bug: 66904994,
+  name: "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ClassPathsTest#testClassPaths001"
+},
+{
+  description: "Test fails with Error VM_DEAD when trying to resume during VM_DEATH event",
+  result: EXEC_FAILED,
+  bug: 66904725,
+  name: "org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test#testVMDeathRequest"
+},
+{
+  description: "Test fails with INTERNAL error due to proxy frame!",
+  result: EXEC_FAILED,
+  bug: 66903662,
+  name: "org.apache.harmony.jpda.tests.jdwp.StackFrame.ProxyThisObjectTest#testThisObject"
+},
+{
+  description: "Test fails with unexpected TYPE_MISMATCH error",
+  result: EXEC_FAILED,
+  bug: 66904008,
+  name: "org.apache.harmony.jpda.tests.jdwp.StackFrame.ThisObjectTest#testThisObjectTest001"
+},
+{
+  description: "Tests that fail only on ART with INVALID_SLOT error",
+  result: EXEC_FAILED,
+  bug: 66903181,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testBreakpoint",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testException",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testFieldAccess",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testFieldModification",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodEntry",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExit",
+           "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExitWithReturnValue" ]
+},
+/* TODO Categorize these failures more. */
+{
+  description: "Tests that fail on both ART and RI. These tests are likely incorrect",
+  result: EXEC_FAILED,
+  bug: 66906734,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.ArrayReference.SetValues003Test#testSetValues003_InvalidIndex",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethod002Test#testInvokeMethod_wrong_argument_types",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest#testInvokeMethod002",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest#testInvokeMethod003",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceTest#testNewInstance002",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.SetValues002Test#testSetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.Events.ClassPrepare002Test#testClassPrepareCausedByDebugger",
+           "org.apache.harmony.jpda.tests.jdwp.Events.ExceptionCaughtTest#testExceptionEvent_ThrowLocation_FromNative",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.DisableCollectionTest#testDisableCollection_null",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection_invalid",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection_null",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.GetValues002Test#testGetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.SetValues003Test#testSetValues003",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.SetValuesTest#testSetValues001",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.FieldsWithGenericTest#testFieldsWithGeneric001",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues002Test#testGetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues004Test#testGetValues004",
+           "org.apache.harmony.jpda.tests.jdwp.StringReference.ValueTest#testStringReferenceValueTest001_NullString",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ChildrenTest#testChildren_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.NameTest#testName001_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ParentTest#testParent_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ]
+}
+]