Opt compiler: Add support for more IRs on arm64.

Change-Id: I4b6425135d1af74912a206411288081d2516f8bf
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 5432882..fc9bdba 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -48,18 +48,28 @@
   return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
 }
 
+bool IsIntegralType(Primitive::Type type) {
+  switch (type) {
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      return true;
+    default:
+      return false;
+  }
+}
+
 bool Is64BitType(Primitive::Type type) {
   return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
 }
 
 // Convenience helpers to ease conversion to and from VIXL operands.
+static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
+              "Unexpected values for register codes.");
 
 int VIXLRegCodeFromART(int code) {
-  // TODO: static check?
-  DCHECK_EQ(SP, 31);
-  DCHECK_EQ(WSP, 31);
-  DCHECK_EQ(XZR, 32);
-  DCHECK_EQ(WZR, 32);
   if (code == SP) {
     return vixl::kSPRegInternalCode;
   }
@@ -70,11 +80,6 @@
 }
 
 int ARTRegCodeFromVIXL(int code) {
-  // TODO: static check?
-  DCHECK_EQ(SP, 31);
-  DCHECK_EQ(WSP, 31);
-  DCHECK_EQ(XZR, 32);
-  DCHECK_EQ(WZR, 32);
   if (code == vixl::kSPRegInternalCode) {
     return SP;
   }
@@ -128,6 +133,17 @@
                         instr->InputAt(input_index)->GetType());
 }
 
+CPURegister OutputCPURegister(HInstruction* instr) {
+  return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
+                                    : static_cast<CPURegister>(OutputRegister(instr));
+}
+
+CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
+  return IsFPType(instr->InputAt(index)->GetType())
+      ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
+      : static_cast<CPURegister>(InputRegisterAt(instr, index));
+}
+
 int64_t Int64ConstantFrom(Location location) {
   HConstant* instr = location.GetConstant();
   return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
@@ -151,14 +167,18 @@
   return MemOperand(sp, location.GetStackIndex());
 }
 
-MemOperand HeapOperand(const Register& base, Offset offset) {
+MemOperand HeapOperand(const Register& base, size_t offset) {
   // A heap reference must be 32bit, so fit in a W register.
   DCHECK(base.IsW());
-  return MemOperand(base.X(), offset.SizeValue());
+  return MemOperand(base.X(), offset);
 }
 
-MemOperand HeapOperandFrom(Location location, Primitive::Type type, Offset offset) {
-  return HeapOperand(RegisterFrom(location, type), offset);
+MemOperand HeapOperand(const Register& base, Offset offset) {
+  return HeapOperand(base, offset.SizeValue());
+}
+
+MemOperand HeapOperandFrom(Location location, Offset offset) {
+  return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
 }
 
 Location LocationFrom(const Register& reg) {
@@ -227,7 +247,8 @@
   return ARM64ReturnLocation(return_type);
 }
 
-#define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_->
+#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
 
 class SlowPathCodeARM64 : public SlowPathCode {
  public:
@@ -245,45 +266,125 @@
 
 class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
  public:
-  explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
-                                    Location index_location,
-                                    Location length_location)
-      : instruction_(instruction),
-        index_location_(index_location),
-        length_location_(length_location) {}
+  BoundsCheckSlowPathARM64() {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorARM64* arm64_codegen = reinterpret_cast<CodeGeneratorARM64*>(codegen);
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     __ Bind(GetEntryLabel());
-    InvokeRuntimeCallingConvention calling_convention;
-    arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(0)),
-                              index_location_, Primitive::kPrimInt);
-    arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(1)),
-                              length_location_, Primitive::kPrimInt);
-    size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowArrayBounds).SizeValue();
-    __ Ldr(lr, MemOperand(tr, offset));
-    __ Blr(lr);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    __ Brk(__LINE__);  // TODO: Unimplemented BoundsCheckSlowPathARM64.
   }
 
  private:
-  HBoundsCheck* const instruction_;
-  const Location index_location_;
-  const Location length_location_;
-
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
 };
 
+class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HDivZeroCheck* const instruction_;
+  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
+};
+
+class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  LoadClassSlowPathARM64(HLoadClass* cls,
+                         HInstruction* at,
+                         uint32_t dex_pc,
+                         bool do_clinit)
+      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+  }
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = at_->GetLocations();
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+    arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
+    int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
+                                            : QUICK_ENTRY_POINT(pInitializeType);
+    arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
+
+    // Move the class to the desired location.
+    Location out = locations->Out();
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      Primitive::Type type = at_->GetType();
+      arm64_codegen->MoveHelper(out, calling_convention.GetReturnLocation(type), type);
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ B(GetExitLabel());
+  }
+
+ private:
+  // The class this slow path will load.
+  HLoadClass* const cls_;
+
+  // The instruction where this slow path is happening.
+  // (Might be the load class or an initialization check).
+  HInstruction* const at_;
+
+  // The dex PC of `at_`.
+  const uint32_t dex_pc_;
+
+  // Whether to initialize the class.
+  const bool do_clinit_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
+};
+
+class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W());
+    __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
+    Primitive::Type type = instruction_->GetType();
+    arm64_codegen->MoveHelper(locations->Out(), calling_convention.GetReturnLocation(type), type);
+
+    codegen->RestoreLiveRegisters(locations);
+    __ B(GetExitLabel());
+  }
+
+ private:
+  HLoadString* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
+};
+
 class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
  public:
   explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
     __ Bind(GetEntryLabel());
-    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowNullPointer).Int32Value();
-    __ Ldr(lr, MemOperand(tr, offset));
-    __ Blr(lr);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
   }
 
  private:
@@ -298,13 +399,18 @@
                                      HBasicBlock* successor)
       : instruction_(instruction), successor_(successor) {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pTestSuspend).SizeValue();
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
     __ Bind(GetEntryLabel());
-    __ Ldr(lr, MemOperand(tr, offset));
-    __ Blr(lr);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
-    __ B(GetReturnLabel());
+    codegen->SaveLiveRegisters(instruction_->GetLocations());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
+    codegen->RestoreLiveRegisters(instruction_->GetLocations());
+    if (successor_ == nullptr) {
+      __ B(GetReturnLabel());
+    } else {
+      __ B(arm64_codegen->GetLabelOf(successor_));
+    }
   }
 
   vixl::Label* GetReturnLabel() {
@@ -324,6 +430,20 @@
   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
 };
 
+class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  TypeCheckSlowPathARM64() {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    __ Brk(__LINE__);  // TODO: Unimplemented TypeCheckSlowPathARM64.
+    __ b(GetExitLabel());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
+};
+
 #undef __
 
 Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
@@ -356,11 +476,12 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this) {}
 
-#define __ reinterpret_cast<Arm64Assembler*>(GetAssembler())->vixl_masm_->
+#undef __
+#define __ GetVIXLAssembler()->
 
 void CodeGeneratorARM64::GenerateFrameEntry() {
   // TODO: Add proper support for the stack overflow check.
-  UseScratchRegisterScope temps(assembler_.vixl_masm_);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
   Register temp = temps.AcquireX();
   __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
   __ Ldr(temp, MemOperand(temp, 0));
@@ -378,7 +499,7 @@
   // ...                       : other preserved registers.
   // sp[frame_size - regs_size]: first preserved register.
   // ...                       : reserved frame space.
-  // sp[0]                     : context pointer.
+  // sp[0]                     : current method.
 }
 
 void CodeGeneratorARM64::GenerateFrameExit() {
@@ -413,7 +534,7 @@
       __ Mov(dst, value);
     } else {
       DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
-      UseScratchRegisterScope temps(assembler_.vixl_masm_);
+      UseScratchRegisterScope temps(GetVIXLAssembler());
       Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
       __ Mov(temp, value);
       __ Str(temp, StackOperandFrom(location));
@@ -465,7 +586,7 @@
 }
 
 void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
-  UseScratchRegisterScope temps(assembler_.vixl_masm_);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
   Register card = temps.AcquireX();
   Register temp = temps.AcquireX();
   vixl::Label done;
@@ -522,6 +643,19 @@
   stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
 }
 
+void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
+  if (constant->IsIntConstant() || constant->IsLongConstant()) {
+    __ Mov(Register(destination),
+           constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
+                                     : constant->AsLongConstant()->GetValue());
+  } else if (constant->IsFloatConstant()) {
+    __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
+  } else {
+    DCHECK(constant->IsDoubleConstant());
+    __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
+  }
+}
+
 void CodeGeneratorARM64::MoveHelper(Location destination,
                                     Location source,
                                     Primitive::Type type) {
@@ -544,13 +678,7 @@
     } else if (source.IsFpuRegister()) {
       __ Fmov(dst, FPRegisterFrom(source, type));
     } else {
-      HConstant* cst = source.GetConstant();
-      if (cst->IsFloatConstant()) {
-        __ Fmov(dst, cst->AsFloatConstant()->GetValue());
-      } else {
-        DCHECK(cst->IsDoubleConstant());
-        __ Fmov(dst, cst->AsDoubleConstant()->GetValue());
-      }
+      MoveConstant(dst, source.GetConstant());
     }
   } else {
     DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
@@ -558,8 +686,21 @@
       __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
     } else if (source.IsFpuRegister()) {
       __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
+    } else if (source.IsConstant()) {
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      HConstant* cst = source.GetConstant();
+      CPURegister temp;
+      if (cst->IsIntConstant() || cst->IsLongConstant()) {
+        temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+      } else {
+        DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant());
+        temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD();
+      }
+      MoveConstant(temp, cst);
+      __ Str(temp, StackOperandFrom(destination));
     } else {
-      UseScratchRegisterScope temps(assembler_.vixl_masm_);
+      DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
+      UseScratchRegisterScope temps(GetVIXLAssembler());
       Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
       __ Ldr(temp, StackOperandFrom(source));
       __ Str(temp, StackOperandFrom(destination));
@@ -568,61 +709,89 @@
 }
 
 void CodeGeneratorARM64::Load(Primitive::Type type,
-                              vixl::Register dst,
+                              vixl::CPURegister dst,
                               const vixl::MemOperand& src) {
   switch (type) {
     case Primitive::kPrimBoolean:
-      __ Ldrb(dst, src);
+      __ Ldrb(Register(dst), src);
       break;
     case Primitive::kPrimByte:
-      __ Ldrsb(dst, src);
+      __ Ldrsb(Register(dst), src);
       break;
     case Primitive::kPrimShort:
-      __ Ldrsh(dst, src);
+      __ Ldrsh(Register(dst), src);
       break;
     case Primitive::kPrimChar:
-      __ Ldrh(dst, src);
+      __ Ldrh(Register(dst), src);
       break;
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
     case Primitive::kPrimLong:
-      DCHECK(dst.Is64Bits() == (type == Primitive::kPrimLong));
-      __ Ldr(dst, src);
-      break;
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
+      DCHECK(dst.Is64Bits() == Is64BitType(type));
+      __ Ldr(dst, src);
+      break;
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 }
 
 void CodeGeneratorARM64::Store(Primitive::Type type,
-                               vixl::Register rt,
+                               vixl::CPURegister rt,
                                const vixl::MemOperand& dst) {
   switch (type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
-      __ Strb(rt, dst);
+      __ Strb(Register(rt), dst);
       break;
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
-      __ Strh(rt, dst);
+      __ Strh(Register(rt), dst);
       break;
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
     case Primitive::kPrimLong:
-      DCHECK(rt.Is64Bits() == (type == Primitive::kPrimLong));
-      __ Str(rt, dst);
-      break;
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
+      DCHECK(rt.Is64Bits() == Is64BitType(type));
+      __ Str(rt, dst);
+      break;
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 }
 
-#undef __
-#define __ GetAssembler()->vixl_masm_->
+void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
+  DCHECK(current_method.IsW());
+  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+}
+
+void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
+                                       HInstruction* instruction,
+                                       uint32_t dex_pc) {
+  __ Ldr(lr, MemOperand(tr, entry_point_offset));
+  __ Blr(lr);
+  RecordPcInfo(instruction, dex_pc);
+  DCHECK(instruction->IsSuspendCheck()
+      || instruction->IsBoundsCheck()
+      || instruction->IsNullCheck()
+      || instruction->IsDivZeroCheck()
+      || !IsLeafMethod());
+}
+
+void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
+                                                                     vixl::Register class_reg) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireW();
+  __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset()));
+  __ Cmp(temp, mirror::Class::kStatusInitialized);
+  __ B(lt, slow_path->GetEntryLabel());
+  // Even if the initialized flag is set, we may be in a situation where caches are not synced
+  // properly. Therefore, we do a memory fence.
+  __ Dmb(InnerShareable, BarrierAll);
+  __ Bind(slow_path->GetExitLabel());
+}
 
 InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
                                                              CodeGeneratorARM64* codegen)
@@ -631,28 +800,14 @@
         codegen_(codegen) {}
 
 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)              \
-  M(And)                                                   \
-  M(CheckCast)                                             \
-  M(ClinitCheck)                                           \
-  M(DivZeroCheck)                                          \
-  M(InstanceOf)                                            \
-  M(InvokeInterface)                                       \
-  M(LoadClass)                                             \
-  M(LoadException)                                         \
-  M(LoadString)                                            \
-  M(MonitorOperation)                                      \
-  M(Or)                                                    \
   M(ParallelMove)                                          \
-  M(Rem)                                                   \
-  M(StaticFieldGet)                                        \
-  M(StaticFieldSet)                                        \
-  M(Throw)                                                 \
-  M(TypeConversion)                                        \
-  M(Xor)                                                   \
+  M(Rem)
 
 #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
 
 enum UnimplementedInstructionBreakCode {
+  // Using a base helps identify when we hit such breakpoints.
+  UnimplementedInstructionBreakCodeBaseCode = 0x900,
 #define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
   FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
 #undef ENUM_UNIMPLEMENTED_INSTRUCTION
@@ -671,9 +826,9 @@
 #undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
 
 #undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
+#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
 
-void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) {
-  DCHECK(instr->IsAdd() || instr->IsSub());
+void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
   DCHECK_EQ(instr->InputCount(), 2U);
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
   Primitive::Type type = instr->GetResultType();
@@ -689,7 +844,7 @@
     case Primitive::kPrimDouble:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
-      locations->SetOut(Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
 
     default:
@@ -697,9 +852,7 @@
   }
 }
 
-void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) {
-  DCHECK(instr->IsAdd() || instr->IsSub());
-
+void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
   Primitive::Type type = instr->GetType();
 
   switch (type) {
@@ -710,8 +863,15 @@
       Operand rhs = InputOperandAt(instr, 1);
       if (instr->IsAdd()) {
         __ Add(dst, lhs, rhs);
-      } else {
+      } else if (instr->IsAnd()) {
+        __ And(dst, lhs, rhs);
+      } else if (instr->IsOr()) {
+        __ Orr(dst, lhs, rhs);
+      } else if (instr->IsSub()) {
         __ Sub(dst, lhs, rhs);
+      } else {
+        DCHECK(instr->IsXor());
+        __ Eor(dst, lhs, rhs);
       }
       break;
     }
@@ -722,22 +882,32 @@
       FPRegister rhs = InputFPRegisterAt(instr, 1);
       if (instr->IsAdd()) {
         __ Fadd(dst, lhs, rhs);
-      } else {
+      } else if (instr->IsSub()) {
         __ Fsub(dst, lhs, rhs);
+      } else {
+        LOG(FATAL) << "Unexpected floating-point binary operation";
       }
       break;
     }
     default:
-      LOG(FATAL) << "Unexpected add/sub type " << type;
+      LOG(FATAL) << "Unexpected binary operation type " << type;
   }
 }
 
 void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
-  HandleAddSub(instruction);
+  HandleBinaryOp(instruction);
 }
 
 void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
-  HandleAddSub(instruction);
+  HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
+  HandleBinaryOp(instruction);
 }
 
 void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
@@ -752,11 +922,10 @@
   LocationSummary* locations = instruction->GetLocations();
   Primitive::Type type = instruction->GetType();
   Register obj = InputRegisterAt(instruction, 0);
-  Register out = OutputRegister(instruction);
   Location index = locations->InAt(1);
   size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
   MemOperand source(obj);
-  UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
 
   if (index.IsConstant()) {
     offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
@@ -768,7 +937,7 @@
     source = MemOperand(temp, offset);
   }
 
-  codegen_->Load(type, out, source);
+  codegen_->Load(type, OutputCPURegister(instruction), source);
 }
 
 void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
@@ -802,18 +971,16 @@
 void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
   if (value_type == Primitive::kPrimNot) {
-    __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAputObject).Int32Value()));
-    __ Blr(lr);
-    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-    DCHECK(!codegen_->IsLeafMethod());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+
   } else {
     LocationSummary* locations = instruction->GetLocations();
     Register obj = InputRegisterAt(instruction, 0);
-    Register value = InputRegisterAt(instruction, 2);
+    CPURegister value = InputCPURegisterAt(instruction, 2);
     Location index = locations->InAt(1);
     size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
     MemOperand destination(obj);
-    UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
+    UseScratchRegisterScope temps(GetVIXLAssembler());
 
     if (index.IsConstant()) {
       offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
@@ -829,6 +996,66 @@
   }
 }
 
+void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+  BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64();
+  codegen_->AddSlowPath(slow_path);
+
+  __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
+  __ B(slow_path->GetEntryLabel(), hs);
+}
+
+void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register obj = InputRegisterAt(instruction, 0);;
+  Register cls = InputRegisterAt(instruction, 1);;
+  Register temp = temps.AcquireW();
+
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
+  codegen_->AddSlowPath(slow_path);
+
+  // TODO: avoid this check if we know obj is not null.
+  __ Cbz(obj, slow_path->GetExitLabel());
+  // Compare the class of `obj` with `cls`.
+  __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset()));
+  __ Cmp(temp, cls);
+  __ B(ne, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (check->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
+  // We assume the class is not null.
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+      check->GetLoadClass(), check, check->GetDexPc(), true);
+  codegen_->AddSlowPath(slow_path);
+  GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
+}
+
 void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -847,7 +1074,7 @@
       Register result = OutputRegister(instruction);
       Register left = InputRegisterAt(instruction, 0);
       Operand right = InputOperandAt(instruction, 1);
-      __ Subs(result, left, right);
+      __ Subs(result.X(), left, right);
       __ B(eq, &done);
       __ Mov(result, 1);
       __ Cneg(result, result, le);
@@ -894,6 +1121,7 @@
 void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }         \
 void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
 FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
+#undef DEFINE_CONDITION_VISITORS
 #undef FOR_EACH_CONDITION_INSTRUCTION
 
 void LocationsBuilderARM64::VisitDiv(HDiv* div) {
@@ -937,6 +1165,33 @@
   }
 }
 
+void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  SlowPathCodeARM64* slow_path =
+      new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
+  codegen_->AddSlowPath(slow_path);
+  Location value = instruction->GetLocations()->InAt(0);
+
+  if (value.IsConstant()) {
+    int64_t divisor = Int64ConstantFrom(value);
+    if (divisor == 0) {
+      __ B(slow_path->GetEntryLabel());
+    } else {
+      LOG(FATAL) << "Divisions by non-null constants should have been optimized away.";
+    }
+  } else {
+    __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
+  }
+}
+
 void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -956,7 +1211,7 @@
   UNUSED(exit);
   if (kIsDebugBuild) {
     down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
-    __ Brk(0);    // TODO: Introduce special markers for such code locations.
+    __ Brk(__LINE__);    // TODO: Introduce special markers for such code locations.
   }
 }
 
@@ -1039,7 +1294,7 @@
 void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   MemOperand field = MemOperand(InputRegisterAt(instruction, 0),
                                 instruction->GetFieldOffset().Uint32Value());
-  codegen_->Load(instruction->GetType(), OutputRegister(instruction), field);
+  codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
 }
 
 void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -1050,14 +1305,56 @@
 
 void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   Primitive::Type field_type = instruction->GetFieldType();
-  Register value = InputRegisterAt(instruction, 1);
+  CPURegister value = InputCPURegisterAt(instruction, 1);
   Register obj = InputRegisterAt(instruction, 0);
   codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value()));
   if (field_type == Primitive::kPrimNot) {
-    codegen_->MarkGCCard(obj, value);
+    codegen_->MarkGCCard(obj, Register(value));
   }
 }
 
+void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary::CallKind call_kind =
+      instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), true);  // The output does overlap inputs.
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = InputRegisterAt(instruction, 0);;
+  Register cls = InputRegisterAt(instruction, 1);;
+  Register out = OutputRegister(instruction);
+
+  vixl::Label done;
+
+  // Return 0 if `obj` is null.
+  // TODO: Avoid this check if we know `obj` is not null.
+  __ Mov(out, 0);
+  __ Cbz(obj, &done);
+
+  // Compare the class of `obj` with `cls`.
+  __ Ldr(out, MemOperand(obj, mirror::Object::ClassOffset().Int32Value()));
+  __ Cmp(out, cls);
+  if (instruction->IsClassFinal()) {
+    // Classes must be equal for the instanceof to succeed.
+    __ Cset(out, eq);
+  } else {
+    // If the classes are not equal, we go into a slow path.
+    DCHECK(locations->OnlyCallsOnSlowPath());
+    SlowPathCodeARM64* slow_path =
+        new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
+    codegen_->AddSlowPath(slow_path);
+    __ B(ne, slow_path->GetEntryLabel());
+    __ Mov(out, 1);
+    __ Bind(slow_path->GetExitLabel());
+  }
+
+  __ Bind(&done);
+}
+
 void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
   locations->SetOut(Location::ConstantLocation(constant));
@@ -1068,14 +1365,6 @@
   UNUSED(constant);
 }
 
-void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
-  HandleInvoke(invoke);
-}
-
-void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  HandleInvoke(invoke);
-}
-
 void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
@@ -1093,6 +1382,50 @@
   }
 }
 
+void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+  Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
+  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+  Location receiver = invoke->GetLocations()->InAt(0);
+  Offset class_offset = mirror::Object::ClassOffset();
+  Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset();
+
+  // The register ip1 is required to be used for the hidden argument in
+  // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
+  UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
+  scratch_scope.Exclude(ip1);
+  __ Mov(ip1, invoke->GetDexMethodIndex());
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ Ldr(temp, StackOperandFrom(receiver));
+    __ Ldr(temp, HeapOperand(temp, class_offset));
+  } else {
+    __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
+  }
+  // temp = temp->GetImtEntryAt(method_offset);
+  __ Ldr(temp, HeapOperand(temp, method_offset));
+  // lr = temp->GetEntryPoint();
+  __ Ldr(lr, HeapOperand(temp, entry_point));
+  // lr();
+  __ Blr(lr);
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
+  HandleInvoke(invoke);
+}
+
 void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
   Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
   // Make sure that ArtMethod* is passed in W0 as per the calling convention
@@ -1108,7 +1441,7 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   // temp = method;
-  __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset));
+  codegen_->LoadCurrentMethod(temp);
   // temp = temp->dex_cache_resolved_methods_;
   __ Ldr(temp, MemOperand(temp.X(),
                           mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
@@ -1139,8 +1472,7 @@
     __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue()));
   } else {
     DCHECK(receiver.IsRegister());
-    __ Ldr(temp.W(), HeapOperandFrom(receiver, Primitive::kPrimNot,
-                                     class_offset));
+    __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
   }
   // temp = temp->GetMethodAt(method_offset);
   __ Ldr(temp.W(), MemOperand(temp, method_offset));
@@ -1152,6 +1484,50 @@
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
+  LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
+                                                              : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
+  Register out = OutputRegister(cls);
+  if (cls->IsReferrersClass()) {
+    DCHECK(!cls->CanCallRuntime());
+    DCHECK(!cls->MustGenerateClinitCheck());
+    codegen_->LoadCurrentMethod(out);
+    __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
+  } else {
+    DCHECK(cls->CanCallRuntime());
+    codegen_->LoadCurrentMethod(out);
+    __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
+    __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+
+    SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+    codegen_->AddSlowPath(slow_path);
+    __ Cbz(out, slow_path->GetEntryLabel());
+    if (cls->MustGenerateClinitCheck()) {
+      GenerateClassInitializationCheck(slow_path, out);
+    } else {
+      __ Bind(slow_path->GetExitLabel());
+    }
+  }
+}
+
+void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
+  MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
+  __ Ldr(OutputRegister(instruction), exception);
+  __ Str(wzr, exception);
+}
+
 void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
   load->SetLocations(nullptr);
 }
@@ -1161,6 +1537,24 @@
   UNUSED(load);
 }
 
+void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
+  codegen_->AddSlowPath(slow_path);
+
+  Register out = OutputRegister(load);
+  codegen_->LoadCurrentMethod(out);
+  __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheStringsOffset()));
+  __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ Cbz(out, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
 void LocationsBuilderARM64::VisitLocal(HLocal* local) {
   local->SetLocations(nullptr);
 }
@@ -1179,6 +1573,20 @@
   UNUSED(constant);
 }
 
+void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  codegen_->InvokeRuntime(instruction->IsEnter()
+        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
+      instruction,
+      instruction->GetDexPc());
+}
+
 void LocationsBuilderARM64::VisitMul(HMul* mul) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
@@ -1194,7 +1602,7 @@
     case Primitive::kPrimDouble:
       locations->SetInAt(0, Location::RequiresFpuRegister());
       locations->SetInAt(1, Location::RequiresFpuRegister());
-      locations->SetOut(Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
 
     default:
@@ -1224,15 +1632,15 @@
       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   switch (neg->GetResultType()) {
     case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
-      locations->SetOut(Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
-    }
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
-      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
 
     default:
@@ -1249,7 +1657,7 @@
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
-      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
       break;
 
     default:
@@ -1274,14 +1682,10 @@
   DCHECK(type_index.Is(w0));
   Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
   DCHECK(current_method.Is(w1));
-  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+  codegen_->LoadCurrentMethod(current_method);
   __ Mov(type_index, instruction->GetTypeIndex());
-  int32_t quick_entrypoint_offset =
-      QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocArrayWithAccessCheck).Int32Value();
-  __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
-  __ Blr(lr);
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
 }
 
 void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
@@ -1299,14 +1703,10 @@
   DCHECK(type_index.Is(w0));
   Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
   DCHECK(current_method.Is(w1));
-  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+  codegen_->LoadCurrentMethod(current_method);
   __ Mov(type_index, instruction->GetTypeIndex());
-  int32_t quick_entrypoint_offset =
-      QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value();
-  __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
-  __ Blr(lr);
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
 }
 
 void LocationsBuilderARM64::VisitNot(HNot* instruction) {
@@ -1355,6 +1755,14 @@
   }
 }
 
+void LocationsBuilderARM64::VisitOr(HOr* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
+  HandleBinaryOp(instruction);
+}
+
 void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
@@ -1435,31 +1843,43 @@
 }
 
 void LocationsBuilderARM64::VisitSub(HSub* instruction) {
-  HandleAddSub(instruction);
+  HandleBinaryOp(instruction);
 }
 
 void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
-  HandleAddSub(instruction);
+  HandleBinaryOp(instruction);
 }
 
-void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  Register cls = InputRegisterAt(instruction, 0);
+  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+  codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), MemOperand(cls, offset));
+}
+
+void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
-void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
-      instruction, locations->InAt(0), locations->InAt(1));
-  codegen_->AddSlowPath(slow_path);
+void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  CPURegister value = InputCPURegisterAt(instruction, 1);
+  Register cls = InputRegisterAt(instruction, 0);
+  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+  Primitive::Type field_type = instruction->GetFieldType();
 
-  __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
-  __ B(slow_path->GetEntryLabel(), hs);
+  codegen_->Store(field_type, value, MemOperand(cls, offset));
+  if (field_type == Primitive::kPrimNot) {
+    codegen_->MarkGCCard(cls, Register(value));
+  }
 }
 
 void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
@@ -1486,5 +1906,74 @@
   UNUSED(temp);
 }
 
+void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type input_type = conversion->GetInputType();
+  Primitive::Type result_type = conversion->GetResultType();
+  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
+      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+    LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
+  }
+
+  if (IsFPType(input_type)) {
+    locations->SetInAt(0, Location::RequiresFpuRegister());
+  } else {
+    locations->SetInAt(0, Location::RequiresRegister());
+  }
+
+  if (IsFPType(result_type)) {
+    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+  } else {
+    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+
+  DCHECK_NE(input_type, result_type);
+
+  if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
+    int result_size = Primitive::ComponentSize(result_type);
+    int input_size = Primitive::ComponentSize(input_type);
+    int min_size = kBitsPerByte * std::min(result_size, input_size);
+    if ((result_type == Primitive::kPrimChar) ||
+        ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
+      __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
+    } else {
+      __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
+    }
+    return;
+  }
+
+  LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
+             << " to " << result_type;
+}
+
+void LocationsBuilderARM64::VisitXor(HXor* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+#undef __
+#undef QUICK_ENTRY_POINT
+
 }  // namespace arm64
 }  // namespace art