Merge V8 5.4.500.40

Test: Manual - built & ran d8
Change-Id: I4edfa2853d3e565b729723645395688ece3193f4
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc
index e1cf2a6..4ae282a 100644
--- a/src/compiler/arm/code-generator-arm.cc
+++ b/src/compiler/arm/code-generator-arm.cc
@@ -136,14 +136,25 @@
     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
   }
-};
 
+  FloatRegister InputFloat32Register(size_t index) {
+    return ToFloat32Register(instr_->InputAt(index));
+  }
+
+  FloatRegister OutputFloat32Register() {
+    return ToFloat32Register(instr_->Output());
+  }
+
+  FloatRegister ToFloat32Register(InstructionOperand* op) {
+    return LowDwVfpRegister::from_code(ToDoubleRegister(op).code()).low();
+  }
+};
 
 namespace {
 
-class OutOfLineLoadFloat final : public OutOfLineCode {
+class OutOfLineLoadFloat32 final : public OutOfLineCode {
  public:
-  OutOfLineLoadFloat(CodeGenerator* gen, SwVfpRegister result)
+  OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
       : OutOfLineCode(gen), result_(result) {}
 
   void Generate() final {
@@ -188,7 +199,8 @@
  public:
   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
                        Register value, Register scratch0, Register scratch1,
-                       RecordWriteMode mode)
+                       RecordWriteMode mode,
+                       UnwindingInfoWriter* unwinding_info_writer)
       : OutOfLineCode(gen),
         object_(object),
         index_(index),
@@ -197,11 +209,13 @@
         scratch0_(scratch0),
         scratch1_(scratch1),
         mode_(mode),
-        must_save_lr_(!gen->frame_access_state()->has_frame()) {}
+        must_save_lr_(!gen->frame_access_state()->has_frame()),
+        unwinding_info_writer_(unwinding_info_writer) {}
 
   OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
                        Register value, Register scratch0, Register scratch1,
-                       RecordWriteMode mode)
+                       RecordWriteMode mode,
+                       UnwindingInfoWriter* unwinding_info_writer)
       : OutOfLineCode(gen),
         object_(object),
         index_(no_reg),
@@ -210,7 +224,8 @@
         scratch0_(scratch0),
         scratch1_(scratch1),
         mode_(mode),
-        must_save_lr_(!gen->frame_access_state()->has_frame()) {}
+        must_save_lr_(!gen->frame_access_state()->has_frame()),
+        unwinding_info_writer_(unwinding_info_writer) {}
 
   void Generate() final {
     if (mode_ > RecordWriteMode::kValueIsPointer) {
@@ -227,6 +242,7 @@
     if (must_save_lr_) {
       // We need to save and restore lr if the frame was elided.
       __ Push(lr);
+      unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset());
     }
     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
                          remembered_set_action, save_fp_mode);
@@ -239,6 +255,7 @@
     __ CallStub(&stub);
     if (must_save_lr_) {
       __ Pop(lr);
+      unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
     }
   }
 
@@ -251,6 +268,7 @@
   Register const scratch1_;
   RecordWriteMode const mode_;
   bool must_save_lr_;
+  UnwindingInfoWriter* const unwinding_info_writer_;
 };
 
 
@@ -296,6 +314,10 @@
       return vs;
     case kNotOverflow:
       return vc;
+    case kPositiveOrZero:
+      return pl;
+    case kNegative:
+      return mi;
     default:
       break;
   }
@@ -409,23 +431,10 @@
 
 void CodeGenerator::AssembleDeconstructFrame() {
   __ LeaveFrame(StackFrame::MANUAL);
+  unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
 }
 
-void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
-  int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
-  if (sp_slot_delta > 0) {
-    __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
-  }
-  frame_access_state()->SetFrameAccessToDefault();
-}
-
-
-void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
-  int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
-  if (sp_slot_delta < 0) {
-    __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
-    frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
-  }
+void CodeGenerator::AssemblePrepareTailCall() {
   if (frame_access_state()->has_frame()) {
     if (FLAG_enable_embedded_constant_pool) {
       __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
@@ -461,6 +470,115 @@
   __ bind(&done);
 }
 
+namespace {
+
+void FlushPendingPushRegisters(MacroAssembler* masm,
+                               FrameAccessState* frame_access_state,
+                               ZoneVector<Register>* pending_pushes) {
+  switch (pending_pushes->size()) {
+    case 0:
+      break;
+    case 1:
+      masm->push((*pending_pushes)[0]);
+      break;
+    case 2:
+      masm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
+      break;
+    case 3:
+      masm->Push((*pending_pushes)[0], (*pending_pushes)[1],
+                 (*pending_pushes)[2]);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+  frame_access_state->IncreaseSPDelta(pending_pushes->size());
+  pending_pushes->resize(0);
+}
+
+void AddPendingPushRegister(MacroAssembler* masm,
+                            FrameAccessState* frame_access_state,
+                            ZoneVector<Register>* pending_pushes,
+                            Register reg) {
+  pending_pushes->push_back(reg);
+  if (pending_pushes->size() == 3 || reg.is(ip)) {
+    FlushPendingPushRegisters(masm, frame_access_state, pending_pushes);
+  }
+}
+
+void AdjustStackPointerForTailCall(
+    MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp,
+    ZoneVector<Register>* pending_pushes = nullptr,
+    bool allow_shrinkage = true) {
+  int current_sp_offset = state->GetSPToFPSlotCount() +
+                          StandardFrameConstants::kFixedSlotCountAboveFp;
+  int stack_slot_delta = new_slot_above_sp - current_sp_offset;
+  if (stack_slot_delta > 0) {
+    if (pending_pushes != nullptr) {
+      FlushPendingPushRegisters(masm, state, pending_pushes);
+    }
+    masm->sub(sp, sp, Operand(stack_slot_delta * kPointerSize));
+    state->IncreaseSPDelta(stack_slot_delta);
+  } else if (allow_shrinkage && stack_slot_delta < 0) {
+    if (pending_pushes != nullptr) {
+      FlushPendingPushRegisters(masm, state, pending_pushes);
+    }
+    masm->add(sp, sp, Operand(-stack_slot_delta * kPointerSize));
+    state->IncreaseSPDelta(stack_slot_delta);
+  }
+}
+
+}  // namespace
+
+void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
+                                              int first_unused_stack_slot) {
+  CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
+  ZoneVector<MoveOperands*> pushes(zone());
+  GetPushCompatibleMoves(instr, flags, &pushes);
+
+  if (!pushes.empty() &&
+      (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
+       first_unused_stack_slot)) {
+    ArmOperandConverter g(this, instr);
+    ZoneVector<Register> pending_pushes(zone());
+    for (auto move : pushes) {
+      LocationOperand destination_location(
+          LocationOperand::cast(move->destination()));
+      InstructionOperand source(move->source());
+      AdjustStackPointerForTailCall(
+          masm(), frame_access_state(),
+          destination_location.index() - pending_pushes.size(),
+          &pending_pushes);
+      if (source.IsStackSlot()) {
+        LocationOperand source_location(LocationOperand::cast(source));
+        __ ldr(ip, g.SlotToMemOperand(source_location.index()));
+        AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+                               ip);
+      } else if (source.IsRegister()) {
+        LocationOperand source_location(LocationOperand::cast(source));
+        AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+                               source_location.GetRegister());
+      } else if (source.IsImmediate()) {
+        AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+                               ip);
+      } else {
+        // Pushes of non-scalar data types is not supported.
+        UNIMPLEMENTED();
+      }
+      move->Eliminate();
+    }
+    FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes);
+  }
+  AdjustStackPointerForTailCall(masm(), frame_access_state(),
+                                first_unused_stack_slot, nullptr, false);
+}
+
+void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
+                                             int first_unused_stack_slot) {
+  AdjustStackPointerForTailCall(masm(), frame_access_state(),
+                                first_unused_stack_slot);
+}
+
 // Assembles an instruction after register allocation, producing machine code.
 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
     Instruction* instr) {
@@ -487,8 +605,6 @@
     }
     case kArchTailCallCodeObjectFromJSFunction:
     case kArchTailCallCodeObject: {
-      int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
-      AssembleDeconstructActivationRecord(stack_param_delta);
       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
                                          i.TempRegister(0), i.TempRegister(1),
@@ -503,15 +619,17 @@
         __ Jump(ip);
       }
       DCHECK_EQ(LeaveCC, i.OutputSBit());
+      unwinding_info_writer_.MarkBlockWillExit();
       frame_access_state()->ClearSPDelta();
+      frame_access_state()->SetFrameAccessToDefault();
       break;
     }
     case kArchTailCallAddress: {
-      int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
-      AssembleDeconstructActivationRecord(stack_param_delta);
       CHECK(!instr->InputAt(0)->IsImmediate());
       __ Jump(i.InputRegister(0));
+      unwinding_info_writer_.MarkBlockWillExit();
       frame_access_state()->ClearSPDelta();
+      frame_access_state()->SetFrameAccessToDefault();
       break;
     }
     case kArchCallJSFunction: {
@@ -539,8 +657,6 @@
         __ cmp(cp, kScratchReg);
         __ Assert(eq, kWrongFunctionContext);
       }
-      int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
-      AssembleDeconstructActivationRecord(stack_param_delta);
       if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
                                          i.TempRegister(0), i.TempRegister(1),
@@ -550,6 +666,7 @@
       __ Jump(ip);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       frame_access_state()->ClearSPDelta();
+      frame_access_state()->SetFrameAccessToDefault();
       break;
     }
     case kArchPrepareCallCFunction: {
@@ -560,7 +677,7 @@
       break;
     }
     case kArchPrepareTailCall:
-      AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
+      AssemblePrepareTailCall();
       break;
     case kArchCallCFunction: {
       int const num_parameters = MiscField::decode(instr->opcode());
@@ -590,6 +707,9 @@
     case kArchDebugBreak:
       __ stop("kArchDebugBreak");
       break;
+    case kArchImpossible:
+      __ Abort(kConversionFromImpossibleValue);
+      break;
     case kArchComment: {
       Address comment_string = i.InputExternalReference(0).address();
       __ RecordComment(reinterpret_cast<const char*>(comment_string));
@@ -646,14 +766,16 @@
           AddressingModeField::decode(instr->opcode());
       if (addressing_mode == kMode_Offset_RI) {
         int32_t index = i.InputInt32(1);
-        ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
-                                                scratch0, scratch1, mode);
+        ool = new (zone())
+            OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
+                                 mode, &unwinding_info_writer_);
         __ str(value, MemOperand(object, index));
       } else {
         DCHECK_EQ(kMode_Offset_RR, addressing_mode);
         Register index(i.InputRegister(1));
-        ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
-                                                scratch0, scratch1, mode);
+        ool = new (zone())
+            OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
+                                 mode, &unwinding_info_writer_);
         __ str(value, MemOperand(object, index));
       }
       __ CheckPageFlag(object, scratch0,
@@ -674,9 +796,24 @@
       __ add(i.OutputRegister(0), base, Operand(offset.offset()));
       break;
     }
+    case kIeee754Float64Acos:
+      ASSEMBLE_IEEE754_UNOP(acos);
+      break;
+    case kIeee754Float64Acosh:
+      ASSEMBLE_IEEE754_UNOP(acosh);
+      break;
+    case kIeee754Float64Asin:
+      ASSEMBLE_IEEE754_UNOP(asin);
+      break;
+    case kIeee754Float64Asinh:
+      ASSEMBLE_IEEE754_UNOP(asinh);
+      break;
     case kIeee754Float64Atan:
       ASSEMBLE_IEEE754_UNOP(atan);
       break;
+    case kIeee754Float64Atanh:
+      ASSEMBLE_IEEE754_UNOP(atanh);
+      break;
     case kIeee754Float64Atan2:
       ASSEMBLE_IEEE754_BINOP(atan2);
       break;
@@ -686,15 +823,15 @@
     case kIeee754Float64Cos:
       ASSEMBLE_IEEE754_UNOP(cos);
       break;
+    case kIeee754Float64Cosh:
+      ASSEMBLE_IEEE754_UNOP(cosh);
+      break;
     case kIeee754Float64Exp:
       ASSEMBLE_IEEE754_UNOP(exp);
       break;
     case kIeee754Float64Expm1:
       ASSEMBLE_IEEE754_UNOP(expm1);
       break;
-    case kIeee754Float64Atanh:
-      ASSEMBLE_IEEE754_UNOP(atanh);
-      break;
     case kIeee754Float64Log:
       ASSEMBLE_IEEE754_UNOP(log);
       break;
@@ -707,12 +844,24 @@
     case kIeee754Float64Log10:
       ASSEMBLE_IEEE754_UNOP(log10);
       break;
+    case kIeee754Float64Pow: {
+      MathPowStub stub(isolate(), MathPowStub::DOUBLE);
+      __ CallStub(&stub);
+      __ vmov(d0, d2);
+      break;
+    }
     case kIeee754Float64Sin:
       ASSEMBLE_IEEE754_UNOP(sin);
       break;
+    case kIeee754Float64Sinh:
+      ASSEMBLE_IEEE754_UNOP(sinh);
+      break;
     case kIeee754Float64Tan:
       ASSEMBLE_IEEE754_UNOP(tan);
       break;
+    case kIeee754Float64Tanh:
+      ASSEMBLE_IEEE754_UNOP(tanh);
+      break;
     case kArmAdd:
       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
              i.OutputSBit());
@@ -740,6 +889,10 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmSmull:
+      __ smull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
+               i.InputRegister(1));
+      break;
     case kArmSmmul:
       __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -932,54 +1085,54 @@
       break;
     case kArmVcmpF32:
       if (instr->InputAt(1)->IsFPRegister()) {
-        __ VFPCompareAndSetFlags(i.InputFloatRegister(0),
-                                 i.InputFloatRegister(1));
+        __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
+                                 i.InputFloat32Register(1));
       } else {
         DCHECK(instr->InputAt(1)->IsImmediate());
         // 0.0 is the only immediate supported by vcmp instructions.
         DCHECK(i.InputFloat32(1) == 0.0f);
-        __ VFPCompareAndSetFlags(i.InputFloatRegister(0), i.InputFloat32(1));
+        __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputFloat32(1));
       }
       DCHECK_EQ(SetCC, i.OutputSBit());
       break;
     case kArmVaddF32:
-      __ vadd(i.OutputFloatRegister(), i.InputFloatRegister(0),
-              i.InputFloatRegister(1));
+      __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVsubF32:
-      __ vsub(i.OutputFloatRegister(), i.InputFloatRegister(0),
-              i.InputFloatRegister(1));
+      __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmulF32:
-      __ vmul(i.OutputFloatRegister(), i.InputFloatRegister(0),
-              i.InputFloatRegister(1));
+      __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmlaF32:
-      __ vmla(i.OutputFloatRegister(), i.InputFloatRegister(1),
-              i.InputFloatRegister(2));
+      __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
+              i.InputFloat32Register(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmlsF32:
-      __ vmls(i.OutputFloatRegister(), i.InputFloatRegister(1),
-              i.InputFloatRegister(2));
+      __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
+              i.InputFloat32Register(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVdivF32:
-      __ vdiv(i.OutputFloatRegister(), i.InputFloatRegister(0),
-              i.InputFloatRegister(1));
+      __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVsqrtF32:
-      __ vsqrt(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVabsF32:
-      __ vabs(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVnegF32:
-      __ vneg(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVcmpF64:
       if (instr->InputAt(1)->IsFPRegister()) {
@@ -1047,19 +1200,19 @@
       __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArmVrintmF32:
-      __ vrintm(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vrintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVrintmF64:
       __ vrintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArmVrintpF32:
-      __ vrintp(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vrintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVrintpF64:
       __ vrintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArmVrintzF32:
-      __ vrintz(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vrintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVrintzF64:
       __ vrintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
@@ -1068,32 +1221,32 @@
       __ vrinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArmVrintnF32:
-      __ vrintn(i.OutputFloatRegister(), i.InputFloatRegister(0));
+      __ vrintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
     case kArmVrintnF64:
       __ vrintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArmVcvtF32F64: {
-      __ vcvt_f32_f64(i.OutputFloatRegister(), i.InputDoubleRegister(0));
+      __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputDoubleRegister(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtF64F32: {
-      __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloatRegister(0));
+      __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloat32Register(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtF32S32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
       __ vmov(scratch, i.InputRegister(0));
-      __ vcvt_f32_s32(i.OutputFloatRegister(), scratch);
+      __ vcvt_f32_s32(i.OutputFloat32Register(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtF32U32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
       __ vmov(scratch, i.InputRegister(0));
-      __ vcvt_f32_u32(i.OutputFloatRegister(), scratch);
+      __ vcvt_f32_u32(i.OutputFloat32Register(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
@@ -1113,15 +1266,23 @@
     }
     case kArmVcvtS32F32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
-      __ vcvt_s32_f32(scratch, i.InputFloatRegister(0));
+      __ vcvt_s32_f32(scratch, i.InputFloat32Register(0));
       __ vmov(i.OutputRegister(), scratch);
+      // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
+      // because INT32_MIN allows easier out-of-bounds detection.
+      __ cmn(i.OutputRegister(), Operand(1));
+      __ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtU32F32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
-      __ vcvt_u32_f32(scratch, i.InputFloatRegister(0));
+      __ vcvt_u32_f32(scratch, i.InputFloat32Register(0));
       __ vmov(i.OutputRegister(), scratch);
+      // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
+      // because 0 allows easier out-of-bounds detection.
+      __ cmn(i.OutputRegister(), Operand(1));
+      __ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
@@ -1140,11 +1301,11 @@
       break;
     }
     case kArmVmovU32F32:
-      __ vmov(i.OutputRegister(), i.InputFloatRegister(0));
+      __ vmov(i.OutputRegister(), i.InputFloat32Register(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmovF32U32:
-      __ vmov(i.OutputFloatRegister(), i.InputRegister(0));
+      __ vmov(i.OutputFloat32Register(), i.InputRegister(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmovLowU32F64:
@@ -1167,6 +1328,11 @@
       __ vmov(i.OutputDoubleRegister(), i.InputRegister(0), i.InputRegister(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
+    case kArmVmovU32U32F64:
+      __ vmov(i.OutputRegister(0), i.OutputRegister(1),
+              i.InputDoubleRegister(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmLdrb:
       __ ldrb(i.OutputRegister(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -1197,12 +1363,12 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVldrF32: {
-      __ vldr(i.OutputFloatRegister(), i.InputOffset());
+      __ vldr(i.OutputFloat32Register(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVstrF32:
-      __ vstr(i.InputFloatRegister(0), i.InputOffset(1));
+      __ vstr(i.InputFloat32Register(0), i.InputOffset(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVldrF64:
@@ -1214,43 +1380,145 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmFloat32Max: {
-      CpuFeatureScope scope(masm(), ARMv8);
-      // (b < a) ? a : b
-      SwVfpRegister a = i.InputFloatRegister(0);
-      SwVfpRegister b = i.InputFloatRegister(1);
-      SwVfpRegister result = i.OutputFloatRegister();
-      __ VFPCompareAndSetFlags(a, b);
-      __ vsel(gt, result, a, b);
-      break;
-    }
-    case kArmFloat32Min: {
-      CpuFeatureScope scope(masm(), ARMv8);
-      // (a < b) ? a : b
-      SwVfpRegister a = i.InputFloatRegister(0);
-      SwVfpRegister b = i.InputFloatRegister(1);
-      SwVfpRegister result = i.OutputFloatRegister();
-      __ VFPCompareAndSetFlags(b, a);
-      __ vsel(gt, result, a, b);
+      FloatRegister left_reg = i.InputFloat32Register(0);
+      FloatRegister right_reg = i.InputFloat32Register(1);
+      FloatRegister result_reg = i.OutputFloat32Register();
+      Label result_is_nan, return_left, return_right, check_zero, done;
+      __ VFPCompareAndSetFlags(left_reg, right_reg);
+      __ b(mi, &return_right);
+      __ b(gt, &return_left);
+      __ b(vs, &result_is_nan);
+      // Left equals right => check for -0.
+      __ VFPCompareAndSetFlags(left_reg, 0.0);
+      if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+        __ b(ne, &done);  // left == right != 0.
+      } else {
+        __ b(ne, &return_left);  // left == right != 0.
+      }
+      // At this point, both left and right are either 0 or -0.
+      // Since we operate on +0 and/or -0, vadd and vand have the same effect;
+      // the decision for vadd is easy because vand is a NEON instruction.
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&result_is_nan);
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&return_right);
+      __ Move(result_reg, right_reg);
+      if (!left_reg.is(result_reg)) __ b(&done);
+      __ bind(&return_left);
+      __ Move(result_reg, left_reg);
+      __ bind(&done);
       break;
     }
     case kArmFloat64Max: {
-      CpuFeatureScope scope(masm(), ARMv8);
-      // (b < a) ? a : b
-      DwVfpRegister a = i.InputDoubleRegister(0);
-      DwVfpRegister b = i.InputDoubleRegister(1);
-      DwVfpRegister result = i.OutputDoubleRegister();
-      __ VFPCompareAndSetFlags(a, b);
-      __ vsel(gt, result, a, b);
+      DwVfpRegister left_reg = i.InputDoubleRegister(0);
+      DwVfpRegister right_reg = i.InputDoubleRegister(1);
+      DwVfpRegister result_reg = i.OutputDoubleRegister();
+      Label result_is_nan, return_left, return_right, check_zero, done;
+      __ VFPCompareAndSetFlags(left_reg, right_reg);
+      __ b(mi, &return_right);
+      __ b(gt, &return_left);
+      __ b(vs, &result_is_nan);
+      // Left equals right => check for -0.
+      __ VFPCompareAndSetFlags(left_reg, 0.0);
+      if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+        __ b(ne, &done);  // left == right != 0.
+      } else {
+        __ b(ne, &return_left);  // left == right != 0.
+      }
+      // At this point, both left and right are either 0 or -0.
+      // Since we operate on +0 and/or -0, vadd and vand have the same effect;
+      // the decision for vadd is easy because vand is a NEON instruction.
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&result_is_nan);
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&return_right);
+      __ Move(result_reg, right_reg);
+      if (!left_reg.is(result_reg)) __ b(&done);
+      __ bind(&return_left);
+      __ Move(result_reg, left_reg);
+      __ bind(&done);
+      break;
+    }
+    case kArmFloat32Min: {
+      FloatRegister left_reg = i.InputFloat32Register(0);
+      FloatRegister right_reg = i.InputFloat32Register(1);
+      FloatRegister result_reg = i.OutputFloat32Register();
+      Label result_is_nan, return_left, return_right, check_zero, done;
+      __ VFPCompareAndSetFlags(left_reg, right_reg);
+      __ b(mi, &return_left);
+      __ b(gt, &return_right);
+      __ b(vs, &result_is_nan);
+      // Left equals right => check for -0.
+      __ VFPCompareAndSetFlags(left_reg, 0.0);
+      if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+        __ b(ne, &done);  // left == right != 0.
+      } else {
+        __ b(ne, &return_left);  // left == right != 0.
+      }
+      // At this point, both left and right are either 0 or -0.
+      // We could use a single 'vorr' instruction here if we had NEON support.
+      // The algorithm is: -((-L) + (-R)), which in case of L and R being
+      // different registers is most efficiently expressed as -((-L) - R).
+      __ vneg(left_reg, left_reg);
+      if (left_reg.is(right_reg)) {
+        __ vadd(result_reg, left_reg, right_reg);
+      } else {
+        __ vsub(result_reg, left_reg, right_reg);
+      }
+      __ vneg(result_reg, result_reg);
+      __ b(&done);
+      __ bind(&result_is_nan);
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&return_right);
+      __ Move(result_reg, right_reg);
+      if (!left_reg.is(result_reg)) __ b(&done);
+      __ bind(&return_left);
+      __ Move(result_reg, left_reg);
+      __ bind(&done);
       break;
     }
     case kArmFloat64Min: {
-      CpuFeatureScope scope(masm(), ARMv8);
-      // (a < b) ? a : b
-      DwVfpRegister a = i.InputDoubleRegister(0);
-      DwVfpRegister b = i.InputDoubleRegister(1);
-      DwVfpRegister result = i.OutputDoubleRegister();
-      __ VFPCompareAndSetFlags(b, a);
-      __ vsel(gt, result, a, b);
+      DwVfpRegister left_reg = i.InputDoubleRegister(0);
+      DwVfpRegister right_reg = i.InputDoubleRegister(1);
+      DwVfpRegister result_reg = i.OutputDoubleRegister();
+      Label result_is_nan, return_left, return_right, check_zero, done;
+      __ VFPCompareAndSetFlags(left_reg, right_reg);
+      __ b(mi, &return_left);
+      __ b(gt, &return_right);
+      __ b(vs, &result_is_nan);
+      // Left equals right => check for -0.
+      __ VFPCompareAndSetFlags(left_reg, 0.0);
+      if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+        __ b(ne, &done);  // left == right != 0.
+      } else {
+        __ b(ne, &return_left);  // left == right != 0.
+      }
+      // At this point, both left and right are either 0 or -0.
+      // We could use a single 'vorr' instruction here if we had NEON support.
+      // The algorithm is: -((-L) + (-R)), which in case of L and R being
+      // different registers is most efficiently expressed as -((-L) - R).
+      __ vneg(left_reg, left_reg);
+      if (left_reg.is(right_reg)) {
+        __ vadd(result_reg, left_reg, right_reg);
+      } else {
+        __ vsub(result_reg, left_reg, right_reg);
+      }
+      __ vneg(result_reg, result_reg);
+      __ b(&done);
+      __ bind(&result_is_nan);
+      __ vadd(result_reg, left_reg, right_reg);
+      __ b(&done);
+      __ bind(&return_right);
+      __ Move(result_reg, right_reg);
+      if (!left_reg.is(result_reg)) __ b(&done);
+      __ bind(&return_left);
+      __ Move(result_reg, left_reg);
+      __ bind(&done);
       break;
     }
     case kArmFloat64SilenceNaN: {
@@ -1267,7 +1535,7 @@
           frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
         } else {
           DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
-          __ vpush(i.InputFloatRegister(0));
+          __ vpush(i.InputFloat32Register(0));
           frame_access_state()->IncreaseSPDelta(1);
         }
       } else {
@@ -1298,7 +1566,7 @@
       ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
       break;
     case kCheckedLoadFloat32:
-      ASSEMBLE_CHECKED_LOAD_FP(Float);
+      ASSEMBLE_CHECKED_LOAD_FP(Float32);
       break;
     case kCheckedLoadFloat64:
       ASSEMBLE_CHECKED_LOAD_FP(Double);
@@ -1313,7 +1581,7 @@
       ASSEMBLE_CHECKED_STORE_INTEGER(str);
       break;
     case kCheckedStoreFloat32:
-      ASSEMBLE_CHECKED_STORE_FP(Float);
+      ASSEMBLE_CHECKED_STORE_FP(Float32);
       break;
     case kCheckedStoreFloat64:
       ASSEMBLE_CHECKED_STORE_FP(Double);
@@ -1418,6 +1686,9 @@
   // actual final call site and just bl'ing to it here, similar to what we do
   // in the lithium backend.
   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
+  DeoptimizeReason deoptimization_reason =
+      GetDeoptimizationReason(deoptimization_id);
+  __ RecordDeoptReason(deoptimization_reason, 0, deoptimization_id);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   __ CheckConstPool(false, false);
   return kSuccess;
@@ -1467,6 +1738,10 @@
     } else {
       __ StubPrologue(info()->GetOutputStackFrameType());
     }
+
+    if (!info()->GeneratePreagedPrologue()) {
+      unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
+    }
   }
 
   int shrink_slots = frame()->GetSpillSlotCount();
@@ -1530,6 +1805,8 @@
             DwVfpRegister::from_code(last));
   }
 
+  unwinding_info_writer_.MarkBlockWillExit();
+
   if (descriptor->IsCFunctionCall()) {
     AssembleDeconstructFrame();
   } else if (frame_access_state()->has_frame()) {
@@ -1601,10 +1878,7 @@
         case Constant::kHeapObject: {
           Handle<HeapObject> src_object = src.ToHeapObject();
           Heap::RootListIndex index;
-          int slot;
-          if (IsMaterializableFromFrame(src_object, &slot)) {
-            __ ldr(dst, g.SlotToMemOperand(slot));
-          } else if (IsMaterializableFromRoot(src_object, &index)) {
+          if (IsMaterializableFromRoot(src_object, &index)) {
             __ LoadRoot(dst, index);
           } else {
             __ Move(dst, src_object);
@@ -1622,7 +1896,7 @@
         __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
         __ str(ip, dst);
       } else {
-        SwVfpRegister dst = g.ToFloatRegister(destination);
+        SwVfpRegister dst = g.ToFloat32Register(destination);
         __ vmov(dst, src.ToFloat32());
       }
     } else {
@@ -1636,50 +1910,23 @@
       }
     }
   } else if (source->IsFPRegister()) {
-    MachineRepresentation rep = LocationOperand::cast(source)->representation();
-    if (rep == MachineRepresentation::kFloat64) {
-      DwVfpRegister src = g.ToDoubleRegister(source);
-      if (destination->IsFPRegister()) {
-        DwVfpRegister dst = g.ToDoubleRegister(destination);
-        __ Move(dst, src);
-      } else {
-        DCHECK(destination->IsFPStackSlot());
-        __ vstr(src, g.ToMemOperand(destination));
-      }
+    DwVfpRegister src = g.ToDoubleRegister(source);
+    if (destination->IsFPRegister()) {
+      DwVfpRegister dst = g.ToDoubleRegister(destination);
+      __ Move(dst, src);
     } else {
-      DCHECK_EQ(MachineRepresentation::kFloat32, rep);
-      SwVfpRegister src = g.ToFloatRegister(source);
-      if (destination->IsFPRegister()) {
-        SwVfpRegister dst = g.ToFloatRegister(destination);
-        __ Move(dst, src);
-      } else {
-        DCHECK(destination->IsFPStackSlot());
-        __ vstr(src, g.ToMemOperand(destination));
-      }
+      DCHECK(destination->IsFPStackSlot());
+      __ vstr(src, g.ToMemOperand(destination));
     }
   } else if (source->IsFPStackSlot()) {
     MemOperand src = g.ToMemOperand(source);
-    MachineRepresentation rep =
-        LocationOperand::cast(destination)->representation();
     if (destination->IsFPRegister()) {
-      if (rep == MachineRepresentation::kFloat64) {
         __ vldr(g.ToDoubleRegister(destination), src);
-      } else {
-        DCHECK_EQ(MachineRepresentation::kFloat32, rep);
-        __ vldr(g.ToFloatRegister(destination), src);
-      }
     } else {
       DCHECK(destination->IsFPStackSlot());
-      if (rep == MachineRepresentation::kFloat64) {
         DwVfpRegister temp = kScratchDoubleReg;
         __ vldr(temp, src);
         __ vstr(temp, g.ToMemOperand(destination));
-      } else {
-        DCHECK_EQ(MachineRepresentation::kFloat32, rep);
-        SwVfpRegister temp = kScratchDoubleReg.low();
-        __ vldr(temp, src);
-        __ vstr(temp, g.ToMemOperand(destination));
-      }
     }
   } else {
     UNREACHABLE();
@@ -1719,9 +1966,7 @@
     __ str(temp_0, dst);
     __ vstr(temp_1, src);
   } else if (source->IsFPRegister()) {
-    MachineRepresentation rep = LocationOperand::cast(source)->representation();
     LowDwVfpRegister temp = kScratchDoubleReg;
-    if (rep == MachineRepresentation::kFloat64) {
       DwVfpRegister src = g.ToDoubleRegister(source);
       if (destination->IsFPRegister()) {
         DwVfpRegister dst = g.ToDoubleRegister(destination);
@@ -1735,30 +1980,12 @@
         __ vldr(src, dst);
         __ vstr(temp, dst);
       }
-    } else {
-      DCHECK_EQ(MachineRepresentation::kFloat32, rep);
-      SwVfpRegister src = g.ToFloatRegister(source);
-      if (destination->IsFPRegister()) {
-        SwVfpRegister dst = g.ToFloatRegister(destination);
-        __ Move(temp.low(), src);
-        __ Move(src, dst);
-        __ Move(dst, temp.low());
-      } else {
-        DCHECK(destination->IsFPStackSlot());
-        MemOperand dst = g.ToMemOperand(destination);
-        __ Move(temp.low(), src);
-        __ vldr(src, dst);
-        __ vstr(temp.low(), dst);
-      }
-    }
   } else if (source->IsFPStackSlot()) {
     DCHECK(destination->IsFPStackSlot());
     Register temp_0 = kScratchReg;
     LowDwVfpRegister temp_1 = kScratchDoubleReg;
     MemOperand src0 = g.ToMemOperand(source);
     MemOperand dst0 = g.ToMemOperand(destination);
-    MachineRepresentation rep = LocationOperand::cast(source)->representation();
-    if (rep == MachineRepresentation::kFloat64) {
       MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
       MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
       __ vldr(temp_1, dst0);  // Save destination in temp_1.
@@ -1767,13 +1994,6 @@
       __ ldr(temp_0, src1);
       __ str(temp_0, dst1);
       __ vstr(temp_1, src0);
-    } else {
-      DCHECK_EQ(MachineRepresentation::kFloat32, rep);
-      __ vldr(temp_1.low(), dst0);  // Save destination in temp_1.
-      __ ldr(temp_0, src0);  // Then use temp_0 to copy source to destination.
-      __ str(temp_0, dst0);
-      __ vstr(temp_1.low(), src0);
-    }
   } else {
     // No other combinations are possible.
     UNREACHABLE();
diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h
index bc3336f..07c4033 100644
--- a/src/compiler/arm/instruction-codes-arm.h
+++ b/src/compiler/arm/instruction-codes-arm.h
@@ -27,6 +27,7 @@
   V(ArmMul)                        \
   V(ArmMla)                        \
   V(ArmMls)                        \
+  V(ArmSmull)                      \
   V(ArmSmmul)                      \
   V(ArmSmmla)                      \
   V(ArmUmull)                      \
@@ -99,13 +100,14 @@
   V(ArmVmovHighU32F64)             \
   V(ArmVmovHighF64U32)             \
   V(ArmVmovF64U32U32)              \
+  V(ArmVmovU32U32F64)              \
   V(ArmVldrF32)                    \
   V(ArmVstrF32)                    \
   V(ArmVldrF64)                    \
   V(ArmVstrF64)                    \
   V(ArmFloat32Max)                 \
-  V(ArmFloat32Min)                 \
   V(ArmFloat64Max)                 \
+  V(ArmFloat32Min)                 \
   V(ArmFloat64Min)                 \
   V(ArmFloat64SilenceNaN)          \
   V(ArmLdrb)                       \
diff --git a/src/compiler/arm/instruction-scheduler-arm.cc b/src/compiler/arm/instruction-scheduler-arm.cc
index 065fe52..3f38e5d 100644
--- a/src/compiler/arm/instruction-scheduler-arm.cc
+++ b/src/compiler/arm/instruction-scheduler-arm.cc
@@ -30,6 +30,7 @@
     case kArmMla:
     case kArmMls:
     case kArmSmmul:
+    case kArmSmull:
     case kArmSmmla:
     case kArmUmull:
     case kArmSdiv:
@@ -101,10 +102,11 @@
     case kArmVmovHighU32F64:
     case kArmVmovHighF64U32:
     case kArmVmovF64U32U32:
-    case kArmFloat64Max:
-    case kArmFloat64Min:
+    case kArmVmovU32U32F64:
     case kArmFloat32Max:
+    case kArmFloat64Max:
     case kArmFloat32Min:
+    case kArmFloat64Min:
     case kArmFloat64SilenceNaN:
       return kNoOpcodeFlags;
 
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
index e21e63f..4b0b6af 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -273,7 +273,7 @@
   opcode = cont->Encode(opcode);
   if (cont->IsDeoptimize()) {
     selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
-                             cont->frame_state());
+                             cont->reason(), cont->frame_state());
   } else {
     selector->Emit(opcode, output_count, outputs, input_count, inputs);
   }
@@ -338,6 +338,46 @@
   }
 }
 
+void EmitLoad(InstructionSelector* selector, InstructionCode opcode,
+              InstructionOperand* output, Node* base, Node* index) {
+  ArmOperandGenerator g(selector);
+  InstructionOperand inputs[3];
+  size_t input_count = 2;
+
+  inputs[0] = g.UseRegister(base);
+  if (g.CanBeImmediate(index, opcode)) {
+    inputs[1] = g.UseImmediate(index);
+    opcode |= AddressingModeField::encode(kMode_Offset_RI);
+  } else if ((opcode == kArmLdr) &&
+             TryMatchLSLImmediate(selector, &opcode, index, &inputs[1],
+                                  &inputs[2])) {
+    input_count = 3;
+  } else {
+    inputs[1] = g.UseRegister(index);
+    opcode |= AddressingModeField::encode(kMode_Offset_RR);
+  }
+  selector->Emit(opcode, 1, output, input_count, inputs);
+}
+
+void EmitStore(InstructionSelector* selector, InstructionCode opcode,
+               size_t input_count, InstructionOperand* inputs,
+               Node* index) {
+  ArmOperandGenerator g(selector);
+
+  if (g.CanBeImmediate(index, opcode)) {
+    inputs[input_count++] = g.UseImmediate(index);
+    opcode |= AddressingModeField::encode(kMode_Offset_RI);
+  } else if ((opcode == kArmStr) &&
+             TryMatchLSLImmediate(selector, &opcode, index, &inputs[2],
+                                  &inputs[3])) {
+    input_count = 4;
+  } else {
+    inputs[input_count++] = g.UseRegister(index);
+    opcode |= AddressingModeField::encode(kMode_Offset_RR);
+  }
+  selector->Emit(opcode, 0, nullptr, input_count, inputs);
+}
+
 }  // namespace
 
 
@@ -346,9 +386,6 @@
   ArmOperandGenerator g(this);
   Node* base = node->InputAt(0);
   Node* index = node->InputAt(1);
-  InstructionOperand inputs[3];
-  size_t input_count = 0;
-  InstructionOperand outputs[1];
 
   InstructionCode opcode = kArchNop;
   switch (load_rep.representation()) {
@@ -365,6 +402,8 @@
     case MachineRepresentation::kWord16:
       opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
       break;
+    case MachineRepresentation::kTaggedSigned:   // Fall through.
+    case MachineRepresentation::kTaggedPointer:  // Fall through.
     case MachineRepresentation::kTagged:  // Fall through.
     case MachineRepresentation::kWord32:
       opcode = kArmLdr;
@@ -376,24 +415,8 @@
       return;
   }
 
-  outputs[0] = g.DefineAsRegister(node);
-  inputs[0] = g.UseRegister(base);
-
-  if (g.CanBeImmediate(index, opcode)) {
-    input_count = 2;
-    inputs[1] = g.UseImmediate(index);
-    opcode |= AddressingModeField::encode(kMode_Offset_RI);
-  } else if ((opcode == kArmLdr) &&
-             TryMatchLSLImmediate(this, &opcode, index, &inputs[1],
-                                  &inputs[2])) {
-    input_count = 3;
-  } else {
-    input_count = 2;
-    inputs[1] = g.UseRegister(index);
-    opcode |= AddressingModeField::encode(kMode_Offset_RR);
-  }
-
-  Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
+  InstructionOperand output = g.DefineAsRegister(node);
+  EmitLoad(this, opcode, &output, base, index);
 }
 
 
@@ -445,9 +468,6 @@
     code |= MiscField::encode(static_cast<int>(record_write_mode));
     Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
   } else {
-    InstructionOperand inputs[4];
-    size_t input_count = 0;
-
     InstructionCode opcode = kArchNop;
     switch (rep) {
       case MachineRepresentation::kFloat32:
@@ -463,6 +483,8 @@
       case MachineRepresentation::kWord16:
         opcode = kArmStrh;
         break;
+      case MachineRepresentation::kTaggedSigned:   // Fall through.
+      case MachineRepresentation::kTaggedPointer:  // Fall through.
       case MachineRepresentation::kTagged:  // Fall through.
       case MachineRepresentation::kWord32:
         opcode = kArmStr;
@@ -474,26 +496,129 @@
         return;
     }
 
-    inputs[0] = g.UseRegister(value);
-    inputs[1] = g.UseRegister(base);
-
-    if (g.CanBeImmediate(index, opcode)) {
-      input_count = 3;
-      inputs[2] = g.UseImmediate(index);
-      opcode |= AddressingModeField::encode(kMode_Offset_RI);
-    } else if ((opcode == kArmStr) &&
-               TryMatchLSLImmediate(this, &opcode, index, &inputs[2],
-                                    &inputs[3])) {
-      input_count = 4;
-    } else {
-      input_count = 3;
-      inputs[2] = g.UseRegister(index);
-      opcode |= AddressingModeField::encode(kMode_Offset_RR);
-    }
-    Emit(opcode, 0, nullptr, input_count, inputs);
+    InstructionOperand inputs[4];
+    size_t input_count = 0;
+    inputs[input_count++] = g.UseRegister(value);
+    inputs[input_count++] = g.UseRegister(base);
+    EmitStore(this, opcode, input_count, inputs, index);
   }
 }
 
+void InstructionSelector::VisitUnalignedLoad(Node* node) {
+  UnalignedLoadRepresentation load_rep =
+      UnalignedLoadRepresentationOf(node->op());
+  ArmOperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+
+  InstructionCode opcode = kArmLdr;
+  // Only floating point loads need to be specially handled; integer loads
+  // support unaligned access. We support unaligned FP loads by loading to
+  // integer registers first, then moving to the destination FP register.
+  switch (load_rep.representation()) {
+    case MachineRepresentation::kFloat32: {
+      InstructionOperand temp = g.TempRegister();
+      EmitLoad(this, opcode, &temp, base, index);
+      Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp);
+      return;
+    }
+    case MachineRepresentation::kFloat64: {
+      // TODO(arm): use vld1.8 for this when NEON is available.
+      // Compute the address of the least-significant half of the FP value.
+      // We assume that the base node is unlikely to be an encodable immediate
+      // or the result of a shift operation, so only consider the addressing
+      // mode that should be used for the index node.
+      InstructionCode add_opcode = kArmAdd;
+      InstructionOperand inputs[3];
+      inputs[0] = g.UseRegister(base);
+
+      size_t input_count;
+      if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count,
+                                   &inputs[1])) {
+        // input_count has been set by TryMatchImmediateOrShift(), so increment
+        // it to account for the base register in inputs[0].
+        input_count++;
+      } else {
+        add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
+        inputs[1] = g.UseRegister(index);
+        input_count = 2;  // Base register and index.
+      }
+
+      InstructionOperand addr = g.TempRegister();
+      Emit(add_opcode, 1, &addr, input_count, inputs);
+
+      // Load both halves and move to an FP register.
+      InstructionOperand fp_lo = g.TempRegister();
+      InstructionOperand fp_hi = g.TempRegister();
+      opcode |= AddressingModeField::encode(kMode_Offset_RI);
+      Emit(opcode, fp_lo, addr, g.TempImmediate(0));
+      Emit(opcode, fp_hi, addr, g.TempImmediate(4));
+      Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi);
+      return;
+    }
+    default:
+      // All other cases should support unaligned accesses.
+      UNREACHABLE();
+      return;
+  }
+}
+
+void InstructionSelector::VisitUnalignedStore(Node* node) {
+  ArmOperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+  Node* value = node->InputAt(2);
+
+  InstructionOperand inputs[4];
+  size_t input_count = 0;
+
+  UnalignedStoreRepresentation store_rep =
+      UnalignedStoreRepresentationOf(node->op());
+
+  // Only floating point stores need to be specially handled; integer stores
+  // support unaligned access. We support unaligned FP stores by moving the
+  // value to integer registers first, then storing to the destination address.
+  switch (store_rep) {
+    case MachineRepresentation::kFloat32: {
+      inputs[input_count++] = g.TempRegister();
+      Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value));
+      inputs[input_count++] = g.UseRegister(base);
+      EmitStore(this, kArmStr, input_count, inputs, index);
+      return;
+    }
+    case MachineRepresentation::kFloat64: {
+      // TODO(arm): use vst1.8 for this when NEON is available.
+      // Store a 64-bit floating point value using two 32-bit integer stores.
+      // Computing the store address here would require three live temporary
+      // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after
+      // storing the least-significant half of the value.
+
+      // First, move the 64-bit FP value into two temporary integer registers.
+      InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()};
+      inputs[input_count++] = g.UseRegister(value);
+      Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count,
+           inputs);
+
+      // Store the least-significant half.
+      inputs[0] = fp[0];  // Low 32-bits of FP value.
+      inputs[input_count++] = g.UseRegister(base);  // First store base address.
+      EmitStore(this, kArmStr, input_count, inputs, index);
+
+      // Store the most-significant half.
+      InstructionOperand base4 = g.TempRegister();
+      Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4,
+           g.UseRegister(base), g.TempImmediate(4));  // Compute base + 4.
+      inputs[0] = fp[1];  // High 32-bits of FP value.
+      inputs[1] = base4;  // Second store base + 4 address.
+      EmitStore(this, kArmStr, input_count, inputs, index);
+      return;
+    }
+    default:
+      // All other cases should support unaligned accesses.
+      UNREACHABLE();
+      return;
+  }
+}
 
 void InstructionSelector::VisitCheckedLoad(Node* node) {
   CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
@@ -519,6 +644,8 @@
       opcode = kCheckedLoadFloat64;
       break;
     case MachineRepresentation::kBit:      // Fall through.
+    case MachineRepresentation::kTaggedSigned:   // Fall through.
+    case MachineRepresentation::kTaggedPointer:  // Fall through.
     case MachineRepresentation::kTagged:   // Fall through.
     case MachineRepresentation::kWord64:   // Fall through.
     case MachineRepresentation::kSimd128:  // Fall through.
@@ -561,6 +688,8 @@
       opcode = kCheckedStoreFloat64;
       break;
     case MachineRepresentation::kBit:      // Fall through.
+    case MachineRepresentation::kTaggedSigned:   // Fall through.
+    case MachineRepresentation::kTaggedPointer:  // Fall through.
     case MachineRepresentation::kTagged:   // Fall through.
     case MachineRepresentation::kWord64:   // Fall through.
     case MachineRepresentation::kSimd128:  // Fall through.
@@ -758,7 +887,7 @@
   opcode = cont->Encode(opcode);
   if (cont->IsDeoptimize()) {
     selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
-                             cont->frame_state());
+                             cont->reason(), cont->frame_state());
   } else {
     selector->Emit(opcode, output_count, outputs, input_count, inputs);
   }
@@ -961,6 +1090,9 @@
   VisitRR(this, kArmRbit, node);
 }
 
+void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
+
+void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); }
 
 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
 
@@ -1093,6 +1225,38 @@
   VisitBinop(this, node, kArmSub, kArmRsb);
 }
 
+namespace {
+
+void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
+                              FlagsContinuation* cont) {
+  ArmOperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  InstructionOperand result_operand = g.DefineAsRegister(node);
+  InstructionOperand temp_operand = g.TempRegister();
+  InstructionOperand outputs[] = {result_operand, temp_operand};
+  InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
+                                 g.UseRegister(m.right().node())};
+  selector->Emit(kArmSmull, 2, outputs, 2, inputs);
+
+  // result operand needs shift operator.
+  InstructionOperand shift_31 = g.UseImmediate(31);
+  InstructionCode opcode = cont->Encode(kArmCmp) |
+                           AddressingModeField::encode(kMode_Operand2_R_ASR_I);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, g.NoOutput(), temp_operand, result_operand, shift_31,
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
+  } else if (cont->IsDeoptimize()) {
+    InstructionOperand in[] = {temp_operand, result_operand, shift_31};
+    selector->EmitDeoptimize(opcode, 0, nullptr, 3, in, cont->reason(),
+                             cont->frame_state());
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), temp_operand,
+                   result_operand, shift_31);
+  }
+}
+
+}  // namespace
 
 void InstructionSelector::VisitInt32Mul(Node* node) {
   ArmOperandGenerator g(this);
@@ -1260,76 +1424,30 @@
   VisitRRR(this, kArmVaddF64, node);
 }
 
-namespace {
-void VisitFloat32SubHelper(InstructionSelector* selector, Node* node) {
-  ArmOperandGenerator g(selector);
-  Float32BinopMatcher m(node);
-  if (m.right().IsFloat32Mul() && selector->CanCover(node, m.right().node())) {
-    Float32BinopMatcher mright(m.right().node());
-    selector->Emit(kArmVmlsF32, g.DefineSameAsFirst(node),
-                   g.UseRegister(m.left().node()),
-                   g.UseRegister(mright.left().node()),
-                   g.UseRegister(mright.right().node()));
-    return;
-  }
-  VisitRRR(selector, kArmVsubF32, node);
-}
-
-void VisitFloat64SubHelper(InstructionSelector* selector, Node* node) {
-  ArmOperandGenerator g(selector);
-  Float64BinopMatcher m(node);
-  if (m.right().IsFloat64Mul() && selector->CanCover(node, m.right().node())) {
-    Float64BinopMatcher mright(m.right().node());
-    selector->Emit(kArmVmlsF64, g.DefineSameAsFirst(node),
-                   g.UseRegister(m.left().node()),
-                   g.UseRegister(mright.left().node()),
-                   g.UseRegister(mright.right().node()));
-    return;
-  }
-  VisitRRR(selector, kArmVsubF64, node);
-}
-}  // namespace
-
 void InstructionSelector::VisitFloat32Sub(Node* node) {
   ArmOperandGenerator g(this);
   Float32BinopMatcher m(node);
-  if (m.left().IsMinusZero()) {
-    Emit(kArmVnegF32, g.DefineAsRegister(node),
-         g.UseRegister(m.right().node()));
+  if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
+    Float32BinopMatcher mright(m.right().node());
+    Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()));
     return;
   }
-  VisitFloat32SubHelper(this, node);
-}
-
-void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
-  VisitFloat32SubHelper(this, node);
+  VisitRRR(this, kArmVsubF32, node);
 }
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   ArmOperandGenerator g(this);
   Float64BinopMatcher m(node);
-  if (m.left().IsMinusZero()) {
-    if (m.right().IsFloat64RoundDown() &&
-        CanCover(m.node(), m.right().node())) {
-      if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
-          CanCover(m.right().node(), m.right().InputAt(0))) {
-        Float64BinopMatcher mright0(m.right().InputAt(0));
-        if (mright0.left().IsMinusZero()) {
-          Emit(kArmVrintpF64, g.DefineAsRegister(node),
-               g.UseRegister(mright0.right().node()));
-          return;
-        }
-      }
-    }
-    Emit(kArmVnegF64, g.DefineAsRegister(node),
-         g.UseRegister(m.right().node()));
+  if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
+    Float64BinopMatcher mright(m.right().node());
+    Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()));
     return;
   }
-  VisitFloat64SubHelper(this, node);
-}
-
-void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
-  VisitFloat64SubHelper(this, node);
+  VisitRRR(this, kArmVsubF64, node);
 }
 
 void InstructionSelector::VisitFloat32Mul(Node* node) {
@@ -1359,12 +1477,10 @@
 }
 
 void InstructionSelector::VisitFloat32Max(Node* node) {
-  DCHECK(IsSupported(ARMv8));
   VisitRRR(this, kArmFloat32Max, node);
 }
 
 void InstructionSelector::VisitFloat64Max(Node* node) {
-  DCHECK(IsSupported(ARMv8));
   VisitRRR(this, kArmFloat64Max, node);
 }
 
@@ -1373,12 +1489,10 @@
 }
 
 void InstructionSelector::VisitFloat32Min(Node* node) {
-  DCHECK(IsSupported(ARMv8));
   VisitRRR(this, kArmFloat32Min, node);
 }
 
 void InstructionSelector::VisitFloat64Min(Node* node) {
-  DCHECK(IsSupported(ARMv8));
   VisitRRR(this, kArmFloat64Min, node);
 }
 
@@ -1476,7 +1590,7 @@
   // Prepare for C function call.
   if (descriptor->IsCFunctionCall()) {
     Emit(kArchPrepareCallCFunction |
-             MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
+             MiscField::encode(static_cast<int>(descriptor->ParameterCount())),
          0, nullptr, 0, nullptr);
 
     // Poke any stack arguments.
@@ -1515,7 +1629,7 @@
     selector->Emit(opcode, g.NoOutput(), left, right,
                    g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else if (cont->IsDeoptimize()) {
-    selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
+    selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->reason(),
                              cont->frame_state());
   } else {
     DCHECK(cont->IsSet());
@@ -1561,6 +1675,101 @@
   }
 }
 
+// Check whether we can convert:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+// We only generate conditions <cond'> that are a combination of the N
+// and Z flags. This avoids the need to make this function dependent on
+// the flag-setting operation.
+bool CanUseFlagSettingBinop(FlagsCondition cond) {
+  switch (cond) {
+    case kEqual:
+    case kNotEqual:
+    case kSignedLessThan:
+    case kSignedGreaterThanOrEqual:
+    case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
+    case kUnsignedGreaterThan:      // x > 0 -> x != 0
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Map <cond> to <cond'> so that the following transformation is possible:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
+  DCHECK(CanUseFlagSettingBinop(cond));
+  switch (cond) {
+    case kEqual:
+    case kNotEqual:
+      return cond;
+    case kSignedLessThan:
+      return kNegative;
+    case kSignedGreaterThanOrEqual:
+      return kPositiveOrZero;
+    case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
+      return kEqual;
+    case kUnsignedGreaterThan:  // x > 0 -> x != 0
+      return kNotEqual;
+    default:
+      UNREACHABLE();
+      return cond;
+  }
+}
+
+// Check if we can perform the transformation:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>, and if so,
+// updates {node}, {opcode} and {cont} accordingly.
+void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
+                                             Node** node, Node* binop,
+                                             InstructionCode* opcode,
+                                             FlagsCondition cond,
+                                             FlagsContinuation* cont) {
+  InstructionCode binop_opcode;
+  InstructionCode no_output_opcode;
+  switch (binop->opcode()) {
+    case IrOpcode::kInt32Add:
+      binop_opcode = kArmAdd;
+      no_output_opcode = kArmCmn;
+      break;
+    case IrOpcode::kWord32And:
+      binop_opcode = kArmAnd;
+      no_output_opcode = kArmTst;
+      break;
+    case IrOpcode::kWord32Or:
+      binop_opcode = kArmOrr;
+      no_output_opcode = kArmOrr;
+      break;
+    case IrOpcode::kWord32Xor:
+      binop_opcode = kArmEor;
+      no_output_opcode = kArmTeq;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  if (selector->CanCover(*node, binop)) {
+    // The comparison is the only user of {node}.
+    cont->Overwrite(MapForFlagSettingBinop(cond));
+    *opcode = no_output_opcode;
+    *node = binop;
+  } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
+    // We can also handle the case where the {node} and the comparison are in
+    // the same basic block, and the comparison is the only user of {node} in
+    // this basic block ({node} has users in other basic blocks).
+    cont->Overwrite(MapForFlagSettingBinop(cond));
+    *opcode = binop_opcode;
+    *node = binop;
+  }
+}
 
 // Shared routine for multiple word compare operations.
 void VisitWordCompare(InstructionSelector* selector, Node* node,
@@ -1569,8 +1778,10 @@
   Int32BinopMatcher m(node);
   InstructionOperand inputs[5];
   size_t input_count = 0;
-  InstructionOperand outputs[1];
+  InstructionOperand outputs[2];
   size_t output_count = 0;
+  bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) &&
+                    (opcode != kArmTst) && (opcode != kArmTeq);
 
   if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
                                &input_count, &inputs[1])) {
@@ -1587,6 +1798,17 @@
     inputs[input_count++] = g.UseRegister(m.right().node());
   }
 
+  if (has_result) {
+    if (cont->IsDeoptimize()) {
+      // If we can deoptimize as a result of the binop, we need to make sure
+      // that the deopt inputs are not overwritten by the binop result. One way
+      // to achieve that is to declare the output register as same-as-first.
+      outputs[output_count++] = g.DefineSameAsFirst(node);
+    } else {
+      outputs[output_count++] = g.DefineAsRegister(node);
+    }
+  }
+
   if (cont->IsBranch()) {
     inputs[input_count++] = g.Label(cont->true_block());
     inputs[input_count++] = g.Label(cont->false_block());
@@ -1601,7 +1823,7 @@
   opcode = cont->Encode(opcode);
   if (cont->IsDeoptimize()) {
     selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
-                             cont->frame_state());
+                             cont->reason(), cont->frame_state());
   } else {
     selector->Emit(opcode, output_count, outputs, input_count, inputs);
   }
@@ -1610,7 +1832,32 @@
 
 void VisitWordCompare(InstructionSelector* selector, Node* node,
                       FlagsContinuation* cont) {
-  VisitWordCompare(selector, node, kArmCmp, cont);
+  InstructionCode opcode = kArmCmp;
+  Int32BinopMatcher m(node);
+
+  FlagsCondition cond = cont->condition();
+  if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() ||
+                          m.left().IsWord32And() || m.left().IsWord32Xor())) {
+    // Emit flag setting instructions for comparisons against zero.
+    if (CanUseFlagSettingBinop(cond)) {
+      Node* binop = m.left().node();
+      MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+                                              cond, cont);
+    }
+  } else if (m.left().Is(0) &&
+             (m.right().IsInt32Add() || m.right().IsWord32Or() ||
+              m.right().IsWord32And() || m.right().IsWord32Xor())) {
+    // Same as above, but we need to commute the condition before we
+    // continue with the rest of the checks.
+    cond = CommuteFlagsCondition(cond);
+    if (CanUseFlagSettingBinop(cond)) {
+      Node* binop = m.right().node();
+      MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+                                              cond, cont);
+    }
+  }
+
+  VisitWordCompare(selector, node, opcode, cont);
 }
 
 
@@ -1681,6 +1928,13 @@
               case IrOpcode::kInt32SubWithOverflow:
                 cont->OverwriteAndNegateIfEqual(kOverflow);
                 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
+              case IrOpcode::kInt32MulWithOverflow:
+                // ARM doesn't set the overflow flag for multiplication, so we
+                // need to test on kNotEqual. Here is the code sequence used:
+                //   smull resultlow, resulthigh, left, right
+                //   cmp resulthigh, Operand(resultlow, ASR, 31)
+                cont->OverwriteAndNegateIfEqual(kNotEqual);
+                return EmitInt32MulWithOverflow(selector, node, cont);
               default:
                 break;
             }
@@ -1721,7 +1975,7 @@
                    g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else if (cont->IsDeoptimize()) {
     selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
-                             cont->frame_state());
+                             cont->reason(), cont->frame_state());
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
@@ -1738,14 +1992,14 @@
 }
 
 void InstructionSelector::VisitDeoptimizeIf(Node* node) {
-  FlagsContinuation cont =
-      FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
+  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
+      kNotEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
   VisitWordCompareZero(this, node, node->InputAt(0), &cont);
 }
 
 void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
-  FlagsContinuation cont =
-      FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
+  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
+      kEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
   VisitWordCompareZero(this, node, node->InputAt(0), &cont);
 }
 
@@ -1822,7 +2076,6 @@
   VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
 }
 
-
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
@@ -1832,6 +2085,18 @@
   VisitBinop(this, node, kArmSub, kArmRsb, &cont);
 }
 
+void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
+    // ARM doesn't set the overflow flag for multiplication, so we need to test
+    // on kNotEqual. Here is the code sequence used:
+    //   smull resultlow, resulthigh, left, right
+    //   cmp resulthigh, Operand(resultlow, ASR, 31)
+    FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
+    return EmitInt32MulWithOverflow(this, node, &cont);
+  }
+  FlagsContinuation cont;
+  EmitInt32MulWithOverflow(this, node, &cont);
+}
 
 void InstructionSelector::VisitFloat32Equal(Node* node) {
   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
@@ -1990,13 +2255,7 @@
              MachineOperatorBuilder::kFloat64RoundTruncate |
              MachineOperatorBuilder::kFloat64RoundTiesAway |
              MachineOperatorBuilder::kFloat32RoundTiesEven |
-             MachineOperatorBuilder::kFloat64RoundTiesEven |
-             MachineOperatorBuilder::kFloat32Min |
-             MachineOperatorBuilder::kFloat32Max |
-             MachineOperatorBuilder::kFloat64Min |
-             MachineOperatorBuilder::kFloat64Max |
-             MachineOperatorBuilder::kFloat32Neg |
-             MachineOperatorBuilder::kFloat64Neg;
+             MachineOperatorBuilder::kFloat64RoundTiesEven;
   }
   return flags;
 }
@@ -2004,8 +2263,11 @@
 // static
 MachineOperatorBuilder::AlignmentRequirements
 InstructionSelector::AlignmentRequirements() {
+  Vector<MachineType> req_aligned = Vector<MachineType>::New(2);
+  req_aligned[0] = MachineType::Float32();
+  req_aligned[1] = MachineType::Float64();
   return MachineOperatorBuilder::AlignmentRequirements::
-      FullUnalignedAccessSupport();
+      SomeUnalignedAccessUnsupported(req_aligned, req_aligned);
 }
 
 }  // namespace compiler
diff --git a/src/compiler/arm/unwinding-info-writer-arm.cc b/src/compiler/arm/unwinding-info-writer-arm.cc
new file mode 100644
index 0000000..a950612
--- /dev/null
+++ b/src/compiler/arm/unwinding-info-writer-arm.cc
@@ -0,0 +1,108 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/arm/unwinding-info-writer-arm.h"
+#include "src/compiler/instruction.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+void UnwindingInfoWriter::BeginInstructionBlock(int pc_offset,
+                                                const InstructionBlock* block) {
+  if (!enabled()) return;
+
+  block_will_exit_ = false;
+
+  DCHECK_LT(block->rpo_number().ToInt(), block_initial_states_.size());
+  const BlockInitialState* initial_state =
+      block_initial_states_[block->rpo_number().ToInt()];
+  if (initial_state) {
+    if (initial_state->saved_lr_ != saved_lr_) {
+      eh_frame_writer_.AdvanceLocation(pc_offset);
+      if (initial_state->saved_lr_) {
+        eh_frame_writer_.RecordRegisterSavedToStack(lr, kPointerSize);
+      } else {
+        eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+      }
+      saved_lr_ = initial_state->saved_lr_;
+    }
+  } else {
+    // The entry block always lacks an explicit initial state.
+    // The exit block may lack an explicit state, if it is only reached by
+    //   the block ending in a bx lr.
+    // All the other blocks must have an explicit initial state.
+    DCHECK(block->predecessors().empty() || block->successors().empty());
+  }
+}
+
+void UnwindingInfoWriter::EndInstructionBlock(const InstructionBlock* block) {
+  if (!enabled() || block_will_exit_) return;
+
+  for (const RpoNumber& successor : block->successors()) {
+    int successor_index = successor.ToInt();
+    DCHECK_LT(successor_index, block_initial_states_.size());
+    const BlockInitialState* existing_state =
+        block_initial_states_[successor_index];
+
+    // If we already had an entry for this BB, check that the values are the
+    // same we are trying to insert.
+    if (existing_state) {
+      DCHECK_EQ(existing_state->saved_lr_, saved_lr_);
+    } else {
+      block_initial_states_[successor_index] =
+          new (zone_) BlockInitialState(saved_lr_);
+    }
+  }
+}
+
+void UnwindingInfoWriter::MarkFrameConstructed(int at_pc) {
+  if (!enabled()) return;
+
+  // Regardless of the type of frame constructed, the relevant part of the
+  // layout is always the one in the diagram:
+  //
+  // |   ....   |         higher addresses
+  // +----------+               ^
+  // |    LR    |               |            |
+  // +----------+               |            |
+  // | saved FP |               |            |
+  // +----------+ <-- FP                     v
+  // |   ....   |                       stack growth
+  //
+  // The LR is pushed on the stack, and we can record this fact at the end of
+  // the construction, since the LR itself is not modified in the process.
+  eh_frame_writer_.AdvanceLocation(at_pc);
+  eh_frame_writer_.RecordRegisterSavedToStack(lr, kPointerSize);
+  saved_lr_ = true;
+}
+
+void UnwindingInfoWriter::MarkFrameDeconstructed(int at_pc) {
+  if (!enabled()) return;
+
+  // The lr is restored by the last operation in LeaveFrame().
+  eh_frame_writer_.AdvanceLocation(at_pc);
+  eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+  saved_lr_ = false;
+}
+
+void UnwindingInfoWriter::MarkLinkRegisterOnTopOfStack(int pc_offset) {
+  if (!enabled()) return;
+
+  eh_frame_writer_.AdvanceLocation(pc_offset);
+  eh_frame_writer_.SetBaseAddressRegisterAndOffset(sp, 0);
+  eh_frame_writer_.RecordRegisterSavedToStack(lr, 0);
+}
+
+void UnwindingInfoWriter::MarkPopLinkRegisterFromTopOfStack(int pc_offset) {
+  if (!enabled()) return;
+
+  eh_frame_writer_.AdvanceLocation(pc_offset);
+  eh_frame_writer_.SetBaseAddressRegisterAndOffset(fp, 0);
+  eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/arm/unwinding-info-writer-arm.h b/src/compiler/arm/unwinding-info-writer-arm.h
new file mode 100644
index 0000000..d47ca08
--- /dev/null
+++ b/src/compiler/arm/unwinding-info-writer-arm.h
@@ -0,0 +1,72 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_ARM_UNWINDING_INFO_WRITER_H_
+#define V8_COMPILER_ARM_UNWINDING_INFO_WRITER_H_
+
+#include "src/eh-frame.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionBlock;
+
+class UnwindingInfoWriter {
+ public:
+  explicit UnwindingInfoWriter(Zone* zone)
+      : zone_(zone),
+        eh_frame_writer_(zone),
+        saved_lr_(false),
+        block_will_exit_(false),
+        block_initial_states_(zone) {
+    if (enabled()) eh_frame_writer_.Initialize();
+  }
+
+  void SetNumberOfInstructionBlocks(int number) {
+    if (enabled()) block_initial_states_.resize(number);
+  }
+
+  void BeginInstructionBlock(int pc_offset, const InstructionBlock* block);
+  void EndInstructionBlock(const InstructionBlock* block);
+
+  void MarkLinkRegisterOnTopOfStack(int pc_offset);
+  void MarkPopLinkRegisterFromTopOfStack(int pc_offset);
+
+  void MarkFrameConstructed(int at_pc);
+  void MarkFrameDeconstructed(int at_pc);
+
+  void MarkBlockWillExit() { block_will_exit_ = true; }
+
+  void Finish(int code_size) {
+    if (enabled()) eh_frame_writer_.Finish(code_size);
+  }
+
+  EhFrameWriter* eh_frame_writer() {
+    return enabled() ? &eh_frame_writer_ : nullptr;
+  }
+
+ private:
+  bool enabled() const { return FLAG_perf_prof_unwinding_info; }
+
+  class BlockInitialState : public ZoneObject {
+   public:
+    explicit BlockInitialState(bool saved_lr) : saved_lr_(saved_lr) {}
+
+    bool saved_lr_;
+  };
+
+  Zone* zone_;
+  EhFrameWriter eh_frame_writer_;
+  bool saved_lr_;
+  bool block_will_exit_;
+
+  ZoneVector<const BlockInitialState*> block_initial_states_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif