Long support in optimizing compiler.

- Add stack locations to the Location class.
- Change logic of parameter passing/setup by setting the
  location of such instructions the ones for the calling
  convention.

Change-Id: I4730ad58732813dcb9c238f44f55dfc0baa18799
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index ef5819d..1f8f799 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -18,6 +18,7 @@
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
 	runtime/barrier_test.cc \
+	runtime/base/bit_field_test.cc \
 	runtime/base/bit_vector_test.cc \
 	runtime/base/hex_dump_test.cc \
 	runtime/base/histogram_test.cc \
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index beccf01..637cf17 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -48,7 +48,8 @@
 
   if (!dex_compilation_unit_->IsStatic()) {
     // Add the implicit 'this' argument, not expressed in the signature.
-    HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
+    HParameterValue* parameter =
+        new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot);
     entry_block_->AddInstruction(parameter);
     HLocal* local = GetLocalAt(locals_index++);
     entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
@@ -59,19 +60,24 @@
   for (int i = 0; i < number_of_parameters; i++) {
     switch (shorty[pos++]) {
       case 'F':
-      case 'D':
-      case 'J': {
+      case 'D': {
         return false;
       }
 
       default: {
         // integer and reference parameters.
-        HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
+        HParameterValue* parameter =
+            new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1]));
         entry_block_->AddInstruction(parameter);
         HLocal* local = GetLocalAt(locals_index++);
         // Store the parameter value in the local that the dex code will use
         // to reference that parameter.
         entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+        if (parameter->GetType() == Primitive::kPrimLong) {
+          i++;
+          locals_index++;
+          parameter_index++;
+        }
         break;
       }
     }
@@ -88,8 +94,8 @@
 
 template<typename T>
 void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) {
-  HInstruction* first = LoadLocal(instruction.VRegA());
-  HInstruction* second = LoadLocal(instruction.VRegB());
+  HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
   current_block_->AddInstruction(new (arena_) T(first, second));
   if (is_not) {
     current_block_->AddInstruction(new (arena_) HNot(current_block_->GetLastInstruction()));
@@ -205,25 +211,25 @@
 }
 
 template<typename T>
-void HGraphBuilder::Binop_32x(const Instruction& instruction) {
-  HInstruction* first = LoadLocal(instruction.VRegB());
-  HInstruction* second = LoadLocal(instruction.VRegC());
-  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
+void HGraphBuilder::Binop_32x(const Instruction& instruction, Primitive::Type type) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type);
+  HInstruction* second = LoadLocal(instruction.VRegC(), type);
+  current_block_->AddInstruction(new (arena_) T(type, first, second));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
 template<typename T>
-void HGraphBuilder::Binop_12x(const Instruction& instruction) {
-  HInstruction* first = LoadLocal(instruction.VRegA());
-  HInstruction* second = LoadLocal(instruction.VRegB());
-  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
+void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
+  HInstruction* first = LoadLocal(instruction.VRegA(), type);
+  HInstruction* second = LoadLocal(instruction.VRegB(), type);
+  current_block_->AddInstruction(new (arena_) T(type, first, second));
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
 template<typename T>
 void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
-  HInstruction* first = LoadLocal(instruction.VRegB());
-  HInstruction* second = GetConstant(instruction.VRegC_22s());
+  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* second = GetIntConstant(instruction.VRegC_22s());
   if (reverse) {
     std::swap(first, second);
   }
@@ -233,8 +239,8 @@
 
 template<typename T>
 void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
-  HInstruction* first = LoadLocal(instruction.VRegB());
-  HInstruction* second = GetConstant(instruction.VRegC_22b());
+  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  HInstruction* second = GetIntConstant(instruction.VRegC_22b());
   if (reverse) {
     std::swap(first, second);
   }
@@ -242,6 +248,78 @@
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
+void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
+  if (type == Primitive::kPrimVoid) {
+    current_block_->AddInstruction(new (arena_) HReturnVoid());
+  } else {
+    HInstruction* value = LoadLocal(instruction.VRegA(), type);
+    current_block_->AddInstruction(new (arena_) HReturn(value));
+  }
+  current_block_->AddSuccessor(exit_block_);
+  current_block_ = nullptr;
+}
+
+bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
+                                uint32_t dex_offset,
+                                uint32_t method_idx,
+                                uint32_t number_of_vreg_arguments,
+                                bool is_range,
+                                uint32_t* args,
+                                uint32_t register_index) {
+  const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
+  const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_);
+  const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_);
+  Primitive::Type return_type = Primitive::GetType(descriptor[0]);
+  bool is_instance_call =
+      instruction.Opcode() != Instruction::INVOKE_STATIC
+      && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE;
+  const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
+
+  // Treat invoke-direct like static calls for now.
+  HInvoke* invoke = new (arena_) HInvokeStatic(
+      arena_, number_of_arguments, return_type, dex_offset, method_idx);
+
+  size_t start_index = 0;
+  if (is_instance_call) {
+    HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
+    HInstruction* push = new (arena_) HPushArgument(arg, 0);
+    current_block_->AddInstruction(push);
+    invoke->SetArgumentAt(0, push);
+    start_index = 1;
+  }
+
+  uint32_t descriptor_index = 1;
+  uint32_t argument_index = start_index;
+  for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) {
+    Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
+    switch (type) {
+      case Primitive::kPrimFloat:
+      case Primitive::kPrimDouble:
+        return false;
+
+      default: {
+        if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) {
+          LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol()
+                       << " at " << dex_offset;
+          // We do not implement non sequential register pair.
+          return false;
+        }
+        HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
+        HInstruction* push = new (arena_) HPushArgument(arg, i);
+        current_block_->AddInstruction(push);
+        invoke->SetArgumentAt(argument_index, push);
+        if (type == Primitive::kPrimLong) {
+          i++;
+        }
+      }
+    }
+  }
+
+  DCHECK_EQ(argument_index, number_of_arguments);
+  current_block_->AddInstruction(invoke);
+  return true;
+}
+
 bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
   if (current_block_ == nullptr) {
     return true;  // Dead code
@@ -250,28 +328,47 @@
   switch (instruction.Opcode()) {
     case Instruction::CONST_4: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetConstant(instruction.VRegB_11n());
+      HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::CONST_16: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetConstant(instruction.VRegB_21s());
+      HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
+      UpdateLocal(register_index, constant);
+      break;
+    }
+
+    case Instruction::CONST_WIDE_16: {
+      int32_t register_index = instruction.VRegA();
+      HLongConstant* constant = GetLongConstant(instruction.VRegB_21s());
+      UpdateLocal(register_index, constant);
+      break;
+    }
+
+    case Instruction::CONST_WIDE_32: {
+      int32_t register_index = instruction.VRegA();
+      HLongConstant* constant = GetLongConstant(instruction.VRegB_31i());
+      UpdateLocal(register_index, constant);
+      break;
+    }
+
+    case Instruction::CONST_WIDE: {
+      int32_t register_index = instruction.VRegA();
+      HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::MOVE: {
-      HInstruction* value = LoadLocal(instruction.VRegB());
+      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
       UpdateLocal(instruction.VRegA(), value);
       break;
     }
 
     case Instruction::RETURN_VOID: {
-      current_block_->AddInstruction(new (arena_) HReturnVoid());
-      current_block_->AddSuccessor(exit_block_);
-      current_block_ = nullptr;
+      BuildReturn(instruction, Primitive::kPrimVoid);
       break;
     }
 
@@ -296,88 +393,82 @@
       break;
     }
 
-    case Instruction::RETURN:
+    case Instruction::RETURN: {
+      BuildReturn(instruction, Primitive::kPrimInt);
+      break;
+    }
+
     case Instruction::RETURN_OBJECT: {
-      HInstruction* value = LoadLocal(instruction.VRegA());
-      current_block_->AddInstruction(new (arena_) HReturn(value));
-      current_block_->AddSuccessor(exit_block_);
-      current_block_ = nullptr;
+      BuildReturn(instruction, Primitive::kPrimNot);
+      break;
+    }
+
+    case Instruction::RETURN_WIDE: {
+      BuildReturn(instruction, Primitive::kPrimLong);
       break;
     }
 
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_DIRECT: {
       uint32_t method_idx = instruction.VRegB_35c();
-      const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-      uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
-      const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
-      const size_t number_of_arguments = instruction.VRegA_35c();
-
-      if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
-        return false;
-      }
-
-      // Treat invoke-direct like static calls for now.
-      HInvokeStatic* invoke = new (arena_) HInvokeStatic(
-          arena_, number_of_arguments, dex_offset, method_idx);
-
+      uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
       uint32_t args[5];
       instruction.GetArgs(args);
-
-      for (size_t i = 0; i < number_of_arguments; i++) {
-        HInstruction* arg = LoadLocal(args[i]);
-        HInstruction* push = new (arena_) HPushArgument(arg, i);
-        current_block_->AddInstruction(push);
-        invoke->SetArgumentAt(i, push);
+      if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
+        return false;
       }
-
-      current_block_->AddInstruction(invoke);
       break;
     }
 
     case Instruction::INVOKE_STATIC_RANGE:
     case Instruction::INVOKE_DIRECT_RANGE: {
       uint32_t method_idx = instruction.VRegB_3rc();
-      const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-      uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
-      const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
-      const size_t number_of_arguments = instruction.VRegA_3rc();
-
-      if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
+      uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
+      uint32_t register_index = instruction.VRegC();
+      if (!BuildInvoke(instruction, dex_offset, method_idx,
+                       number_of_vreg_arguments, true, nullptr, register_index)) {
         return false;
       }
-
-      // Treat invoke-direct like static calls for now.
-      HInvokeStatic* invoke = new (arena_) HInvokeStatic(
-          arena_, number_of_arguments, dex_offset, method_idx);
-      int32_t register_index = instruction.VRegC();
-      for (size_t i = 0; i < number_of_arguments; i++) {
-        HInstruction* arg = LoadLocal(register_index + i);
-        HInstruction* push = new (arena_) HPushArgument(arg, i);
-        current_block_->AddInstruction(push);
-        invoke->SetArgumentAt(i, push);
-      }
-      current_block_->AddInstruction(invoke);
       break;
     }
 
     case Instruction::ADD_INT: {
-      Binop_32x<HAdd>(instruction);
+      Binop_32x<HAdd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::ADD_LONG: {
+      Binop_32x<HAdd>(instruction, Primitive::kPrimLong);
       break;
     }
 
     case Instruction::SUB_INT: {
-      Binop_32x<HSub>(instruction);
+      Binop_32x<HSub>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SUB_LONG: {
+      Binop_32x<HSub>(instruction, Primitive::kPrimLong);
       break;
     }
 
     case Instruction::ADD_INT_2ADDR: {
-      Binop_12x<HAdd>(instruction);
+      Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::ADD_LONG_2ADDR: {
+      Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
       break;
     }
 
     case Instruction::SUB_INT_2ADDR: {
-      Binop_12x<HSub>(instruction);
+      Binop_12x<HSub>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SUB_LONG_2ADDR: {
+      Binop_12x<HSub>(instruction, Primitive::kPrimLong);
       break;
     }
 
@@ -408,6 +499,11 @@
       break;
     }
 
+    case Instruction::MOVE_RESULT_WIDE: {
+      UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+      break;
+    }
+
     case Instruction::NOP:
       break;
 
@@ -417,7 +513,7 @@
   return true;
 }
 
-HIntConstant* HGraphBuilder::GetConstant0() {
+HIntConstant* HGraphBuilder::GetIntConstant0() {
   if (constant0_ != nullptr) {
     return constant0_;
   }
@@ -426,7 +522,7 @@
   return constant0_;
 }
 
-HIntConstant* HGraphBuilder::GetConstant1() {
+HIntConstant* HGraphBuilder::GetIntConstant1() {
   if (constant1_ != nullptr) {
     return constant1_;
   }
@@ -435,10 +531,10 @@
   return constant1_;
 }
 
-HIntConstant* HGraphBuilder::GetConstant(int constant) {
+HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
   switch (constant) {
-    case 0: return GetConstant0();
-    case 1: return GetConstant1();
+    case 0: return GetIntConstant0();
+    case 1: return GetIntConstant1();
     default: {
       HIntConstant* instruction = new (arena_) HIntConstant(constant);
       entry_block_->AddInstruction(instruction);
@@ -447,6 +543,12 @@
   }
 }
 
+HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
+  HLongConstant* instruction = new (arena_) HLongConstant(constant);
+  entry_block_->AddInstruction(instruction);
+  return instruction;
+}
+
 HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
   return locals_.Get(register_index);
 }
@@ -456,9 +558,9 @@
   current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
 }
 
-HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
+HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
   HLocal* local = GetLocalAt(register_index);
-  current_block_->AddInstruction(new (arena_) HLoadLocal(local));
+  current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
   return current_block_->GetLastInstruction();
 }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 60d9982..108514a 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -19,6 +19,7 @@
 
 #include "dex_file.h"
 #include "driver/dex_compilation_unit.h"
+#include "primitive.h"
 #include "utils/allocation.h"
 #include "utils/growable_array.h"
 
@@ -29,13 +30,14 @@
 class HBasicBlock;
 class HGraph;
 class HIntConstant;
+class HLongConstant;
 class HInstruction;
 class HLocal;
 
 class HGraphBuilder : public ValueObject {
  public:
   HGraphBuilder(ArenaAllocator* arena,
-                const DexCompilationUnit* dex_compilation_unit = nullptr,
+                DexCompilationUnit* dex_compilation_unit = nullptr,
                 const DexFile* dex_file = nullptr)
       : arena_(arena),
         branch_targets_(arena, 0),
@@ -63,24 +65,44 @@
   void MaybeUpdateCurrentBlock(size_t index);
   HBasicBlock* FindBlockStartingAt(int32_t index) const;
 
-  HIntConstant* GetConstant0();
-  HIntConstant* GetConstant1();
-  HIntConstant* GetConstant(int constant);
+  HIntConstant* GetIntConstant0();
+  HIntConstant* GetIntConstant1();
+  HIntConstant* GetIntConstant(int32_t constant);
+  HLongConstant* GetLongConstant(int64_t constant);
   void InitializeLocals(uint16_t count);
   HLocal* GetLocalAt(int register_index) const;
   void UpdateLocal(int register_index, HInstruction* instruction) const;
-  HInstruction* LoadLocal(int register_index) const;
+  HInstruction* LoadLocal(int register_index, Primitive::Type type) const;
 
   // Temporarily returns whether the compiler supports the parameters
   // of the method.
   bool InitializeParameters(uint16_t number_of_parameters);
 
-  template<typename T> void Binop_32x(const Instruction& instruction);
-  template<typename T> void Binop_12x(const Instruction& instruction);
-  template<typename T> void Binop_22b(const Instruction& instruction, bool reverse);
-  template<typename T> void Binop_22s(const Instruction& instruction, bool reverse);
+  template<typename T>
+  void Binop_32x(const Instruction& instruction, Primitive::Type type);
+
+  template<typename T>
+  void Binop_12x(const Instruction& instruction, Primitive::Type type);
+
+  template<typename T>
+  void Binop_22b(const Instruction& instruction, bool reverse);
+
+  template<typename T>
+  void Binop_22s(const Instruction& instruction, bool reverse);
+
   template<typename T> void If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not);
 
+  void BuildReturn(const Instruction& instruction, Primitive::Type type);
+
+  // Builds an invocation node and returns whether the instruction is supported.
+  bool BuildInvoke(const Instruction& instruction,
+                   uint32_t dex_offset,
+                   uint32_t method_idx,
+                   uint32_t number_of_vreg_arguments,
+                   bool is_range,
+                   uint32_t* args,
+                   uint32_t register_index);
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
@@ -99,7 +121,7 @@
   HIntConstant* constant1_;
 
   const DexFile* const dex_file_;
-  const DexCompilationUnit* const dex_compilation_unit_;
+  DexCompilationUnit* const dex_compilation_unit_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 6648598..d459dd5 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 
+#include "base/bit_field.h"
 #include "globals.h"
 #include "instruction_set.h"
 #include "memory_region.h"
@@ -49,30 +50,149 @@
  */
 class Location : public ValueObject {
  public:
-  template<typename T>
-  T reg() const { return static_cast<T>(reg_); }
+  enum Kind {
+    kInvalid = 0,
+    kStackSlot = 1,  // Word size slot.
+    kDoubleStackSlot = 2,  // 64bit stack slot.
+    kRegister = 3,
+    // On 32bits architectures, quick can pass a long where the
+    // low bits are in the last parameter register, and the high
+    // bits are in a stack slot. The kQuickParameter kind is for
+    // handling this special case.
+    kQuickParameter = 4,
+  };
 
-  Location() : reg_(kInvalid) { }
-  explicit Location(uword reg) : reg_(reg) { }
-
-  static Location RegisterLocation(uword reg) {
-    return Location(reg);
+  Location() : value_(kInvalid) {
+    DCHECK(!IsValid());
   }
 
-  bool IsValid() const { return reg_ != kInvalid; }
-
-  Location(const Location& other) : reg_(other.reg_) { }
+  Location(const Location& other) : ValueObject(), value_(other.value_) {}
 
   Location& operator=(const Location& other) {
-    reg_ = other.reg_;
+    value_ = other.value_;
     return *this;
   }
 
+  bool IsValid() const {
+    return value_ != kInvalid;
+  }
+
+  // Register locations.
+  static Location RegisterLocation(ManagedRegister reg) {
+    return Location(kRegister, reg.RegId());
+  }
+
+  bool IsRegister() const {
+    return GetKind() == kRegister;
+  }
+
+  ManagedRegister reg() const {
+    DCHECK(IsRegister());
+    return static_cast<ManagedRegister>(GetPayload());
+  }
+
+  static uword EncodeStackIndex(intptr_t stack_index) {
+    DCHECK(-kStackIndexBias <= stack_index);
+    DCHECK(stack_index < kStackIndexBias);
+    return static_cast<uword>(kStackIndexBias + stack_index);
+  }
+
+  static Location StackSlot(intptr_t stack_index) {
+    uword payload = EncodeStackIndex(stack_index);
+    Location loc(kStackSlot, payload);
+    // Ensure that sign is preserved.
+    DCHECK_EQ(loc.GetStackIndex(), stack_index);
+    return loc;
+  }
+
+  bool IsStackSlot() const {
+    return GetKind() == kStackSlot;
+  }
+
+  static Location DoubleStackSlot(intptr_t stack_index) {
+    uword payload = EncodeStackIndex(stack_index);
+    Location loc(kDoubleStackSlot, payload);
+    // Ensure that sign is preserved.
+    DCHECK_EQ(loc.GetStackIndex(), stack_index);
+    return loc;
+  }
+
+  bool IsDoubleStackSlot() const {
+    return GetKind() == kDoubleStackSlot;
+  }
+
+  intptr_t GetStackIndex() const {
+    DCHECK(IsStackSlot() || IsDoubleStackSlot());
+    // Decode stack index manually to preserve sign.
+    return GetPayload() - kStackIndexBias;
+  }
+
+  intptr_t GetHighStackIndex(uintptr_t word_size) const {
+    DCHECK(IsDoubleStackSlot());
+    // Decode stack index manually to preserve sign.
+    return GetPayload() - kStackIndexBias + word_size;
+  }
+
+  static Location QuickParameter(uint32_t parameter_index) {
+    return Location(kQuickParameter, parameter_index);
+  }
+
+  uint32_t GetQuickParameterIndex() const {
+    DCHECK(IsQuickParameter());
+    return GetPayload();
+  }
+
+  bool IsQuickParameter() const {
+    return GetKind() == kQuickParameter;
+  }
+
+  arm::ArmManagedRegister AsArm() const;
+  x86::X86ManagedRegister AsX86() const;
+
+  Kind GetKind() const {
+    return KindField::Decode(value_);
+  }
+
+  bool Equals(Location other) const {
+    return value_ == other.value_;
+  }
+
+  const char* DebugString() const {
+    switch (GetKind()) {
+      case kInvalid: return "?";
+      case kRegister: return "R";
+      case kStackSlot: return "S";
+      case kDoubleStackSlot: return "DS";
+      case kQuickParameter: return "Q";
+    }
+    return "?";
+  }
+
  private:
-  // The target register for that location.
-  // TODO: Support stack location.
-  uword reg_;
-  static const uword kInvalid = -1;
+  // Number of bits required to encode Kind value.
+  static constexpr uint32_t kBitsForKind = 4;
+  static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
+
+  explicit Location(uword value) : value_(value) {}
+
+  Location(Kind kind, uword payload)
+      : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
+
+  uword GetPayload() const {
+    return PayloadField::Decode(value_);
+  }
+
+  typedef BitField<Kind, 0, kBitsForKind> KindField;
+  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
+
+  // Layout for stack slots.
+  static const intptr_t kStackIndexBias =
+      static_cast<intptr_t>(1) << (kBitsForPayload - 1);
+
+  // Location either contains kind and payload fields or a tagged handle for
+  // a constant locations. Values of enumeration Kind are selected in such a
+  // way that none of them can be interpreted as a kConstant tag.
+  uword value_;
 };
 
 /**
@@ -204,7 +324,6 @@
   }
 
   uint8_t GetStackOffsetOf(size_t index) const {
-    DCHECK_GE(index, number_of_registers_);
     // We still reserve the space for parameters passed by registers.
     // Add kWordSize for the method pointer.
     return index * kWordSize + kWordSize;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 4e88765..fe61333 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -17,6 +17,7 @@
 #include "code_generator_arm.h"
 #include "utils/assembler.h"
 #include "utils/arm/assembler_arm.h"
+#include "utils/arm/managed_register_arm.h"
 
 #include "mirror/array.h"
 #include "mirror/art_method.h"
@@ -24,11 +25,20 @@
 #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
 
 namespace art {
+
+arm::ArmManagedRegister Location::AsArm() const {
+  return reg().AsArm();
+}
+
 namespace arm {
 
 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
 static constexpr int kCurrentMethodStackOffset = 0;
 
+static Location ArmCoreLocation(Register reg) {
+  return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
+}
+
 InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
       : HGraphVisitor(graph),
         assembler_(codegen->GetAssembler()),
@@ -73,18 +83,171 @@
   }
 }
 
+static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
+static constexpr RegisterPair kParameterCorePairRegisters[] = { R1_R2, R2_R3 };
+static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+
+class InvokeDexCallingConvention : public CallingConvention<Register> {
+ public:
+  InvokeDexCallingConvention()
+      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
+
+  RegisterPair GetRegisterPairAt(size_t argument_index) {
+    DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
+    return kParameterCorePairRegisters[argument_index];
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
+};
+
+void CodeGeneratorARM::Move32(Location destination, Location source) {
+  if (source.Equals(destination)) {
+    return;
+  }
+  if (destination.IsRegister()) {
+    if (source.IsRegister()) {
+      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
+    } else {
+      __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
+    }
+  } else {
+    DCHECK(destination.IsStackSlot());
+    if (source.IsRegister()) {
+      __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
+    } else {
+      __ ldr(R0, Address(SP, source.GetStackIndex()));
+      __ str(R0, Address(SP, destination.GetStackIndex()));
+    }
+  }
+}
+
+void CodeGeneratorARM::Move64(Location destination, Location source) {
+  if (source.Equals(destination)) {
+    return;
+  }
+  if (destination.IsRegister()) {
+    if (source.IsRegister()) {
+      __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
+      __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
+    } else if (source.IsQuickParameter()) {
+      uint32_t argument_index = source.GetQuickParameterIndex();
+      InvokeDexCallingConvention calling_convention;
+      __ Mov(destination.AsArm().AsRegisterPairLow(),
+             calling_convention.GetRegisterAt(argument_index));
+      __ ldr(destination.AsArm().AsRegisterPairHigh(),
+             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      if (destination.AsArm().AsRegisterPair() == R1_R2) {
+        __ ldr(R1, Address(SP, source.GetStackIndex()));
+        __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
+      } else {
+        __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
+                          SP, source.GetStackIndex());
+      }
+    }
+  } else if (destination.IsQuickParameter()) {
+    InvokeDexCallingConvention calling_convention;
+    uint32_t argument_index = destination.GetQuickParameterIndex();
+    if (source.IsRegister()) {
+      __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
+      __ str(source.AsArm().AsRegisterPairHigh(),
+             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
+      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
+      __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
+    }
+  } else {
+    DCHECK(destination.IsDoubleStackSlot());
+    if (source.IsRegister()) {
+      if (source.AsArm().AsRegisterPair() == R1_R2) {
+        __ str(R1, Address(SP, destination.GetStackIndex()));
+        __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+      } else {
+        __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
+                         SP, destination.GetStackIndex());
+      }
+    } else if (source.IsQuickParameter()) {
+      InvokeDexCallingConvention calling_convention;
+      uint32_t argument_index = source.GetQuickParameterIndex();
+      __ str(calling_convention.GetRegisterAt(argument_index),
+             Address(SP, destination.GetStackIndex()));
+      __ ldr(R0,
+             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ ldr(R0, Address(SP, source.GetStackIndex()));
+      __ str(R0, Address(SP, destination.GetStackIndex()));
+      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
+      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+    }
+  }
+}
+
 void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
   if (instruction->AsIntConstant() != nullptr) {
-    __ LoadImmediate(location.reg<Register>(), instruction->AsIntConstant()->GetValue());
+    int32_t value = instruction->AsIntConstant()->GetValue();
+    if (location.IsRegister()) {
+      __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
+    } else {
+      __ LoadImmediate(R0, value);
+      __ str(R0, Address(SP, location.GetStackIndex()));
+    }
+  } else if (instruction->AsLongConstant() != nullptr) {
+    int64_t value = instruction->AsLongConstant()->GetValue();
+    if (location.IsRegister()) {
+      __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
+      __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
+    } else {
+      __ LoadImmediate(R0, Low32Bits(value));
+      __ str(R0, Address(SP, location.GetStackIndex()));
+      __ LoadImmediate(R0, High32Bits(value));
+      __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize)));
+    }
   } else if (instruction->AsLoadLocal() != nullptr) {
-    __ LoadFromOffset(kLoadWord, location.reg<Register>(),
-                      SP, GetStackSlot(instruction->AsLoadLocal()->GetLocal()));
+    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
+    switch (instruction->GetType()) {
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimNot:
+        Move32(location, Location::StackSlot(stack_slot));
+        break;
+
+      case Primitive::kPrimLong:
+        Move64(location, Location::DoubleStackSlot(stack_slot));
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+    }
   } else {
     // This can currently only happen when the instruction that requests the move
     // is the next to be compiled.
     DCHECK_EQ(instruction->GetNext(), move_for);
-    __ mov(location.reg<Register>(),
-           ShifterOperand(instruction->GetLocations()->Out().reg<Register>()));
+    switch (instruction->GetType()) {
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimNot:
+      case Primitive::kPrimInt:
+        Move32(location, instruction->GetLocations()->Out());
+        break;
+
+      case Primitive::kPrimLong:
+        Move64(location, instruction->GetLocations()->Out());
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+    }
   }
 }
 
@@ -114,13 +277,13 @@
 
 void LocationsBuilderARM::VisitIf(HIf* if_instr) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
-  locations->SetInAt(0, Location(R0));
+  locations->SetInAt(0, ArmCoreLocation(R0));
   if_instr->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
   // TODO: Generate the input as a condition, instead of materializing in a register.
-  __ cmp(if_instr->GetLocations()->InAt(0).reg<Register>(), ShifterOperand(0));
+  __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
   __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
   if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
     __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
@@ -129,18 +292,18 @@
 
 void LocationsBuilderARM::VisitEqual(HEqual* equal) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
-  locations->SetInAt(0, Location(R0));
-  locations->SetInAt(1, Location(R1));
-  locations->SetOut(Location(R0));
+  locations->SetInAt(0, ArmCoreLocation(R0));
+  locations->SetInAt(1, ArmCoreLocation(R1));
+  locations->SetOut(ArmCoreLocation(R0));
   equal->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
   LocationSummary* locations = equal->GetLocations();
-  __ teq(locations->InAt(0).reg<Register>(),
-         ShifterOperand(locations->InAt(1).reg<Register>()));
-  __ mov(locations->Out().reg<Register>(), ShifterOperand(1), EQ);
-  __ mov(locations->Out().reg<Register>(), ShifterOperand(0), NE);
+  __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
+         ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
+  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
+  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
 }
 
 void LocationsBuilderARM::VisitLocal(HLocal* local) {
@@ -161,14 +324,27 @@
 
 void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
-  locations->SetInAt(1, Location(R0));
+  switch (store->InputAt(1)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
+  }
   store->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
-  LocationSummary* locations = store->GetLocations();
-  __ StoreToOffset(kStoreWord, locations->InAt(1).reg<Register>(),
-                   SP, codegen_->GetStackSlot(store->GetLocal()));
 }
 
 void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
@@ -179,6 +355,14 @@
   // Will be generated at use site.
 }
 
+void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
+  constant->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
+  // Will be generated at use site.
+}
+
 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
   ret->SetLocations(nullptr);
 }
@@ -189,56 +373,118 @@
 
 void LocationsBuilderARM::VisitReturn(HReturn* ret) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
-  locations->SetInAt(0, Location(R0));
+  switch (ret->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetInAt(0, ArmCoreLocation(R0));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+  }
+
   ret->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
-  DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), R0);
+  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:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
+        break;
+
+      case Primitive::kPrimLong:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+    }
+  }
   codegen_->GenerateFrameExit();
 }
 
-static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
-static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
-
-class InvokeDexCallingConvention : public CallingConvention<Register> {
- public:
-  InvokeDexCallingConvention()
-      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
-};
-
 void LocationsBuilderARM::VisitPushArgument(HPushArgument* argument) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument);
   InvokeDexCallingConvention calling_convention;
-  if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) {
-    Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex()));
-    locations->SetInAt(0, location);
-    locations->SetOut(location);
-  } else {
-    locations->SetInAt(0, Location(R0));
+  uint32_t argument_index = argument->GetArgumentIndex();
+  switch (argument->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      if (argument_index < calling_convention.GetNumberOfRegisters()) {
+        locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(argument_index)));
+      } else {
+        locations->SetInAt(
+            0, Location::StackSlot(calling_convention.GetStackOffsetOf(argument_index)));
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
+        Location location = Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
+            calling_convention.GetRegisterPairAt(argument_index)));
+        locations->SetInAt(0, location);
+      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
+        locations->SetInAt(0, Location::QuickParameter(argument_index));
+      } else {
+        locations->SetInAt(
+            0, Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(argument_index)));
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unimplemented argument type " << argument->InputAt(0)->GetType();
   }
   argument->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitPushArgument(HPushArgument* argument) {
-  uint8_t argument_index = argument->GetArgumentIndex();
-  InvokeDexCallingConvention calling_convention;
-  size_t parameter_registers = calling_convention.GetNumberOfRegisters();
-  LocationSummary* locations = argument->GetLocations();
-  if (argument_index >= parameter_registers) {
-    uint8_t offset = calling_convention.GetStackOffsetOf(argument_index);
-    __ StoreToOffset(kStoreWord, locations->InAt(0).reg<Register>(), SP, offset);
-  } else {
-    DCHECK_EQ(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>());
-  }
+  // Nothing to do.
 }
 
 void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
-  locations->AddTemp(Location(R0));
+  locations->AddTemp(ArmCoreLocation(R0));
+    switch (invoke->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetOut(ArmCoreLocation(R0));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      break;
+
+    case Primitive::kPrimVoid:
+      break;
+
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat:
+      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
+      break;
+  }
+
   invoke->SetLocations(locations);
 }
 
@@ -247,7 +493,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>();
+  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
   size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
       invoke->GetIndexInDexCache() * kArmWordSize;
 
@@ -277,13 +523,30 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
   switch (add->GetResultType()) {
     case Primitive::kPrimInt: {
-      locations->SetInAt(0, Location(R0));
-      locations->SetInAt(1, Location(R1));
-      locations->SetOut(Location(R0));
+      locations->SetInAt(0, ArmCoreLocation(R0));
+      locations->SetInAt(1, ArmCoreLocation(R1));
+      locations->SetOut(ArmCoreLocation(R0));
       break;
     }
+
+    case Primitive::kPrimLong: {
+      locations->SetInAt(
+          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      locations->SetInAt(
+          1, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R2_R3)));
+      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
   }
   add->SetLocations(locations);
 }
@@ -292,12 +555,29 @@
   LocationSummary* locations = add->GetLocations();
   switch (add->GetResultType()) {
     case Primitive::kPrimInt:
-      __ add(locations->Out().reg<Register>(),
-             locations->InAt(0).reg<Register>(),
-             ShifterOperand(locations->InAt(1).reg<Register>()));
+      __ add(locations->Out().AsArm().AsCoreRegister(),
+             locations->InAt(0).AsArm().AsCoreRegister(),
+             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
       break;
+
+    case Primitive::kPrimLong:
+      __ adds(locations->Out().AsArm().AsRegisterPairLow(),
+              locations->InAt(0).AsArm().AsRegisterPairLow(),
+              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
+      __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
+             locations->InAt(0).AsArm().AsRegisterPairHigh(),
+             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
+      break;
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
   }
 }
 
@@ -305,13 +585,30 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt: {
-      locations->SetInAt(0, Location(R0));
-      locations->SetInAt(1, Location(R1));
-      locations->SetOut(Location(R0));
+      locations->SetInAt(0, ArmCoreLocation(R0));
+      locations->SetInAt(1, ArmCoreLocation(R1));
+      locations->SetOut(ArmCoreLocation(R0));
       break;
     }
+
+    case Primitive::kPrimLong: {
+      locations->SetInAt(
+          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      locations->SetInAt(
+          1, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R2_R3)));
+      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
   }
   sub->SetLocations(locations);
 }
@@ -320,12 +617,29 @@
   LocationSummary* locations = sub->GetLocations();
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt:
-      __ sub(locations->Out().reg<Register>(),
-             locations->InAt(0).reg<Register>(),
-             ShifterOperand(locations->InAt(1).reg<Register>()));
+      __ sub(locations->Out().AsArm().AsCoreRegister(),
+             locations->InAt(0).AsArm().AsCoreRegister(),
+             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
       break;
+
+    case Primitive::kPrimLong:
+      __ subs(locations->Out().AsArm().AsRegisterPairLow(),
+              locations->InAt(0).AsArm().AsRegisterPairLow(),
+              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
+      __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
+             locations->InAt(0).AsArm().AsRegisterPairHigh(),
+             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
+      break;
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
   }
 }
 
@@ -345,7 +659,7 @@
 
 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetOut(Location(R0));
+  locations->SetOut(ArmCoreLocation(R0));
   instruction->SetLocations(locations);
 }
 
@@ -365,34 +679,55 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   InvokeDexCallingConvention calling_convention;
   uint32_t argument_index = instruction->GetIndex();
-  if (argument_index < calling_convention.GetNumberOfRegisters()) {
-    locations->SetOut(Location(calling_convention.GetRegisterAt(argument_index)));
-  } else {
-    locations->SetOut(Location(R0));
+  switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      if (argument_index < calling_convention.GetNumberOfRegisters()) {
+        locations->SetOut(ArmCoreLocation(calling_convention.GetRegisterAt(argument_index)));
+      } else {
+        locations->SetOut(Location::StackSlot(
+            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
+        locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
+            (calling_convention.GetRegisterPairAt(argument_index)))));
+      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
+        // Spanning a register and a stack slot. Use the quick parameter kind.
+        locations->SetOut(Location::QuickParameter(argument_index));
+      } else {
+        locations->SetOut(Location::DoubleStackSlot(
+            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
+      }
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented parameter type " << instruction->GetType();
   }
   instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  InvokeDexCallingConvention calling_convention;
-  uint8_t argument_index = instruction->GetIndex();
-  if (argument_index >= calling_convention.GetNumberOfRegisters()) {
-    uint8_t offset = calling_convention.GetStackOffsetOf(argument_index);
-    __ ldr(locations->Out().reg<Register>(), Address(SP, offset + codegen_->GetFrameSize()));
-  }
+  // Nothing to do, the parameter is already at its location.
 }
 
 void LocationsBuilderARM::VisitNot(HNot* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetInAt(0, Location(R0));
-  locations->SetOut(Location(R0));
+  locations->SetInAt(0, ArmCoreLocation(R0));
+  locations->SetOut(ArmCoreLocation(R0));
   instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  __ eor(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>(), ShifterOperand(1));
+  __ eor(locations->Out().AsArm().AsCoreRegister(),
+         locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
 }
 
 }  // namespace arm
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index a51d85e..3fbe631 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -24,11 +24,14 @@
 namespace art {
 namespace arm {
 
+class CodeGeneratorARM;
+
 static constexpr size_t kArmWordSize = 4;
 
 class LocationsBuilderARM : public HGraphVisitor {
  public:
-  explicit LocationsBuilderARM(HGraph* graph) : HGraphVisitor(graph) { }
+  explicit LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen)
+      : HGraphVisitor(graph), codegen_(codegen) {}
 
 #define DECLARE_VISIT_INSTRUCTION(name)     \
   virtual void Visit##name(H##name* instr);
@@ -38,11 +41,11 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  private:
+  CodeGeneratorARM* const codegen_;
+
   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM);
 };
 
-class CodeGeneratorARM;
-
 class InstructionCodeGeneratorARM : public HGraphVisitor {
  public:
   InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
@@ -68,7 +71,7 @@
  public:
   explicit CodeGeneratorARM(HGraph* graph)
       : CodeGenerator(graph),
-        location_builder_(graph),
+        location_builder_(graph, this),
         instruction_visitor_(graph, this) { }
   virtual ~CodeGeneratorARM() { }
 
@@ -96,6 +99,11 @@
   int32_t GetStackSlot(HLocal* local) const;
 
  private:
+  // Helper method to move a 32bits value between two locations.
+  void Move32(Location destination, Location source);
+  // Helper method to move a 64bits value between two locations.
+  void Move64(Location destination, Location source);
+
   LocationsBuilderARM location_builder_;
   InstructionCodeGeneratorARM instruction_visitor_;
   ArmAssembler assembler_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 88198dc..7507ee7 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -17,6 +17,7 @@
 #include "code_generator_x86.h"
 #include "utils/assembler.h"
 #include "utils/x86/assembler_x86.h"
+#include "utils/x86/managed_register_x86.h"
 
 #include "mirror/array.h"
 #include "mirror/art_method.h"
@@ -24,11 +25,20 @@
 #define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
 
 namespace art {
+
+x86::X86ManagedRegister Location::AsX86() const {
+  return reg().AsX86();
+}
+
 namespace x86 {
 
 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
 static constexpr int kCurrentMethodStackOffset = 0;
 
+static Location X86CpuLocation(Register reg) {
+  return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
+}
+
 InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
       : HGraphVisitor(graph),
         assembler_(codegen->GetAssembler()),
@@ -77,18 +87,163 @@
   }
 }
 
+static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
+static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX };
+static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+
+class InvokeDexCallingConvention : public CallingConvention<Register> {
+ public:
+  InvokeDexCallingConvention()
+      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
+
+  RegisterPair GetRegisterPairAt(size_t argument_index) {
+    DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
+    return kParameterCorePairRegisters[argument_index];
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
+};
+
+void CodeGeneratorX86::Move32(Location destination, Location source) {
+  if (source.Equals(destination)) {
+    return;
+  }
+  if (destination.IsRegister()) {
+    if (source.IsRegister()) {
+      __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+    } else {
+      DCHECK(source.IsStackSlot());
+      __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
+    }
+  } else {
+    if (source.IsRegister()) {
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
+    } else {
+      DCHECK(source.IsStackSlot());
+      __ movl(EAX, Address(ESP, source.GetStackIndex()));
+      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
+    }
+  }
+}
+
+void CodeGeneratorX86::Move64(Location destination, Location source) {
+  if (source.Equals(destination)) {
+    return;
+  }
+  if (destination.IsRegister()) {
+    if (source.IsRegister()) {
+      __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow());
+      __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh());
+    } else if (source.IsQuickParameter()) {
+      uint32_t argument_index = source.GetQuickParameterIndex();
+      InvokeDexCallingConvention calling_convention;
+      __ movl(destination.AsX86().AsRegisterPairLow(),
+              calling_convention.GetRegisterAt(argument_index));
+      __ movl(destination.AsX86().AsRegisterPairHigh(),
+              Address(ESP,
+                      calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex()));
+      __ movl(destination.AsX86().AsRegisterPairHigh(),
+              Address(ESP, source.GetHighStackIndex(kX86WordSize)));
+    }
+  } else if (destination.IsQuickParameter()) {
+    InvokeDexCallingConvention calling_convention;
+    uint32_t argument_index = destination.GetQuickParameterIndex();
+    if (source.IsRegister()) {
+      __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow());
+      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)),
+              source.AsX86().AsRegisterPairHigh());
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ movl(calling_convention.GetRegisterAt(argument_index),
+              Address(ESP, source.GetStackIndex()));
+      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
+      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)), EAX);
+    }
+  } else {
+    if (source.IsRegister()) {
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
+      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
+              source.AsX86().AsRegisterPairHigh());
+    } else if (source.IsQuickParameter()) {
+      InvokeDexCallingConvention calling_convention;
+      uint32_t argument_index = source.GetQuickParameterIndex();
+      __ movl(Address(ESP, destination.GetStackIndex()),
+              calling_convention.GetRegisterAt(argument_index));
+      __ movl(EAX,
+              Address(ESP,
+                      calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ movl(EAX, Address(ESP, source.GetStackIndex()));
+      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
+      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
+      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
+    }
+  }
+}
+
 void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
   if (instruction->AsIntConstant() != nullptr) {
-    __ movl(location.reg<Register>(), Immediate(instruction->AsIntConstant()->GetValue()));
+    Immediate imm(instruction->AsIntConstant()->GetValue());
+    if (location.IsRegister()) {
+      __ movl(location.AsX86().AsCpuRegister(), imm);
+    } else {
+      __ movl(Address(ESP, location.GetStackIndex()), imm);
+    }
+  } else if (instruction->AsLongConstant() != nullptr) {
+    int64_t value = instruction->AsLongConstant()->GetValue();
+    if (location.IsRegister()) {
+      __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value)));
+      __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value)));
+    } else {
+      __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
+      __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
+    }
   } else if (instruction->AsLoadLocal() != nullptr) {
-    __ movl(location.reg<Register>(),
-            Address(ESP, GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+    switch (instruction->GetType()) {
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimNot:
+        Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+        break;
+
+      case Primitive::kPrimLong:
+        Move64(location, Location::DoubleStackSlot(
+            GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
+    }
   } else {
     // This can currently only happen when the instruction that requests the move
     // is the next to be compiled.
     DCHECK_EQ(instruction->GetNext(), move_for);
-    __ movl(location.reg<Register>(),
-            instruction->GetLocations()->Out().reg<Register>());
+    switch (instruction->GetType()) {
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimNot:
+        Move32(location, instruction->GetLocations()->Out());
+        break;
+
+      case Primitive::kPrimLong:
+        Move64(location, instruction->GetLocations()->Out());
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+    }
   }
 }
 
@@ -118,13 +273,13 @@
 
 void LocationsBuilderX86::VisitIf(HIf* if_instr) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
-  locations->SetInAt(0, Location(EAX));
+  locations->SetInAt(0, X86CpuLocation(EAX));
   if_instr->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
   // TODO: Generate the input as a condition, instead of materializing in a register.
-  __ cmpl(if_instr->GetLocations()->InAt(0).reg<Register>(), Immediate(0));
+  __ cmpl(if_instr->GetLocations()->InAt(0).AsX86().AsCpuRegister(), Immediate(0));
   __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
   if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
     __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
@@ -147,29 +302,43 @@
   // Nothing to do, this is driven by the code generator.
 }
 
-void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* local) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(local);
-  locations->SetInAt(1, Location(EAX));
-  local->SetLocations(locations);
+void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
+  switch (store->InputAt(1)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
+  }
+  store->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
-  __ movl(Address(ESP, codegen_->GetStackSlot(store->GetLocal())),
-          store->GetLocations()->InAt(1).reg<Register>());
 }
 
 void LocationsBuilderX86::VisitEqual(HEqual* equal) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
-  locations->SetInAt(0, Location(EAX));
-  locations->SetInAt(1, Location(ECX));
-  locations->SetOut(Location(EAX));
+  locations->SetInAt(0, X86CpuLocation(EAX));
+  locations->SetInAt(1, X86CpuLocation(ECX));
+  locations->SetOut(X86CpuLocation(EAX));
   equal->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) {
-  __ cmpl(equal->GetLocations()->InAt(0).reg<Register>(),
-          equal->GetLocations()->InAt(1).reg<Register>());
-  __ setb(kEqual, equal->GetLocations()->Out().reg<Register>());
+  __ cmpl(equal->GetLocations()->InAt(0).AsX86().AsCpuRegister(),
+          equal->GetLocations()->InAt(1).AsX86().AsCpuRegister());
+  __ setb(kEqual, equal->GetLocations()->Out().AsX86().AsCpuRegister());
 }
 
 void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
@@ -180,6 +349,14 @@
   // Will be generated at use site.
 }
 
+void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
+  constant->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
+  // Will be generated at use site.
+}
+
 void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
   ret->SetLocations(nullptr);
 }
@@ -191,28 +368,51 @@
 
 void LocationsBuilderX86::VisitReturn(HReturn* ret) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
-  locations->SetInAt(0, Location(EAX));
+  switch (ret->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetInAt(0, X86CpuLocation(EAX));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetInAt(
+          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+  }
   ret->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
-  DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), EAX);
+  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:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX);
+        break;
+
+      case Primitive::kPrimLong:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX);
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+    }
+  }
   codegen_->GenerateFrameExit();
   __ ret();
 }
 
-static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
-static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
-
-class InvokeDexCallingConvention : public CallingConvention<Register> {
- public:
-  InvokeDexCallingConvention()
-      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
-};
-
 static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     arraysize(kRuntimeParameterCoreRegisters);
@@ -230,39 +430,78 @@
 void LocationsBuilderX86::VisitPushArgument(HPushArgument* argument) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument);
   InvokeDexCallingConvention calling_convention;
-  if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) {
-    Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex()));
-    locations->SetInAt(0, location);
-    locations->SetOut(location);
-  } else {
-    locations->SetInAt(0, Location(EAX));
+  uint32_t argument_index = argument->GetArgumentIndex();
+  switch (argument->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      if (argument_index < calling_convention.GetNumberOfRegisters()) {
+        locations->SetInAt(
+            0, X86CpuLocation(calling_convention.GetRegisterAt(argument->GetArgumentIndex())));
+      } else {
+        locations->SetInAt(
+            0, Location::StackSlot(calling_convention.GetStackOffsetOf(argument_index)));
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
+        Location location = Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
+            calling_convention.GetRegisterPairAt(argument_index)));
+        locations->SetInAt(0, location);
+      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
+        locations->SetInAt(0, Location::QuickParameter(argument_index));
+      } else {
+        locations->SetInAt(
+            0, Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(argument_index)));
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unimplemented argument type " << argument->InputAt(0)->GetType();
   }
+
   argument->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitPushArgument(HPushArgument* argument) {
-  uint8_t argument_index = argument->GetArgumentIndex();
-  InvokeDexCallingConvention calling_convention;
-  size_t parameter_registers = calling_convention.GetNumberOfRegisters();
-  if (argument_index >= parameter_registers) {
-    uint8_t offset = calling_convention.GetStackOffsetOf(argument_index);
-    __ movl(Address(ESP, offset),
-            argument->GetLocations()->InAt(0).reg<Register>());
-
-  } else {
-    DCHECK_EQ(argument->GetLocations()->Out().reg<Register>(),
-              argument->GetLocations()->InAt(0).reg<Register>());
-  }
+  // Nothing to do.
 }
 
 void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
-  locations->AddTemp(Location(EAX));
+  locations->AddTemp(X86CpuLocation(EAX));
+  switch (invoke->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetOut(X86CpuLocation(EAX));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      break;
+
+    case Primitive::kPrimVoid:
+      break;
+
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat:
+      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
+      break;
+  }
+
   invoke->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>();
+  Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
   size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
       invoke->GetIndexInDexCache() * kX86WordSize;
 
@@ -289,13 +528,29 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
   switch (add->GetResultType()) {
     case Primitive::kPrimInt: {
-      locations->SetInAt(0, Location(EAX));
-      locations->SetInAt(1, Location(ECX));
-      locations->SetOut(Location(EAX));
+      locations->SetInAt(0, X86CpuLocation(EAX));
+      locations->SetInAt(1, X86CpuLocation(ECX));
+      locations->SetOut(X86CpuLocation(EAX));
       break;
     }
+    case Primitive::kPrimLong: {
+      locations->SetInAt(
+          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      locations->SetInAt(
+          1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX)));
+      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
   }
   add->SetLocations(locations);
 }
@@ -303,12 +558,33 @@
 void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
   LocationSummary* locations = add->GetLocations();
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt:
-      DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>());
-      __ addl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>());
+    case Primitive::kPrimInt: {
+      DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
+                locations->Out().AsX86().AsCpuRegister());
+      __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
+              locations->InAt(1).AsX86().AsCpuRegister());
       break;
+    }
+
+    case Primitive::kPrimLong: {
+      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
+                locations->Out().AsX86().AsRegisterPair());
+      __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
+              locations->InAt(1).AsX86().AsRegisterPairLow());
+      __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
+              locations->InAt(1).AsX86().AsRegisterPairHigh());
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
   }
 }
 
@@ -316,13 +592,30 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt: {
-      locations->SetInAt(0, Location(EAX));
-      locations->SetInAt(1, Location(ECX));
-      locations->SetOut(Location(EAX));
+      locations->SetInAt(0, X86CpuLocation(EAX));
+      locations->SetInAt(1, X86CpuLocation(ECX));
+      locations->SetOut(X86CpuLocation(EAX));
       break;
     }
+
+    case Primitive::kPrimLong: {
+      locations->SetInAt(
+          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      locations->SetInAt(
+          1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX)));
+      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
   }
   sub->SetLocations(locations);
 }
@@ -330,18 +623,39 @@
 void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
   LocationSummary* locations = sub->GetLocations();
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt:
-      DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>());
-      __ subl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>());
+    case Primitive::kPrimInt: {
+      DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
+                locations->Out().AsX86().AsCpuRegister());
+      __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
+              locations->InAt(1).AsX86().AsCpuRegister());
       break;
+    }
+
+    case Primitive::kPrimLong: {
+      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
+                locations->Out().AsX86().AsRegisterPair());
+      __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
+              locations->InAt(1).AsX86().AsRegisterPairLow());
+      __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
+              locations->InAt(1).AsX86().AsRegisterPairHigh());
+      break;
+    }
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+      break;
+
     default:
-      LOG(FATAL) << "Unimplemented";
+      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
   }
 }
 
 void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetOut(Location(EAX));
+  locations->SetOut(X86CpuLocation(EAX));
   instruction->SetLocations(locations);
 }
 
@@ -361,35 +675,54 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   InvokeDexCallingConvention calling_convention;
   uint32_t argument_index = instruction->GetIndex();
-  if (argument_index < calling_convention.GetNumberOfRegisters()) {
-    locations->SetOut(Location(calling_convention.GetRegisterAt(argument_index)));
-  } else {
-    locations->SetOut(Location(EAX));
+  switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      if (argument_index < calling_convention.GetNumberOfRegisters()) {
+        locations->SetOut(X86CpuLocation(calling_convention.GetRegisterAt(argument_index)));
+      } else {
+        locations->SetOut(Location::StackSlot(
+            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
+        locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
+            (calling_convention.GetRegisterPairAt(argument_index)))));
+      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
+        locations->SetOut(Location::QuickParameter(argument_index));
+      } else {
+        locations->SetOut(Location::DoubleStackSlot(
+            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
+      }
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented parameter type " << instruction->GetType();
   }
   instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  InvokeDexCallingConvention calling_convention;
-  uint32_t argument_index = instruction->GetIndex();
-  if (argument_index >= calling_convention.GetNumberOfRegisters()) {
-    uint8_t offset = calling_convention.GetStackOffsetOf(argument_index);
-    __ movl(locations->Out().reg<Register>(), Address(ESP, offset + codegen_->GetFrameSize()));
-  }
+  // Nothing to do, the parameter is already at its location.
 }
 
 void LocationsBuilderX86::VisitNot(HNot* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetInAt(0, Location(EAX));
-  locations->SetOut(Location(EAX));
+  locations->SetInAt(0, X86CpuLocation(EAX));
+  locations->SetOut(X86CpuLocation(EAX));
   instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>());
-  __ xorl(locations->Out().reg<Register>(), Immediate(1));
+  DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), locations->Out().AsX86().AsCpuRegister());
+  __ xorl(locations->Out().AsX86().AsCpuRegister(), Immediate(1));
 }
 
 }  // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index bba81c0..9108f80 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -26,9 +26,12 @@
 
 static constexpr size_t kX86WordSize = 4;
 
+class CodeGeneratorX86;
+
 class LocationsBuilderX86 : public HGraphVisitor {
  public:
-  explicit LocationsBuilderX86(HGraph* graph) : HGraphVisitor(graph) { }
+  LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen)
+      : HGraphVisitor(graph), codegen_(codegen) {}
 
 #define DECLARE_VISIT_INSTRUCTION(name)     \
   virtual void Visit##name(H##name* instr);
@@ -38,11 +41,11 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  private:
+  CodeGeneratorX86* const codegen_;
+
   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86);
 };
 
-class CodeGeneratorX86;
-
 class InstructionCodeGeneratorX86 : public HGraphVisitor {
  public:
   InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
@@ -69,7 +72,7 @@
  public:
   explicit CodeGeneratorX86(HGraph* graph)
       : CodeGenerator(graph),
-        location_builder_(graph),
+        location_builder_(graph, this),
         instruction_visitor_(graph, this) { }
   virtual ~CodeGeneratorX86() { }
 
@@ -97,6 +100,11 @@
   int32_t GetStackSlot(HLocal* local) const;
 
  private:
+  // Helper method to move a 32bits value between two locations.
+  void Move32(Location destination, Location source);
+  // Helper method to move a 64bits value between two locations.
+  void Move64(Location destination, Location source);
+
   LocationsBuilderX86 location_builder_;
   InstructionCodeGeneratorX86 instruction_visitor_;
   X86Assembler assembler_;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index adea0ba..d7e74f8 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -226,6 +226,7 @@
   M(InvokeStatic)                                          \
   M(LoadLocal)                                             \
   M(Local)                                                 \
+  M(LongConstant)                                          \
   M(NewInstance)                                           \
   M(Not)                                                   \
   M(ParameterValue)                                        \
@@ -283,6 +284,8 @@
   virtual void Accept(HGraphVisitor* visitor) = 0;
   virtual const char* DebugName() const = 0;
 
+  virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; }
+
   void AddUse(HInstruction* user) {
     uses_ = new (block_->GetGraph()->GetArena()) HUseListNode(user, uses_);
   }
@@ -534,6 +537,7 @@
   Primitive::Type GetResultType() const { return result_type_; }
 
   virtual bool IsCommutative() { return false; }
+  virtual Primitive::Type GetType() const { return GetResultType(); }
 
  private:
   const Primitive::Type result_type_;
@@ -550,6 +554,8 @@
 
   virtual bool IsCommutative() { return true; }
 
+  virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; }
+
   DECLARE_INSTRUCTION(Equal)
 
  private:
@@ -575,15 +581,19 @@
 // Load a given local. The local is an input of this instruction.
 class HLoadLocal : public HTemplateInstruction<1> {
  public:
-  explicit HLoadLocal(HLocal* local) {
+  explicit HLoadLocal(HLocal* local, Primitive::Type type) : type_(type) {
     SetRawInputAt(0, local);
   }
 
+  virtual Primitive::Type GetType() const { return type_; }
+
   HLocal* GetLocal() const { return reinterpret_cast<HLocal*>(InputAt(0)); }
 
   DECLARE_INSTRUCTION(LoadLocal)
 
  private:
+  const Primitive::Type type_;
+
   DISALLOW_COPY_AND_ASSIGN(HLoadLocal);
 };
 
@@ -611,6 +621,7 @@
   explicit HIntConstant(int32_t value) : value_(value) { }
 
   int32_t GetValue() const { return value_; }
+  virtual Primitive::Type GetType() const { return Primitive::kPrimInt; }
 
   DECLARE_INSTRUCTION(IntConstant)
 
@@ -620,10 +631,30 @@
   DISALLOW_COPY_AND_ASSIGN(HIntConstant);
 };
 
+class HLongConstant : public HTemplateInstruction<0> {
+ public:
+  explicit HLongConstant(int64_t value) : value_(value) { }
+
+  int64_t GetValue() const { return value_; }
+
+  virtual Primitive::Type GetType() const { return Primitive::kPrimLong; }
+
+  DECLARE_INSTRUCTION(LongConstant)
+
+ private:
+  const int64_t value_;
+
+  DISALLOW_COPY_AND_ASSIGN(HLongConstant);
+};
+
 class HInvoke : public HInstruction {
  public:
-  HInvoke(ArenaAllocator* arena, uint32_t number_of_arguments, uint32_t dex_pc)
+  HInvoke(ArenaAllocator* arena,
+          uint32_t number_of_arguments,
+          Primitive::Type return_type,
+          uint32_t dex_pc)
     : inputs_(arena, number_of_arguments),
+      return_type_(return_type),
       dex_pc_(dex_pc) {
     inputs_.SetSize(number_of_arguments);
   }
@@ -635,10 +666,13 @@
     inputs_.Put(index, argument);
   }
 
+  virtual Primitive::Type GetType() const { return return_type_; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
  protected:
   GrowableArray<HInstruction*> inputs_;
+  const Primitive::Type return_type_;
   const uint32_t dex_pc_;
 
  private:
@@ -649,9 +683,11 @@
  public:
   HInvokeStatic(ArenaAllocator* arena,
                 uint32_t number_of_arguments,
+                Primitive::Type return_type,
                 uint32_t dex_pc,
                 uint32_t index_in_dex_cache)
-      : HInvoke(arena, number_of_arguments, dex_pc), index_in_dex_cache_(index_in_dex_cache) {}
+      : HInvoke(arena, number_of_arguments, return_type, dex_pc),
+        index_in_dex_cache_(index_in_dex_cache) {}
 
   uint32_t GetIndexInDexCache() const { return index_in_dex_cache_; }
 
@@ -670,6 +706,8 @@
   uint32_t GetDexPc() const { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
 
+  virtual Primitive::Type GetType() const { return Primitive::kPrimNot; }
+
   DECLARE_INSTRUCTION(NewInstance)
 
  private:
@@ -727,10 +765,13 @@
 // the calling convention.
 class HParameterValue : public HTemplateInstruction<0> {
  public:
-  explicit HParameterValue(uint8_t index) : index_(index) {}
+  HParameterValue(uint8_t index, Primitive::Type parameter_type)
+      : index_(index), parameter_type_(parameter_type) {}
 
   uint8_t GetIndex() const { return index_; }
 
+  virtual Primitive::Type GetType() const { return parameter_type_; }
+
   DECLARE_INSTRUCTION(ParameterValue);
 
  private:
@@ -738,6 +779,8 @@
   // than HGraph::number_of_in_vregs_;
   const uint8_t index_;
 
+  const Primitive::Type parameter_type_;
+
   DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
@@ -747,6 +790,8 @@
     SetRawInputAt(0, input);
   }
 
+  virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; }
+
   DECLARE_INSTRUCTION(Not);
 
  private:
diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h
index f007d28..0d31322 100644
--- a/compiler/utils/managed_register.h
+++ b/compiler/utils/managed_register.h
@@ -70,11 +70,13 @@
     return ManagedRegister();
   }
 
+  int RegId() const { return id_; }
+  explicit ManagedRegister(int reg_id) : id_(reg_id) { }
+
  protected:
   static const int kNoRegister = -1;
 
   ManagedRegister() : id_(kNoRegister) { }
-  explicit ManagedRegister(int reg_id) : id_(reg_id) { }
 
   int id_;
 };
diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc
index 7fae7a8..034a795 100644
--- a/compiler/utils/x86/managed_register_x86.cc
+++ b/compiler/utils/x86/managed_register_x86.cc
@@ -33,7 +33,8 @@
   P(EDX, EDI)                 \
   P(ECX, EBX)                 \
   P(ECX, EDI)                 \
-  P(EBX, EDI)
+  P(EBX, EDI)                 \
+  P(ECX, EDX)
 
 
 struct RegisterPairDescriptor {
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index 0201a96..09d2b49 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -37,7 +37,8 @@
   ECX_EBX = 7,
   ECX_EDI = 8,
   EBX_EDI = 9,
-  kNumberOfRegisterPairs = 10,
+  ECX_EDX = 10,  // Dalvik style passing
+  kNumberOfRegisterPairs = 11,
   kNoRegisterPair = -1,
 };
 
@@ -121,6 +122,12 @@
     return FromRegId(AllocIdHigh()).AsCpuRegister();
   }
 
+  RegisterPair AsRegisterPair() const {
+    CHECK(IsRegisterPair());
+    return static_cast<RegisterPair>(id_ -
+        (kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds));
+  }
+
   bool IsCpuRegister() const {
     CHECK(IsValidManagedRegister());
     return (0 <= id_) && (id_ < kNumberOfCpuRegIds);
diff --git a/runtime/base/bit_field.h b/runtime/base/bit_field.h
new file mode 100644
index 0000000..e041bd0
--- /dev/null
+++ b/runtime/base/bit_field.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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_BASE_BIT_FIELD_H_
+#define ART_RUNTIME_BASE_BIT_FIELD_H_
+
+#include "globals.h"
+#include "logging.h"
+
+namespace art {
+
+static const uword kUwordOne = 1U;
+
+// BitField is a template for encoding and decoding a bit field inside
+// an unsigned machine word.
+template<typename T, int position, int size>
+class BitField {
+ public:
+  // Tells whether the provided value fits into the bit field.
+  static bool IsValid(T value) {
+    return (static_cast<uword>(value) & ~((kUwordOne << size) - 1)) == 0;
+  }
+
+  // Returns a uword mask of the bit field.
+  static uword Mask() {
+    return (kUwordOne << size) - 1;
+  }
+
+  // Returns a uword mask of the bit field which can be applied directly to
+  // the raw unshifted bits.
+  static uword MaskInPlace() {
+    return ((kUwordOne << size) - 1) << position;
+  }
+
+  // Returns the shift count needed to right-shift the bit field to
+  // the least-significant bits.
+  static int Shift() {
+    return position;
+  }
+
+  // Returns the size of the bit field.
+  static int BitSize() {
+    return size;
+  }
+
+  // Returns a uword with the bit field value encoded.
+  static uword Encode(T value) {
+    DCHECK(IsValid(value));
+    return static_cast<uword>(value) << position;
+  }
+
+  // Extracts the bit field from the value.
+  static T Decode(uword value) {
+    return static_cast<T>((value >> position) & ((kUwordOne << size) - 1));
+  }
+
+  // Returns a uword with the bit field value encoded based on the
+  // original value. Only the bits corresponding to this bit field
+  // will be changed.
+  static uword Update(T value, uword original) {
+    DCHECK(IsValid(value));
+    return (static_cast<uword>(value) << position) |
+        (~MaskInPlace() & original);
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_BIT_FIELD_H_
diff --git a/runtime/base/bit_field_test.cc b/runtime/base/bit_field_test.cc
new file mode 100644
index 0000000..afeb2c4
--- /dev/null
+++ b/runtime/base/bit_field_test.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 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 "bit_field.h"
+#include "globals.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(BitFields, Test1) {
+  class TestBitFields : public BitField<int32_t, 1, 8> {};
+  ASSERT_TRUE(TestBitFields::IsValid(16));
+  ASSERT_TRUE(!TestBitFields::IsValid(256));
+  ASSERT_EQ(0x00ffU, TestBitFields::Mask());
+  ASSERT_EQ(0x001feU, TestBitFields::MaskInPlace());
+  ASSERT_EQ(1, TestBitFields::Shift());
+  ASSERT_EQ(8, TestBitFields::BitSize());
+  ASSERT_EQ(32U, TestBitFields::Encode(16));
+  ASSERT_EQ(16, TestBitFields::Decode(32));
+  ASSERT_EQ(2U, TestBitFields::Update(1, 16));
+}
+
+}  // namespace art
diff --git a/test/403-optimizing-long/expected.txt b/test/403-optimizing-long/expected.txt
new file mode 100644
index 0000000..dff83cf
--- /dev/null
+++ b/test/403-optimizing-long/expected.txt
@@ -0,0 +1 @@
+Long: 42
diff --git a/test/403-optimizing-long/info.txt b/test/403-optimizing-long/info.txt
new file mode 100644
index 0000000..dc2d668
--- /dev/null
+++ b/test/403-optimizing-long/info.txt
@@ -0,0 +1 @@
+Tests long support on optimizing compiler.
diff --git a/test/403-optimizing-long/src/Main.java b/test/403-optimizing-long/src/Main.java
new file mode 100644
index 0000000..21af4e1
--- /dev/null
+++ b/test/403-optimizing-long/src/Main.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+
+public class Main {
+  public static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    long l = $opt$ReturnLong();
+    expectEquals(42, l);
+    System.out.println("Long: " + l);
+
+    l = $opt$TakeOneLong1(42);
+    expectEquals(42, l);
+
+    l = $opt$TakeOneLong2(0, 42);
+    expectEquals(42, l);
+
+    l = $opt$TakeOneLong3(0, 1, 42);
+    expectEquals(42, l);
+
+    l = $opt$TakeOneLong4(0, 1, 2, 42);
+    expectEquals(42, l);
+
+    l = $opt$AddTwoLongs(42, 41);
+    expectEquals(83, l);
+
+    l = $opt$SubTwoLongs(42, 41);
+    expectEquals(1, l);
+
+    l = $opt$MakeCallsWithLongs1();
+    expectEquals(57, l);
+
+    l = $opt$MakeCallsWithLongs2();
+    expectEquals(900000000006L, l);
+
+    l = $opt$SubTwoLongs(-600000000006L, -200000000002L);
+    expectEquals(-400000000004L, l);
+
+    l = $opt$AddTwoLongs(-600000000006L, -200000000002L);
+    expectEquals(-800000000008L, l);
+  }
+
+  static long $opt$MakeCallsWithLongs1() {
+    long l = $opt$SubTwoLongs(-600000000006L, -200000000002L);
+    expectEquals(-400000000004L, l);
+
+    l = $opt$AddTwoLongs(-600000000006L, -200000000002L);
+    expectEquals(-800000000008L, l);
+
+    return $opt$ReturnLong() + $opt$TakeOneLong1(1) + $opt$TakeOneLong2(0, 2)
+        + $opt$TakeOneLong3(0, 0, 3) + $opt$TakeOneLong4(0, 0, 0, 4)
+        // Test invoke-range.
+        + $opt$TakeOneLong5(0, 0, 0, 0, 5);
+  }
+
+  static long $opt$MakeCallsWithLongs2() {
+    return $opt$AddThreeLongs(400000000003L, 200000000002L, 300000000001L);
+  }
+
+  static long $opt$ReturnLong() {
+    return 42;
+  }
+
+  static long $opt$TakeOneLong1(long l) {
+    return l;
+  }
+
+  static long $opt$TakeOneLong2(int a, long l) {
+    return l;
+  }
+
+  static long $opt$TakeOneLong3(int a, int b, long l) {
+    return l;
+  }
+
+  static long $opt$TakeOneLong4(int a, int b, int c, long l) {
+    return l;
+  }
+
+  static long $opt$TakeOneLong5(int a, int b, int c,int d,  long l) {
+    return l;
+  }
+
+  static long $opt$AddTwoLongs(long a, long b) {
+    return a + b;
+  }
+
+  static long $opt$AddThreeLongs(long a, long b, long c) {
+    return a + b + c;
+  }
+
+  static long $opt$SubTwoLongs(long a, long b) {
+    return a - b;
+  }
+}