Home | History | Annotate | Download | only in arm
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/code-generator.h"
      6 
      7 #include "src/arm/macro-assembler-arm.h"
      8 #include "src/compilation-info.h"
      9 #include "src/compiler/code-generator-impl.h"
     10 #include "src/compiler/gap-resolver.h"
     11 #include "src/compiler/node-matchers.h"
     12 #include "src/compiler/osr.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 namespace compiler {
     17 
     18 #define __ masm()->
     19 
     20 
     21 #define kScratchReg r9
     22 
     23 
     24 // Adds Arm-specific methods to convert InstructionOperands.
     25 class ArmOperandConverter final : public InstructionOperandConverter {
     26  public:
     27   ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
     28       : InstructionOperandConverter(gen, instr) {}
     29 
     30   SBit OutputSBit() const {
     31     switch (instr_->flags_mode()) {
     32       case kFlags_branch:
     33       case kFlags_deoptimize:
     34       case kFlags_set:
     35       case kFlags_trap:
     36         return SetCC;
     37       case kFlags_none:
     38         return LeaveCC;
     39     }
     40     UNREACHABLE();
     41     return LeaveCC;
     42   }
     43 
     44   Operand InputImmediate(size_t index) {
     45     Constant constant = ToConstant(instr_->InputAt(index));
     46     switch (constant.type()) {
     47       case Constant::kInt32:
     48         return Operand(constant.ToInt32());
     49       case Constant::kFloat32:
     50         return Operand(
     51             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
     52       case Constant::kFloat64:
     53         return Operand(
     54             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
     55       case Constant::kInt64:
     56       case Constant::kExternalReference:
     57       case Constant::kHeapObject:
     58       case Constant::kRpoNumber:
     59         break;
     60     }
     61     UNREACHABLE();
     62     return Operand::Zero();
     63   }
     64 
     65   Operand InputOperand2(size_t first_index) {
     66     const size_t index = first_index;
     67     switch (AddressingModeField::decode(instr_->opcode())) {
     68       case kMode_None:
     69       case kMode_Offset_RI:
     70       case kMode_Offset_RR:
     71         break;
     72       case kMode_Operand2_I:
     73         return InputImmediate(index + 0);
     74       case kMode_Operand2_R:
     75         return Operand(InputRegister(index + 0));
     76       case kMode_Operand2_R_ASR_I:
     77         return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1));
     78       case kMode_Operand2_R_ASR_R:
     79         return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1));
     80       case kMode_Operand2_R_LSL_I:
     81         return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1));
     82       case kMode_Operand2_R_LSL_R:
     83         return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1));
     84       case kMode_Operand2_R_LSR_I:
     85         return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
     86       case kMode_Operand2_R_LSR_R:
     87         return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
     88       case kMode_Operand2_R_ROR_I:
     89         return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
     90       case kMode_Operand2_R_ROR_R:
     91         return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
     92     }
     93     UNREACHABLE();
     94     return Operand::Zero();
     95   }
     96 
     97   MemOperand InputOffset(size_t* first_index) {
     98     const size_t index = *first_index;
     99     switch (AddressingModeField::decode(instr_->opcode())) {
    100       case kMode_None:
    101       case kMode_Operand2_I:
    102       case kMode_Operand2_R:
    103       case kMode_Operand2_R_ASR_I:
    104       case kMode_Operand2_R_ASR_R:
    105       case kMode_Operand2_R_LSL_R:
    106       case kMode_Operand2_R_LSR_I:
    107       case kMode_Operand2_R_LSR_R:
    108       case kMode_Operand2_R_ROR_I:
    109       case kMode_Operand2_R_ROR_R:
    110         break;
    111       case kMode_Operand2_R_LSL_I:
    112         *first_index += 3;
    113         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
    114                           LSL, InputInt32(index + 2));
    115       case kMode_Offset_RI:
    116         *first_index += 2;
    117         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
    118       case kMode_Offset_RR:
    119         *first_index += 2;
    120         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
    121     }
    122     UNREACHABLE();
    123     return MemOperand(r0);
    124   }
    125 
    126   MemOperand InputOffset(size_t first_index = 0) {
    127     return InputOffset(&first_index);
    128   }
    129 
    130   MemOperand ToMemOperand(InstructionOperand* op) const {
    131     DCHECK_NOT_NULL(op);
    132     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
    133     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
    134   }
    135 
    136   MemOperand SlotToMemOperand(int slot) const {
    137     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
    138     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
    139   }
    140 };
    141 
    142 namespace {
    143 
    144 class OutOfLineLoadFloat final : public OutOfLineCode {
    145  public:
    146   OutOfLineLoadFloat(CodeGenerator* gen, SwVfpRegister result)
    147       : OutOfLineCode(gen), result_(result) {}
    148 
    149   void Generate() final {
    150     // Compute sqrtf(-1.0f), which results in a quiet single-precision NaN.
    151     __ vmov(result_, -1.0f);
    152     __ vsqrt(result_, result_);
    153   }
    154 
    155  private:
    156   SwVfpRegister const result_;
    157 };
    158 
    159 class OutOfLineLoadDouble final : public OutOfLineCode {
    160  public:
    161   OutOfLineLoadDouble(CodeGenerator* gen, DwVfpRegister result)
    162       : OutOfLineCode(gen), result_(result) {}
    163 
    164   void Generate() final {
    165     // Compute sqrt(-1.0), which results in a quiet double-precision NaN.
    166     __ vmov(result_, -1.0);
    167     __ vsqrt(result_, result_);
    168   }
    169 
    170  private:
    171   DwVfpRegister const result_;
    172 };
    173 
    174 
    175 class OutOfLineLoadInteger final : public OutOfLineCode {
    176  public:
    177   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
    178       : OutOfLineCode(gen), result_(result) {}
    179 
    180   void Generate() final { __ mov(result_, Operand::Zero()); }
    181 
    182  private:
    183   Register const result_;
    184 };
    185 
    186 
    187 class OutOfLineRecordWrite final : public OutOfLineCode {
    188  public:
    189   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
    190                        Register value, Register scratch0, Register scratch1,
    191                        RecordWriteMode mode,
    192                        UnwindingInfoWriter* unwinding_info_writer)
    193       : OutOfLineCode(gen),
    194         object_(object),
    195         index_(index),
    196         index_immediate_(0),
    197         value_(value),
    198         scratch0_(scratch0),
    199         scratch1_(scratch1),
    200         mode_(mode),
    201         must_save_lr_(!gen->frame_access_state()->has_frame()),
    202         unwinding_info_writer_(unwinding_info_writer) {}
    203 
    204   OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
    205                        Register value, Register scratch0, Register scratch1,
    206                        RecordWriteMode mode,
    207                        UnwindingInfoWriter* unwinding_info_writer)
    208       : OutOfLineCode(gen),
    209         object_(object),
    210         index_(no_reg),
    211         index_immediate_(index),
    212         value_(value),
    213         scratch0_(scratch0),
    214         scratch1_(scratch1),
    215         mode_(mode),
    216         must_save_lr_(!gen->frame_access_state()->has_frame()),
    217         unwinding_info_writer_(unwinding_info_writer) {}
    218 
    219   void Generate() final {
    220     if (mode_ > RecordWriteMode::kValueIsPointer) {
    221       __ JumpIfSmi(value_, exit());
    222     }
    223     __ CheckPageFlag(value_, scratch0_,
    224                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
    225                      exit());
    226     RememberedSetAction const remembered_set_action =
    227         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
    228                                              : OMIT_REMEMBERED_SET;
    229     SaveFPRegsMode const save_fp_mode =
    230         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    231     if (must_save_lr_) {
    232       // We need to save and restore lr if the frame was elided.
    233       __ Push(lr);
    234       unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset());
    235     }
    236     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    237                          remembered_set_action, save_fp_mode);
    238     if (index_.is(no_reg)) {
    239       __ add(scratch1_, object_, Operand(index_immediate_));
    240     } else {
    241       DCHECK_EQ(0, index_immediate_);
    242       __ add(scratch1_, object_, Operand(index_));
    243     }
    244     __ CallStub(&stub);
    245     if (must_save_lr_) {
    246       __ Pop(lr);
    247       unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
    248     }
    249   }
    250 
    251  private:
    252   Register const object_;
    253   Register const index_;
    254   int32_t const index_immediate_;  // Valid if index_.is(no_reg).
    255   Register const value_;
    256   Register const scratch0_;
    257   Register const scratch1_;
    258   RecordWriteMode const mode_;
    259   bool must_save_lr_;
    260   UnwindingInfoWriter* const unwinding_info_writer_;
    261 };
    262 
    263 template <typename T>
    264 class OutOfLineFloatMin final : public OutOfLineCode {
    265  public:
    266   OutOfLineFloatMin(CodeGenerator* gen, T result, T left, T right)
    267       : OutOfLineCode(gen), result_(result), left_(left), right_(right) {}
    268 
    269   void Generate() final { __ FloatMinOutOfLine(result_, left_, right_); }
    270 
    271  private:
    272   T const result_;
    273   T const left_;
    274   T const right_;
    275 };
    276 typedef OutOfLineFloatMin<SwVfpRegister> OutOfLineFloat32Min;
    277 typedef OutOfLineFloatMin<DwVfpRegister> OutOfLineFloat64Min;
    278 
    279 template <typename T>
    280 class OutOfLineFloatMax final : public OutOfLineCode {
    281  public:
    282   OutOfLineFloatMax(CodeGenerator* gen, T result, T left, T right)
    283       : OutOfLineCode(gen), result_(result), left_(left), right_(right) {}
    284 
    285   void Generate() final { __ FloatMaxOutOfLine(result_, left_, right_); }
    286 
    287  private:
    288   T const result_;
    289   T const left_;
    290   T const right_;
    291 };
    292 typedef OutOfLineFloatMax<SwVfpRegister> OutOfLineFloat32Max;
    293 typedef OutOfLineFloatMax<DwVfpRegister> OutOfLineFloat64Max;
    294 
    295 Condition FlagsConditionToCondition(FlagsCondition condition) {
    296   switch (condition) {
    297     case kEqual:
    298       return eq;
    299     case kNotEqual:
    300       return ne;
    301     case kSignedLessThan:
    302       return lt;
    303     case kSignedGreaterThanOrEqual:
    304       return ge;
    305     case kSignedLessThanOrEqual:
    306       return le;
    307     case kSignedGreaterThan:
    308       return gt;
    309     case kUnsignedLessThan:
    310       return lo;
    311     case kUnsignedGreaterThanOrEqual:
    312       return hs;
    313     case kUnsignedLessThanOrEqual:
    314       return ls;
    315     case kUnsignedGreaterThan:
    316       return hi;
    317     case kFloatLessThanOrUnordered:
    318       return lt;
    319     case kFloatGreaterThanOrEqual:
    320       return ge;
    321     case kFloatLessThanOrEqual:
    322       return ls;
    323     case kFloatGreaterThanOrUnordered:
    324       return hi;
    325     case kFloatLessThan:
    326       return lo;
    327     case kFloatGreaterThanOrEqualOrUnordered:
    328       return hs;
    329     case kFloatLessThanOrEqualOrUnordered:
    330       return le;
    331     case kFloatGreaterThan:
    332       return gt;
    333     case kOverflow:
    334       return vs;
    335     case kNotOverflow:
    336       return vc;
    337     case kPositiveOrZero:
    338       return pl;
    339     case kNegative:
    340       return mi;
    341     default:
    342       break;
    343   }
    344   UNREACHABLE();
    345   return kNoCondition;
    346 }
    347 
    348 }  // namespace
    349 
    350 #define ASSEMBLE_CHECKED_LOAD_FP(Type)                         \
    351   do {                                                         \
    352     auto result = i.Output##Type##Register();                  \
    353     auto offset = i.InputRegister(0);                          \
    354     if (instr->InputAt(1)->IsRegister()) {                     \
    355       __ cmp(offset, i.InputRegister(1));                      \
    356     } else {                                                   \
    357       __ cmp(offset, i.InputImmediate(1));                     \
    358     }                                                          \
    359     auto ool = new (zone()) OutOfLineLoad##Type(this, result); \
    360     __ b(hs, ool->entry());                                    \
    361     __ vldr(result, i.InputOffset(2));                         \
    362     __ bind(ool->exit());                                      \
    363     DCHECK_EQ(LeaveCC, i.OutputSBit());                        \
    364   } while (0)
    365 
    366 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                \
    367   do {                                                          \
    368     auto result = i.OutputRegister();                           \
    369     auto offset = i.InputRegister(0);                           \
    370     if (instr->InputAt(1)->IsRegister()) {                      \
    371       __ cmp(offset, i.InputRegister(1));                       \
    372     } else {                                                    \
    373       __ cmp(offset, i.InputImmediate(1));                      \
    374     }                                                           \
    375     auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
    376     __ b(hs, ool->entry());                                     \
    377     __ asm_instr(result, i.InputOffset(2));                     \
    378     __ bind(ool->exit());                                       \
    379     DCHECK_EQ(LeaveCC, i.OutputSBit());                         \
    380   } while (0)
    381 
    382 #define ASSEMBLE_CHECKED_STORE_FP(Type)      \
    383   do {                                       \
    384     auto offset = i.InputRegister(0);        \
    385     if (instr->InputAt(1)->IsRegister()) {   \
    386       __ cmp(offset, i.InputRegister(1));    \
    387     } else {                                 \
    388       __ cmp(offset, i.InputImmediate(1));   \
    389     }                                        \
    390     auto value = i.Input##Type##Register(2); \
    391     __ vstr(value, i.InputOffset(3), lo);    \
    392     DCHECK_EQ(LeaveCC, i.OutputSBit());      \
    393   } while (0)
    394 
    395 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
    396   do {                                            \
    397     auto offset = i.InputRegister(0);             \
    398     if (instr->InputAt(1)->IsRegister()) {        \
    399       __ cmp(offset, i.InputRegister(1));         \
    400     } else {                                      \
    401       __ cmp(offset, i.InputImmediate(1));        \
    402     }                                             \
    403     auto value = i.InputRegister(2);              \
    404     __ asm_instr(value, i.InputOffset(3), lo);    \
    405     DCHECK_EQ(LeaveCC, i.OutputSBit());           \
    406   } while (0)
    407 
    408 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)                       \
    409   do {                                                                \
    410     __ asm_instr(i.OutputRegister(),                                  \
    411                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    412     __ dmb(ISH);                                                      \
    413   } while (0)
    414 
    415 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)                      \
    416   do {                                                                \
    417     __ dmb(ISH);                                                      \
    418     __ asm_instr(i.InputRegister(2),                                  \
    419                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    420     __ dmb(ISH);                                                      \
    421   } while (0)
    422 
    423 #define ASSEMBLE_IEEE754_BINOP(name)                                           \
    424   do {                                                                         \
    425     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
    426     /* and generate a CallAddress instruction instead. */                      \
    427     FrameScope scope(masm(), StackFrame::MANUAL);                              \
    428     __ PrepareCallCFunction(0, 2, kScratchReg);                                \
    429     __ MovToFloatParameters(i.InputDoubleRegister(0),                          \
    430                             i.InputDoubleRegister(1));                         \
    431     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
    432                      0, 2);                                                    \
    433     /* Move the result in the double result register. */                       \
    434     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
    435     DCHECK_EQ(LeaveCC, i.OutputSBit());                                        \
    436   } while (0)
    437 
    438 #define ASSEMBLE_IEEE754_UNOP(name)                                            \
    439   do {                                                                         \
    440     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
    441     /* and generate a CallAddress instruction instead. */                      \
    442     FrameScope scope(masm(), StackFrame::MANUAL);                              \
    443     __ PrepareCallCFunction(0, 1, kScratchReg);                                \
    444     __ MovToFloatParameter(i.InputDoubleRegister(0));                          \
    445     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
    446                      0, 1);                                                    \
    447     /* Move the result in the double result register. */                       \
    448     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
    449     DCHECK_EQ(LeaveCC, i.OutputSBit());                                        \
    450   } while (0)
    451 
    452 void CodeGenerator::AssembleDeconstructFrame() {
    453   __ LeaveFrame(StackFrame::MANUAL);
    454   unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
    455 }
    456 
    457 void CodeGenerator::AssemblePrepareTailCall() {
    458   if (frame_access_state()->has_frame()) {
    459     if (FLAG_enable_embedded_constant_pool) {
    460       __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
    461     }
    462     __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    463     __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    464   }
    465   frame_access_state()->SetFrameAccessToSP();
    466 }
    467 
    468 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
    469                                                      Register scratch1,
    470                                                      Register scratch2,
    471                                                      Register scratch3) {
    472   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
    473   Label done;
    474 
    475   // Check if current frame is an arguments adaptor frame.
    476   __ ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
    477   __ cmp(scratch1,
    478          Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
    479   __ b(ne, &done);
    480 
    481   // Load arguments count from current arguments adaptor frame (note, it
    482   // does not include receiver).
    483   Register caller_args_count_reg = scratch1;
    484   __ ldr(caller_args_count_reg,
    485          MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
    486   __ SmiUntag(caller_args_count_reg);
    487 
    488   ParameterCount callee_args_count(args_reg);
    489   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
    490                         scratch3);
    491   __ bind(&done);
    492 }
    493 
    494 namespace {
    495 
    496 void FlushPendingPushRegisters(MacroAssembler* masm,
    497                                FrameAccessState* frame_access_state,
    498                                ZoneVector<Register>* pending_pushes) {
    499   switch (pending_pushes->size()) {
    500     case 0:
    501       break;
    502     case 1:
    503       masm->push((*pending_pushes)[0]);
    504       break;
    505     case 2:
    506       masm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
    507       break;
    508     case 3:
    509       masm->Push((*pending_pushes)[0], (*pending_pushes)[1],
    510                  (*pending_pushes)[2]);
    511       break;
    512     default:
    513       UNREACHABLE();
    514       break;
    515   }
    516   frame_access_state->IncreaseSPDelta(pending_pushes->size());
    517   pending_pushes->resize(0);
    518 }
    519 
    520 void AddPendingPushRegister(MacroAssembler* masm,
    521                             FrameAccessState* frame_access_state,
    522                             ZoneVector<Register>* pending_pushes,
    523                             Register reg) {
    524   pending_pushes->push_back(reg);
    525   if (pending_pushes->size() == 3 || reg.is(ip)) {
    526     FlushPendingPushRegisters(masm, frame_access_state, pending_pushes);
    527   }
    528 }
    529 
    530 void AdjustStackPointerForTailCall(
    531     MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp,
    532     ZoneVector<Register>* pending_pushes = nullptr,
    533     bool allow_shrinkage = true) {
    534   int current_sp_offset = state->GetSPToFPSlotCount() +
    535                           StandardFrameConstants::kFixedSlotCountAboveFp;
    536   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
    537   if (stack_slot_delta > 0) {
    538     if (pending_pushes != nullptr) {
    539       FlushPendingPushRegisters(masm, state, pending_pushes);
    540     }
    541     masm->sub(sp, sp, Operand(stack_slot_delta * kPointerSize));
    542     state->IncreaseSPDelta(stack_slot_delta);
    543   } else if (allow_shrinkage && stack_slot_delta < 0) {
    544     if (pending_pushes != nullptr) {
    545       FlushPendingPushRegisters(masm, state, pending_pushes);
    546     }
    547     masm->add(sp, sp, Operand(-stack_slot_delta * kPointerSize));
    548     state->IncreaseSPDelta(stack_slot_delta);
    549   }
    550 }
    551 
    552 }  // namespace
    553 
    554 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
    555                                               int first_unused_stack_slot) {
    556   CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
    557   ZoneVector<MoveOperands*> pushes(zone());
    558   GetPushCompatibleMoves(instr, flags, &pushes);
    559 
    560   if (!pushes.empty() &&
    561       (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
    562        first_unused_stack_slot)) {
    563     ArmOperandConverter g(this, instr);
    564     ZoneVector<Register> pending_pushes(zone());
    565     for (auto move : pushes) {
    566       LocationOperand destination_location(
    567           LocationOperand::cast(move->destination()));
    568       InstructionOperand source(move->source());
    569       AdjustStackPointerForTailCall(
    570           masm(), frame_access_state(),
    571           destination_location.index() - pending_pushes.size(),
    572           &pending_pushes);
    573       if (source.IsStackSlot()) {
    574         LocationOperand source_location(LocationOperand::cast(source));
    575         __ ldr(ip, g.SlotToMemOperand(source_location.index()));
    576         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
    577                                ip);
    578       } else if (source.IsRegister()) {
    579         LocationOperand source_location(LocationOperand::cast(source));
    580         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
    581                                source_location.GetRegister());
    582       } else if (source.IsImmediate()) {
    583         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
    584                                ip);
    585       } else {
    586         // Pushes of non-scalar data types is not supported.
    587         UNIMPLEMENTED();
    588       }
    589       move->Eliminate();
    590     }
    591     FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes);
    592   }
    593   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    594                                 first_unused_stack_slot, nullptr, false);
    595 }
    596 
    597 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
    598                                              int first_unused_stack_slot) {
    599   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    600                                 first_unused_stack_slot);
    601 }
    602 
    603 // Assembles an instruction after register allocation, producing machine code.
    604 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    605     Instruction* instr) {
    606   ArmOperandConverter i(this, instr);
    607 
    608   __ MaybeCheckConstPool();
    609   InstructionCode opcode = instr->opcode();
    610   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
    611   switch (arch_opcode) {
    612     case kArchCallCodeObject: {
    613       EnsureSpaceForLazyDeopt();
    614       if (instr->InputAt(0)->IsImmediate()) {
    615         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
    616                 RelocInfo::CODE_TARGET);
    617       } else {
    618         __ add(ip, i.InputRegister(0),
    619                Operand(Code::kHeaderSize - kHeapObjectTag));
    620         __ Call(ip);
    621       }
    622       RecordCallPosition(instr);
    623       DCHECK_EQ(LeaveCC, i.OutputSBit());
    624       frame_access_state()->ClearSPDelta();
    625       break;
    626     }
    627     case kArchTailCallCodeObjectFromJSFunction:
    628     case kArchTailCallCodeObject: {
    629       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
    630         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    631                                          i.TempRegister(0), i.TempRegister(1),
    632                                          i.TempRegister(2));
    633       }
    634       if (instr->InputAt(0)->IsImmediate()) {
    635         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
    636                 RelocInfo::CODE_TARGET);
    637       } else {
    638         __ add(ip, i.InputRegister(0),
    639                Operand(Code::kHeaderSize - kHeapObjectTag));
    640         __ Jump(ip);
    641       }
    642       DCHECK_EQ(LeaveCC, i.OutputSBit());
    643       unwinding_info_writer_.MarkBlockWillExit();
    644       frame_access_state()->ClearSPDelta();
    645       frame_access_state()->SetFrameAccessToDefault();
    646       break;
    647     }
    648     case kArchTailCallAddress: {
    649       CHECK(!instr->InputAt(0)->IsImmediate());
    650       __ Jump(i.InputRegister(0));
    651       unwinding_info_writer_.MarkBlockWillExit();
    652       frame_access_state()->ClearSPDelta();
    653       frame_access_state()->SetFrameAccessToDefault();
    654       break;
    655     }
    656     case kArchCallJSFunction: {
    657       EnsureSpaceForLazyDeopt();
    658       Register func = i.InputRegister(0);
    659       if (FLAG_debug_code) {
    660         // Check the function's context matches the context argument.
    661         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    662         __ cmp(cp, kScratchReg);
    663         __ Assert(eq, kWrongFunctionContext);
    664       }
    665       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    666       __ Call(ip);
    667       RecordCallPosition(instr);
    668       DCHECK_EQ(LeaveCC, i.OutputSBit());
    669       frame_access_state()->ClearSPDelta();
    670       break;
    671     }
    672     case kArchTailCallJSFunctionFromJSFunction: {
    673       Register func = i.InputRegister(0);
    674       if (FLAG_debug_code) {
    675         // Check the function's context matches the context argument.
    676         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    677         __ cmp(cp, kScratchReg);
    678         __ Assert(eq, kWrongFunctionContext);
    679       }
    680       AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    681                                        i.TempRegister(0), i.TempRegister(1),
    682                                        i.TempRegister(2));
    683       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    684       __ Jump(ip);
    685       DCHECK_EQ(LeaveCC, i.OutputSBit());
    686       frame_access_state()->ClearSPDelta();
    687       frame_access_state()->SetFrameAccessToDefault();
    688       break;
    689     }
    690     case kArchPrepareCallCFunction: {
    691       int const num_parameters = MiscField::decode(instr->opcode());
    692       __ PrepareCallCFunction(num_parameters, kScratchReg);
    693       // Frame alignment requires using FP-relative frame addressing.
    694       frame_access_state()->SetFrameAccessToFP();
    695       break;
    696     }
    697     case kArchPrepareTailCall:
    698       AssemblePrepareTailCall();
    699       break;
    700     case kArchCallCFunction: {
    701       int const num_parameters = MiscField::decode(instr->opcode());
    702       if (instr->InputAt(0)->IsImmediate()) {
    703         ExternalReference ref = i.InputExternalReference(0);
    704         __ CallCFunction(ref, num_parameters);
    705       } else {
    706         Register func = i.InputRegister(0);
    707         __ CallCFunction(func, num_parameters);
    708       }
    709       frame_access_state()->SetFrameAccessToDefault();
    710       frame_access_state()->ClearSPDelta();
    711       break;
    712     }
    713     case kArchJmp:
    714       AssembleArchJump(i.InputRpo(0));
    715       DCHECK_EQ(LeaveCC, i.OutputSBit());
    716       break;
    717     case kArchLookupSwitch:
    718       AssembleArchLookupSwitch(instr);
    719       DCHECK_EQ(LeaveCC, i.OutputSBit());
    720       break;
    721     case kArchTableSwitch:
    722       AssembleArchTableSwitch(instr);
    723       DCHECK_EQ(LeaveCC, i.OutputSBit());
    724       break;
    725     case kArchDebugBreak:
    726       __ stop("kArchDebugBreak");
    727       break;
    728     case kArchComment: {
    729       Address comment_string = i.InputExternalReference(0).address();
    730       __ RecordComment(reinterpret_cast<const char*>(comment_string));
    731       break;
    732     }
    733     case kArchNop:
    734     case kArchThrowTerminator:
    735       // don't emit code for nops.
    736       DCHECK_EQ(LeaveCC, i.OutputSBit());
    737       break;
    738     case kArchDeoptimize: {
    739       int deopt_state_id =
    740           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    741       CodeGenResult result =
    742           AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
    743       if (result != kSuccess) return result;
    744       break;
    745     }
    746     case kArchRet:
    747       AssembleReturn(instr->InputAt(0));
    748       DCHECK_EQ(LeaveCC, i.OutputSBit());
    749       break;
    750     case kArchStackPointer:
    751       __ mov(i.OutputRegister(), sp);
    752       DCHECK_EQ(LeaveCC, i.OutputSBit());
    753       break;
    754     case kArchFramePointer:
    755       __ mov(i.OutputRegister(), fp);
    756       DCHECK_EQ(LeaveCC, i.OutputSBit());
    757       break;
    758     case kArchParentFramePointer:
    759       if (frame_access_state()->has_frame()) {
    760         __ ldr(i.OutputRegister(), MemOperand(fp, 0));
    761       } else {
    762         __ mov(i.OutputRegister(), fp);
    763       }
    764       break;
    765     case kArchTruncateDoubleToI:
    766       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
    767       DCHECK_EQ(LeaveCC, i.OutputSBit());
    768       break;
    769     case kArchStoreWithWriteBarrier: {
    770       RecordWriteMode mode =
    771           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    772       Register object = i.InputRegister(0);
    773       Register value = i.InputRegister(2);
    774       Register scratch0 = i.TempRegister(0);
    775       Register scratch1 = i.TempRegister(1);
    776       OutOfLineRecordWrite* ool;
    777 
    778       AddressingMode addressing_mode =
    779           AddressingModeField::decode(instr->opcode());
    780       if (addressing_mode == kMode_Offset_RI) {
    781         int32_t index = i.InputInt32(1);
    782         ool = new (zone())
    783             OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
    784                                  mode, &unwinding_info_writer_);
    785         __ str(value, MemOperand(object, index));
    786       } else {
    787         DCHECK_EQ(kMode_Offset_RR, addressing_mode);
    788         Register index(i.InputRegister(1));
    789         ool = new (zone())
    790             OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
    791                                  mode, &unwinding_info_writer_);
    792         __ str(value, MemOperand(object, index));
    793       }
    794       __ CheckPageFlag(object, scratch0,
    795                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
    796                        ool->entry());
    797       __ bind(ool->exit());
    798       break;
    799     }
    800     case kArchStackSlot: {
    801       FrameOffset offset =
    802           frame_access_state()->GetFrameOffset(i.InputInt32(0));
    803       Register base;
    804       if (offset.from_stack_pointer()) {
    805         base = sp;
    806       } else {
    807         base = fp;
    808       }
    809       __ add(i.OutputRegister(0), base, Operand(offset.offset()));
    810       break;
    811     }
    812     case kIeee754Float64Acos:
    813       ASSEMBLE_IEEE754_UNOP(acos);
    814       break;
    815     case kIeee754Float64Acosh:
    816       ASSEMBLE_IEEE754_UNOP(acosh);
    817       break;
    818     case kIeee754Float64Asin:
    819       ASSEMBLE_IEEE754_UNOP(asin);
    820       break;
    821     case kIeee754Float64Asinh:
    822       ASSEMBLE_IEEE754_UNOP(asinh);
    823       break;
    824     case kIeee754Float64Atan:
    825       ASSEMBLE_IEEE754_UNOP(atan);
    826       break;
    827     case kIeee754Float64Atanh:
    828       ASSEMBLE_IEEE754_UNOP(atanh);
    829       break;
    830     case kIeee754Float64Atan2:
    831       ASSEMBLE_IEEE754_BINOP(atan2);
    832       break;
    833     case kIeee754Float64Cbrt:
    834       ASSEMBLE_IEEE754_UNOP(cbrt);
    835       break;
    836     case kIeee754Float64Cos:
    837       ASSEMBLE_IEEE754_UNOP(cos);
    838       break;
    839     case kIeee754Float64Cosh:
    840       ASSEMBLE_IEEE754_UNOP(cosh);
    841       break;
    842     case kIeee754Float64Exp:
    843       ASSEMBLE_IEEE754_UNOP(exp);
    844       break;
    845     case kIeee754Float64Expm1:
    846       ASSEMBLE_IEEE754_UNOP(expm1);
    847       break;
    848     case kIeee754Float64Log:
    849       ASSEMBLE_IEEE754_UNOP(log);
    850       break;
    851     case kIeee754Float64Log1p:
    852       ASSEMBLE_IEEE754_UNOP(log1p);
    853       break;
    854     case kIeee754Float64Log2:
    855       ASSEMBLE_IEEE754_UNOP(log2);
    856       break;
    857     case kIeee754Float64Log10:
    858       ASSEMBLE_IEEE754_UNOP(log10);
    859       break;
    860     case kIeee754Float64Pow: {
    861       MathPowStub stub(isolate(), MathPowStub::DOUBLE);
    862       __ CallStub(&stub);
    863       __ vmov(d0, d2);
    864       break;
    865     }
    866     case kIeee754Float64Sin:
    867       ASSEMBLE_IEEE754_UNOP(sin);
    868       break;
    869     case kIeee754Float64Sinh:
    870       ASSEMBLE_IEEE754_UNOP(sinh);
    871       break;
    872     case kIeee754Float64Tan:
    873       ASSEMBLE_IEEE754_UNOP(tan);
    874       break;
    875     case kIeee754Float64Tanh:
    876       ASSEMBLE_IEEE754_UNOP(tanh);
    877       break;
    878     case kArmAdd:
    879       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    880              i.OutputSBit());
    881       break;
    882     case kArmAnd:
    883       __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    884               i.OutputSBit());
    885       break;
    886     case kArmBic:
    887       __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    888              i.OutputSBit());
    889       break;
    890     case kArmMul:
    891       __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    892              i.OutputSBit());
    893       break;
    894     case kArmMla:
    895       __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    896              i.InputRegister(2), i.OutputSBit());
    897       break;
    898     case kArmMls: {
    899       CpuFeatureScope scope(masm(), ARMv7);
    900       __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    901              i.InputRegister(2));
    902       DCHECK_EQ(LeaveCC, i.OutputSBit());
    903       break;
    904     }
    905     case kArmSmull:
    906       __ smull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    907                i.InputRegister(1));
    908       break;
    909     case kArmSmmul:
    910       __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    911       DCHECK_EQ(LeaveCC, i.OutputSBit());
    912       break;
    913     case kArmSmmla:
    914       __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    915                i.InputRegister(2));
    916       DCHECK_EQ(LeaveCC, i.OutputSBit());
    917       break;
    918     case kArmUmull:
    919       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    920                i.InputRegister(1), i.OutputSBit());
    921       break;
    922     case kArmSdiv: {
    923       CpuFeatureScope scope(masm(), SUDIV);
    924       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    925       DCHECK_EQ(LeaveCC, i.OutputSBit());
    926       break;
    927     }
    928     case kArmUdiv: {
    929       CpuFeatureScope scope(masm(), SUDIV);
    930       __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    931       DCHECK_EQ(LeaveCC, i.OutputSBit());
    932       break;
    933     }
    934     case kArmMov:
    935       __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
    936       break;
    937     case kArmMvn:
    938       __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
    939       break;
    940     case kArmOrr:
    941       __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    942              i.OutputSBit());
    943       break;
    944     case kArmEor:
    945       __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    946              i.OutputSBit());
    947       break;
    948     case kArmSub:
    949       __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    950              i.OutputSBit());
    951       break;
    952     case kArmRsb:
    953       __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    954              i.OutputSBit());
    955       break;
    956     case kArmBfc: {
    957       CpuFeatureScope scope(masm(), ARMv7);
    958       __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
    959       DCHECK_EQ(LeaveCC, i.OutputSBit());
    960       break;
    961     }
    962     case kArmUbfx: {
    963       CpuFeatureScope scope(masm(), ARMv7);
    964       __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
    965               i.InputInt8(2));
    966       DCHECK_EQ(LeaveCC, i.OutputSBit());
    967       break;
    968     }
    969     case kArmSbfx: {
    970       CpuFeatureScope scope(masm(), ARMv7);
    971       __ sbfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
    972               i.InputInt8(2));
    973       DCHECK_EQ(LeaveCC, i.OutputSBit());
    974       break;
    975     }
    976     case kArmSxtb:
    977       __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    978       DCHECK_EQ(LeaveCC, i.OutputSBit());
    979       break;
    980     case kArmSxth:
    981       __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    982       DCHECK_EQ(LeaveCC, i.OutputSBit());
    983       break;
    984     case kArmSxtab:
    985       __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    986                i.InputInt32(2));
    987       DCHECK_EQ(LeaveCC, i.OutputSBit());
    988       break;
    989     case kArmSxtah:
    990       __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    991                i.InputInt32(2));
    992       DCHECK_EQ(LeaveCC, i.OutputSBit());
    993       break;
    994     case kArmUxtb:
    995       __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    996       DCHECK_EQ(LeaveCC, i.OutputSBit());
    997       break;
    998     case kArmUxth:
    999       __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
   1000       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1001       break;
   1002     case kArmUxtab:
   1003       __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
   1004                i.InputInt32(2));
   1005       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1006       break;
   1007     case kArmUxtah:
   1008       __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
   1009                i.InputInt32(2));
   1010       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1011       break;
   1012     case kArmRbit: {
   1013       CpuFeatureScope scope(masm(), ARMv7);
   1014       __ rbit(i.OutputRegister(), i.InputRegister(0));
   1015       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1016       break;
   1017     }
   1018     case kArmClz:
   1019       __ clz(i.OutputRegister(), i.InputRegister(0));
   1020       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1021       break;
   1022     case kArmCmp:
   1023       __ cmp(i.InputRegister(0), i.InputOperand2(1));
   1024       DCHECK_EQ(SetCC, i.OutputSBit());
   1025       break;
   1026     case kArmCmn:
   1027       __ cmn(i.InputRegister(0), i.InputOperand2(1));
   1028       DCHECK_EQ(SetCC, i.OutputSBit());
   1029       break;
   1030     case kArmTst:
   1031       __ tst(i.InputRegister(0), i.InputOperand2(1));
   1032       DCHECK_EQ(SetCC, i.OutputSBit());
   1033       break;
   1034     case kArmTeq:
   1035       __ teq(i.InputRegister(0), i.InputOperand2(1));
   1036       DCHECK_EQ(SetCC, i.OutputSBit());
   1037       break;
   1038     case kArmAddPair:
   1039       // i.InputRegister(0) ... left low word.
   1040       // i.InputRegister(1) ... left high word.
   1041       // i.InputRegister(2) ... right low word.
   1042       // i.InputRegister(3) ... right high word.
   1043       __ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
   1044              SBit::SetCC);
   1045       __ adc(i.OutputRegister(1), i.InputRegister(1),
   1046              Operand(i.InputRegister(3)));
   1047       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1048       break;
   1049     case kArmSubPair:
   1050       // i.InputRegister(0) ... left low word.
   1051       // i.InputRegister(1) ... left high word.
   1052       // i.InputRegister(2) ... right low word.
   1053       // i.InputRegister(3) ... right high word.
   1054       __ sub(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
   1055              SBit::SetCC);
   1056       __ sbc(i.OutputRegister(1), i.InputRegister(1),
   1057              Operand(i.InputRegister(3)));
   1058       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1059       break;
   1060     case kArmMulPair:
   1061       // i.InputRegister(0) ... left low word.
   1062       // i.InputRegister(1) ... left high word.
   1063       // i.InputRegister(2) ... right low word.
   1064       // i.InputRegister(3) ... right high word.
   1065       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
   1066                i.InputRegister(2));
   1067       __ mla(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(3),
   1068              i.OutputRegister(1));
   1069       __ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1),
   1070              i.OutputRegister(1));
   1071       break;
   1072     case kArmLslPair: {
   1073       Register second_output =
   1074           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
   1075       if (instr->InputAt(2)->IsImmediate()) {
   1076         __ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1077                    i.InputRegister(1), i.InputInt32(2));
   1078       } else {
   1079         __ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1080                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
   1081       }
   1082       break;
   1083     }
   1084     case kArmLsrPair: {
   1085       Register second_output =
   1086           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
   1087       if (instr->InputAt(2)->IsImmediate()) {
   1088         __ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1089                    i.InputRegister(1), i.InputInt32(2));
   1090       } else {
   1091         __ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1092                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
   1093       }
   1094       break;
   1095     }
   1096     case kArmAsrPair: {
   1097       Register second_output =
   1098           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
   1099       if (instr->InputAt(2)->IsImmediate()) {
   1100         __ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1101                    i.InputRegister(1), i.InputInt32(2));
   1102       } else {
   1103         __ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
   1104                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
   1105       }
   1106       break;
   1107     }
   1108     case kArmVcmpF32:
   1109       if (instr->InputAt(1)->IsFPRegister()) {
   1110         __ VFPCompareAndSetFlags(i.InputFloatRegister(0),
   1111                                  i.InputFloatRegister(1));
   1112       } else {
   1113         DCHECK(instr->InputAt(1)->IsImmediate());
   1114         // 0.0 is the only immediate supported by vcmp instructions.
   1115         DCHECK(i.InputFloat32(1) == 0.0f);
   1116         __ VFPCompareAndSetFlags(i.InputFloatRegister(0), i.InputFloat32(1));
   1117       }
   1118       DCHECK_EQ(SetCC, i.OutputSBit());
   1119       break;
   1120     case kArmVaddF32:
   1121       __ vadd(i.OutputFloatRegister(), i.InputFloatRegister(0),
   1122               i.InputFloatRegister(1));
   1123       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1124       break;
   1125     case kArmVsubF32:
   1126       __ vsub(i.OutputFloatRegister(), i.InputFloatRegister(0),
   1127               i.InputFloatRegister(1));
   1128       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1129       break;
   1130     case kArmVmulF32:
   1131       __ vmul(i.OutputFloatRegister(), i.InputFloatRegister(0),
   1132               i.InputFloatRegister(1));
   1133       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1134       break;
   1135     case kArmVmlaF32:
   1136       __ vmla(i.OutputFloatRegister(), i.InputFloatRegister(1),
   1137               i.InputFloatRegister(2));
   1138       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1139       break;
   1140     case kArmVmlsF32:
   1141       __ vmls(i.OutputFloatRegister(), i.InputFloatRegister(1),
   1142               i.InputFloatRegister(2));
   1143       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1144       break;
   1145     case kArmVdivF32:
   1146       __ vdiv(i.OutputFloatRegister(), i.InputFloatRegister(0),
   1147               i.InputFloatRegister(1));
   1148       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1149       break;
   1150     case kArmVsqrtF32:
   1151       __ vsqrt(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1152       break;
   1153     case kArmVabsF32:
   1154       __ vabs(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1155       break;
   1156     case kArmVnegF32:
   1157       __ vneg(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1158       break;
   1159     case kArmVcmpF64:
   1160       if (instr->InputAt(1)->IsFPRegister()) {
   1161         __ VFPCompareAndSetFlags(i.InputDoubleRegister(0),
   1162                                  i.InputDoubleRegister(1));
   1163       } else {
   1164         DCHECK(instr->InputAt(1)->IsImmediate());
   1165         // 0.0 is the only immediate supported by vcmp instructions.
   1166         DCHECK(i.InputDouble(1) == 0.0);
   1167         __ VFPCompareAndSetFlags(i.InputDoubleRegister(0), i.InputDouble(1));
   1168       }
   1169       DCHECK_EQ(SetCC, i.OutputSBit());
   1170       break;
   1171     case kArmVaddF64:
   1172       __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1173               i.InputDoubleRegister(1));
   1174       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1175       break;
   1176     case kArmVsubF64:
   1177       __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1178               i.InputDoubleRegister(1));
   1179       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1180       break;
   1181     case kArmVmulF64:
   1182       __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1183               i.InputDoubleRegister(1));
   1184       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1185       break;
   1186     case kArmVmlaF64:
   1187       __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1188               i.InputDoubleRegister(2));
   1189       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1190       break;
   1191     case kArmVmlsF64:
   1192       __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1193               i.InputDoubleRegister(2));
   1194       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1195       break;
   1196     case kArmVdivF64:
   1197       __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1198               i.InputDoubleRegister(1));
   1199       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1200       break;
   1201     case kArmVmodF64: {
   1202       // TODO(bmeurer): We should really get rid of this special instruction,
   1203       // and generate a CallAddress instruction instead.
   1204       FrameScope scope(masm(), StackFrame::MANUAL);
   1205       __ PrepareCallCFunction(0, 2, kScratchReg);
   1206       __ MovToFloatParameters(i.InputDoubleRegister(0),
   1207                               i.InputDoubleRegister(1));
   1208       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
   1209                        0, 2);
   1210       // Move the result in the double result register.
   1211       __ MovFromFloatResult(i.OutputDoubleRegister());
   1212       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1213       break;
   1214     }
   1215     case kArmVsqrtF64:
   1216       __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1217       break;
   1218     case kArmVabsF64:
   1219       __ vabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1220       break;
   1221     case kArmVnegF64:
   1222       __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1223       break;
   1224     case kArmVrintmF32: {
   1225       CpuFeatureScope scope(masm(), ARMv8);
   1226       __ vrintm(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1227       break;
   1228     }
   1229     case kArmVrintmF64: {
   1230       CpuFeatureScope scope(masm(), ARMv8);
   1231       __ vrintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1232       break;
   1233     }
   1234     case kArmVrintpF32: {
   1235       CpuFeatureScope scope(masm(), ARMv8);
   1236       __ vrintp(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1237       break;
   1238     }
   1239     case kArmVrintpF64: {
   1240       CpuFeatureScope scope(masm(), ARMv8);
   1241       __ vrintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1242       break;
   1243     }
   1244     case kArmVrintzF32: {
   1245       CpuFeatureScope scope(masm(), ARMv8);
   1246       __ vrintz(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1247       break;
   1248     }
   1249     case kArmVrintzF64: {
   1250       CpuFeatureScope scope(masm(), ARMv8);
   1251       __ vrintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1252       break;
   1253     }
   1254     case kArmVrintaF64: {
   1255       CpuFeatureScope scope(masm(), ARMv8);
   1256       __ vrinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1257       break;
   1258     }
   1259     case kArmVrintnF32: {
   1260       CpuFeatureScope scope(masm(), ARMv8);
   1261       __ vrintn(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1262       break;
   1263     }
   1264     case kArmVrintnF64: {
   1265       CpuFeatureScope scope(masm(), ARMv8);
   1266       __ vrintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1267       break;
   1268     }
   1269     case kArmVcvtF32F64: {
   1270       __ vcvt_f32_f64(i.OutputFloatRegister(), i.InputDoubleRegister(0));
   1271       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1272       break;
   1273     }
   1274     case kArmVcvtF64F32: {
   1275       __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloatRegister(0));
   1276       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1277       break;
   1278     }
   1279     case kArmVcvtF32S32: {
   1280       SwVfpRegister scratch = kScratchDoubleReg.low();
   1281       __ vmov(scratch, i.InputRegister(0));
   1282       __ vcvt_f32_s32(i.OutputFloatRegister(), scratch);
   1283       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1284       break;
   1285     }
   1286     case kArmVcvtF32U32: {
   1287       SwVfpRegister scratch = kScratchDoubleReg.low();
   1288       __ vmov(scratch, i.InputRegister(0));
   1289       __ vcvt_f32_u32(i.OutputFloatRegister(), scratch);
   1290       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1291       break;
   1292     }
   1293     case kArmVcvtF64S32: {
   1294       SwVfpRegister scratch = kScratchDoubleReg.low();
   1295       __ vmov(scratch, i.InputRegister(0));
   1296       __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch);
   1297       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1298       break;
   1299     }
   1300     case kArmVcvtF64U32: {
   1301       SwVfpRegister scratch = kScratchDoubleReg.low();
   1302       __ vmov(scratch, i.InputRegister(0));
   1303       __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch);
   1304       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1305       break;
   1306     }
   1307     case kArmVcvtS32F32: {
   1308       SwVfpRegister scratch = kScratchDoubleReg.low();
   1309       __ vcvt_s32_f32(scratch, i.InputFloatRegister(0));
   1310       __ vmov(i.OutputRegister(), scratch);
   1311       // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
   1312       // because INT32_MIN allows easier out-of-bounds detection.
   1313       __ cmn(i.OutputRegister(), Operand(1));
   1314       __ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs);
   1315       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1316       break;
   1317     }
   1318     case kArmVcvtU32F32: {
   1319       SwVfpRegister scratch = kScratchDoubleReg.low();
   1320       __ vcvt_u32_f32(scratch, i.InputFloatRegister(0));
   1321       __ vmov(i.OutputRegister(), scratch);
   1322       // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
   1323       // because 0 allows easier out-of-bounds detection.
   1324       __ cmn(i.OutputRegister(), Operand(1));
   1325       __ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero());
   1326       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1327       break;
   1328     }
   1329     case kArmVcvtS32F64: {
   1330       SwVfpRegister scratch = kScratchDoubleReg.low();
   1331       __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0));
   1332       __ vmov(i.OutputRegister(), scratch);
   1333       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1334       break;
   1335     }
   1336     case kArmVcvtU32F64: {
   1337       SwVfpRegister scratch = kScratchDoubleReg.low();
   1338       __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0));
   1339       __ vmov(i.OutputRegister(), scratch);
   1340       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1341       break;
   1342     }
   1343     case kArmVmovU32F32:
   1344       __ vmov(i.OutputRegister(), i.InputFloatRegister(0));
   1345       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1346       break;
   1347     case kArmVmovF32U32:
   1348       __ vmov(i.OutputFloatRegister(), i.InputRegister(0));
   1349       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1350       break;
   1351     case kArmVmovLowU32F64:
   1352       __ VmovLow(i.OutputRegister(), i.InputDoubleRegister(0));
   1353       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1354       break;
   1355     case kArmVmovLowF64U32:
   1356       __ VmovLow(i.OutputDoubleRegister(), i.InputRegister(1));
   1357       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1358       break;
   1359     case kArmVmovHighU32F64:
   1360       __ VmovHigh(i.OutputRegister(), i.InputDoubleRegister(0));
   1361       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1362       break;
   1363     case kArmVmovHighF64U32:
   1364       __ VmovHigh(i.OutputDoubleRegister(), i.InputRegister(1));
   1365       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1366       break;
   1367     case kArmVmovF64U32U32:
   1368       __ vmov(i.OutputDoubleRegister(), i.InputRegister(0), i.InputRegister(1));
   1369       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1370       break;
   1371     case kArmVmovU32U32F64:
   1372       __ vmov(i.OutputRegister(0), i.OutputRegister(1),
   1373               i.InputDoubleRegister(0));
   1374       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1375       break;
   1376     case kArmLdrb:
   1377       __ ldrb(i.OutputRegister(), i.InputOffset());
   1378       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1379       break;
   1380     case kArmLdrsb:
   1381       __ ldrsb(i.OutputRegister(), i.InputOffset());
   1382       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1383       break;
   1384     case kArmStrb:
   1385       __ strb(i.InputRegister(0), i.InputOffset(1));
   1386       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1387       break;
   1388     case kArmLdrh:
   1389       __ ldrh(i.OutputRegister(), i.InputOffset());
   1390       break;
   1391     case kArmLdrsh:
   1392       __ ldrsh(i.OutputRegister(), i.InputOffset());
   1393       break;
   1394     case kArmStrh:
   1395       __ strh(i.InputRegister(0), i.InputOffset(1));
   1396       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1397       break;
   1398     case kArmLdr:
   1399       __ ldr(i.OutputRegister(), i.InputOffset());
   1400       break;
   1401     case kArmStr:
   1402       __ str(i.InputRegister(0), i.InputOffset(1));
   1403       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1404       break;
   1405     case kArmVldrF32: {
   1406       __ vldr(i.OutputFloatRegister(), i.InputOffset());
   1407       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1408       break;
   1409     }
   1410     case kArmVstrF32:
   1411       __ vstr(i.InputFloatRegister(0), i.InputOffset(1));
   1412       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1413       break;
   1414     case kArmVldrF64:
   1415       __ vldr(i.OutputDoubleRegister(), i.InputOffset());
   1416       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1417       break;
   1418     case kArmVstrF64:
   1419       __ vstr(i.InputDoubleRegister(0), i.InputOffset(1));
   1420       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1421       break;
   1422     case kArmFloat32Max: {
   1423       SwVfpRegister result = i.OutputFloatRegister();
   1424       SwVfpRegister left = i.InputFloatRegister(0);
   1425       SwVfpRegister right = i.InputFloatRegister(1);
   1426       if (left.is(right)) {
   1427         __ Move(result, left);
   1428       } else {
   1429         auto ool = new (zone()) OutOfLineFloat32Max(this, result, left, right);
   1430         __ FloatMax(result, left, right, ool->entry());
   1431         __ bind(ool->exit());
   1432       }
   1433       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1434       break;
   1435     }
   1436     case kArmFloat64Max: {
   1437       DwVfpRegister result = i.OutputDoubleRegister();
   1438       DwVfpRegister left = i.InputDoubleRegister(0);
   1439       DwVfpRegister right = i.InputDoubleRegister(1);
   1440       if (left.is(right)) {
   1441         __ Move(result, left);
   1442       } else {
   1443         auto ool = new (zone()) OutOfLineFloat64Max(this, result, left, right);
   1444         __ FloatMax(result, left, right, ool->entry());
   1445         __ bind(ool->exit());
   1446       }
   1447       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1448       break;
   1449     }
   1450     case kArmFloat32Min: {
   1451       SwVfpRegister result = i.OutputFloatRegister();
   1452       SwVfpRegister left = i.InputFloatRegister(0);
   1453       SwVfpRegister right = i.InputFloatRegister(1);
   1454       if (left.is(right)) {
   1455         __ Move(result, left);
   1456       } else {
   1457         auto ool = new (zone()) OutOfLineFloat32Min(this, result, left, right);
   1458         __ FloatMin(result, left, right, ool->entry());
   1459         __ bind(ool->exit());
   1460       }
   1461       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1462       break;
   1463     }
   1464     case kArmFloat64Min: {
   1465       DwVfpRegister result = i.OutputDoubleRegister();
   1466       DwVfpRegister left = i.InputDoubleRegister(0);
   1467       DwVfpRegister right = i.InputDoubleRegister(1);
   1468       if (left.is(right)) {
   1469         __ Move(result, left);
   1470       } else {
   1471         auto ool = new (zone()) OutOfLineFloat64Min(this, result, left, right);
   1472         __ FloatMin(result, left, right, ool->entry());
   1473         __ bind(ool->exit());
   1474       }
   1475       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1476       break;
   1477     }
   1478     case kArmFloat64SilenceNaN: {
   1479       DwVfpRegister value = i.InputDoubleRegister(0);
   1480       DwVfpRegister result = i.OutputDoubleRegister();
   1481       __ VFPCanonicalizeNaN(result, value);
   1482       break;
   1483     }
   1484     case kArmPush:
   1485       if (instr->InputAt(0)->IsFPRegister()) {
   1486         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
   1487         if (op->representation() == MachineRepresentation::kFloat64) {
   1488           __ vpush(i.InputDoubleRegister(0));
   1489           frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   1490         } else {
   1491           DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
   1492           __ vpush(i.InputFloatRegister(0));
   1493           frame_access_state()->IncreaseSPDelta(1);
   1494         }
   1495       } else {
   1496         __ push(i.InputRegister(0));
   1497         frame_access_state()->IncreaseSPDelta(1);
   1498       }
   1499       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1500       break;
   1501     case kArmPoke: {
   1502       int const slot = MiscField::decode(instr->opcode());
   1503       __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
   1504       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1505       break;
   1506     }
   1507     case kArmFloat32x4Splat: {
   1508       __ vdup(i.OutputSimd128Register(), i.InputFloatRegister(0));
   1509       break;
   1510     }
   1511     case kArmFloat32x4ExtractLane: {
   1512       __ ExtractLane(i.OutputFloatRegister(), i.InputSimd128Register(0),
   1513                      kScratchReg, i.InputInt8(1));
   1514       break;
   1515     }
   1516     case kArmFloat32x4ReplaceLane: {
   1517       __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1518                      i.InputFloatRegister(2), kScratchReg, i.InputInt8(1));
   1519       break;
   1520     }
   1521     case kArmFloat32x4FromInt32x4: {
   1522       __ vcvt_f32_s32(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1523       break;
   1524     }
   1525     case kArmFloat32x4FromUint32x4: {
   1526       __ vcvt_f32_u32(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1527       break;
   1528     }
   1529     case kArmFloat32x4Abs: {
   1530       __ vabs(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1531       break;
   1532     }
   1533     case kArmFloat32x4Neg: {
   1534       __ vneg(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1535       break;
   1536     }
   1537     case kArmFloat32x4Add: {
   1538       __ vadd(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1539               i.InputSimd128Register(1));
   1540       break;
   1541     }
   1542     case kArmFloat32x4Sub: {
   1543       __ vsub(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1544               i.InputSimd128Register(1));
   1545       break;
   1546     }
   1547     case kArmFloat32x4Equal: {
   1548       __ vceq(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1549               i.InputSimd128Register(1));
   1550       break;
   1551     }
   1552     case kArmFloat32x4NotEqual: {
   1553       Simd128Register dst = i.OutputSimd128Register();
   1554       __ vceq(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
   1555       __ vmvn(dst, dst);
   1556       break;
   1557     }
   1558     case kArmInt32x4Splat: {
   1559       __ vdup(Neon32, i.OutputSimd128Register(), i.InputRegister(0));
   1560       break;
   1561     }
   1562     case kArmInt32x4ExtractLane: {
   1563       __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS32,
   1564                      i.InputInt8(1));
   1565       break;
   1566     }
   1567     case kArmInt32x4ReplaceLane: {
   1568       __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1569                      i.InputRegister(2), NeonS32, i.InputInt8(1));
   1570       break;
   1571     }
   1572     case kArmInt32x4FromFloat32x4: {
   1573       __ vcvt_s32_f32(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1574       break;
   1575     }
   1576     case kArmUint32x4FromFloat32x4: {
   1577       __ vcvt_u32_f32(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1578       break;
   1579     }
   1580     case kArmInt32x4Neg: {
   1581       __ vneg(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0));
   1582       break;
   1583     }
   1584     case kArmInt32x4ShiftLeftByScalar: {
   1585       __ vshl(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1586               i.InputInt5(1));
   1587       break;
   1588     }
   1589     case kArmInt32x4ShiftRightByScalar: {
   1590       __ vshr(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1591               i.InputInt5(1));
   1592       break;
   1593     }
   1594     case kArmInt32x4Add: {
   1595       __ vadd(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1596               i.InputSimd128Register(1));
   1597       break;
   1598     }
   1599     case kArmInt32x4Sub: {
   1600       __ vsub(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1601               i.InputSimd128Register(1));
   1602       break;
   1603     }
   1604     case kArmInt32x4Mul: {
   1605       __ vmul(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1606               i.InputSimd128Register(1));
   1607       break;
   1608     }
   1609     case kArmInt32x4Min: {
   1610       __ vmin(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1611               i.InputSimd128Register(1));
   1612       break;
   1613     }
   1614     case kArmInt32x4Max: {
   1615       __ vmax(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1616               i.InputSimd128Register(1));
   1617       break;
   1618     }
   1619     case kArmInt32x4Equal: {
   1620       __ vceq(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1621               i.InputSimd128Register(1));
   1622       break;
   1623     }
   1624     case kArmInt32x4NotEqual: {
   1625       Simd128Register dst = i.OutputSimd128Register();
   1626       __ vceq(Neon32, dst, i.InputSimd128Register(0),
   1627               i.InputSimd128Register(1));
   1628       __ vmvn(dst, dst);
   1629       break;
   1630     }
   1631     case kArmInt32x4GreaterThan: {
   1632       __ vcgt(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1633               i.InputSimd128Register(1));
   1634       break;
   1635     }
   1636     case kArmInt32x4GreaterThanOrEqual: {
   1637       Simd128Register dst = i.OutputSimd128Register();
   1638       __ vcge(NeonS32, dst, i.InputSimd128Register(0),
   1639               i.InputSimd128Register(1));
   1640       break;
   1641     }
   1642     case kArmUint32x4ShiftRightByScalar: {
   1643       __ vshr(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1644               i.InputInt5(1));
   1645       break;
   1646     }
   1647     case kArmUint32x4Min: {
   1648       __ vmin(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1649               i.InputSimd128Register(1));
   1650       break;
   1651     }
   1652     case kArmUint32x4Max: {
   1653       __ vmax(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1654               i.InputSimd128Register(1));
   1655       break;
   1656     }
   1657     case kArmUint32x4GreaterThan: {
   1658       __ vcgt(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1659               i.InputSimd128Register(1));
   1660       break;
   1661     }
   1662     case kArmUint32x4GreaterThanOrEqual: {
   1663       Simd128Register dst = i.OutputSimd128Register();
   1664       __ vcge(NeonU32, dst, i.InputSimd128Register(0),
   1665               i.InputSimd128Register(1));
   1666       break;
   1667     }
   1668     case kArmInt16x8Splat: {
   1669       __ vdup(Neon16, i.OutputSimd128Register(), i.InputRegister(0));
   1670       break;
   1671     }
   1672     case kArmInt16x8ExtractLane: {
   1673       __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS16,
   1674                      i.InputInt8(1));
   1675       break;
   1676     }
   1677     case kArmInt16x8ReplaceLane: {
   1678       __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1679                      i.InputRegister(2), NeonS16, i.InputInt8(1));
   1680       break;
   1681     }
   1682     case kArmInt16x8Neg: {
   1683       __ vneg(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0));
   1684       break;
   1685     }
   1686     case kArmInt16x8ShiftLeftByScalar: {
   1687       __ vshl(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1688               i.InputInt4(1));
   1689       break;
   1690     }
   1691     case kArmInt16x8ShiftRightByScalar: {
   1692       __ vshr(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1693               i.InputInt4(1));
   1694       break;
   1695     }
   1696     case kArmInt16x8Add: {
   1697       __ vadd(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1698               i.InputSimd128Register(1));
   1699       break;
   1700     }
   1701     case kArmInt16x8AddSaturate: {
   1702       __ vqadd(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1703                i.InputSimd128Register(1));
   1704       break;
   1705     }
   1706     case kArmInt16x8Sub: {
   1707       __ vsub(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1708               i.InputSimd128Register(1));
   1709       break;
   1710     }
   1711     case kArmInt16x8SubSaturate: {
   1712       __ vqsub(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1713                i.InputSimd128Register(1));
   1714       break;
   1715     }
   1716     case kArmInt16x8Mul: {
   1717       __ vmul(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1718               i.InputSimd128Register(1));
   1719       break;
   1720     }
   1721     case kArmInt16x8Min: {
   1722       __ vmin(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1723               i.InputSimd128Register(1));
   1724       break;
   1725     }
   1726     case kArmInt16x8Max: {
   1727       __ vmax(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1728               i.InputSimd128Register(1));
   1729       break;
   1730     }
   1731     case kArmInt16x8Equal: {
   1732       __ vceq(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1733               i.InputSimd128Register(1));
   1734       break;
   1735     }
   1736     case kArmInt16x8NotEqual: {
   1737       Simd128Register dst = i.OutputSimd128Register();
   1738       __ vceq(Neon16, dst, i.InputSimd128Register(0),
   1739               i.InputSimd128Register(1));
   1740       __ vmvn(dst, dst);
   1741       break;
   1742     }
   1743     case kArmInt16x8GreaterThan: {
   1744       __ vcgt(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1745               i.InputSimd128Register(1));
   1746       break;
   1747     }
   1748     case kArmInt16x8GreaterThanOrEqual: {
   1749       Simd128Register dst = i.OutputSimd128Register();
   1750       __ vcge(NeonS16, dst, i.InputSimd128Register(0),
   1751               i.InputSimd128Register(1));
   1752       break;
   1753     }
   1754     case kArmUint16x8ShiftRightByScalar: {
   1755       __ vshr(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1756               i.InputInt4(1));
   1757       break;
   1758     }
   1759     case kArmUint16x8AddSaturate: {
   1760       __ vqadd(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1761                i.InputSimd128Register(1));
   1762       break;
   1763     }
   1764     case kArmUint16x8SubSaturate: {
   1765       __ vqsub(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1766                i.InputSimd128Register(1));
   1767       break;
   1768     }
   1769     case kArmUint16x8Min: {
   1770       __ vmin(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1771               i.InputSimd128Register(1));
   1772       break;
   1773     }
   1774     case kArmUint16x8Max: {
   1775       __ vmax(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1776               i.InputSimd128Register(1));
   1777       break;
   1778     }
   1779     case kArmUint16x8GreaterThan: {
   1780       __ vcgt(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1781               i.InputSimd128Register(1));
   1782       break;
   1783     }
   1784     case kArmUint16x8GreaterThanOrEqual: {
   1785       Simd128Register dst = i.OutputSimd128Register();
   1786       __ vcge(NeonU16, dst, i.InputSimd128Register(0),
   1787               i.InputSimd128Register(1));
   1788       break;
   1789     }
   1790     case kArmInt8x16Splat: {
   1791       __ vdup(Neon8, i.OutputSimd128Register(), i.InputRegister(0));
   1792       break;
   1793     }
   1794     case kArmInt8x16ExtractLane: {
   1795       __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS8,
   1796                      i.InputInt8(1));
   1797       break;
   1798     }
   1799     case kArmInt8x16ReplaceLane: {
   1800       __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1801                      i.InputRegister(2), NeonS8, i.InputInt8(1));
   1802       break;
   1803     }
   1804     case kArmInt8x16Neg: {
   1805       __ vneg(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0));
   1806       break;
   1807     }
   1808     case kArmInt8x16ShiftLeftByScalar: {
   1809       __ vshl(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1810               i.InputInt3(1));
   1811       break;
   1812     }
   1813     case kArmInt8x16ShiftRightByScalar: {
   1814       __ vshr(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1815               i.InputInt3(1));
   1816       break;
   1817     }
   1818     case kArmInt8x16Add: {
   1819       __ vadd(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1820               i.InputSimd128Register(1));
   1821       break;
   1822     }
   1823     case kArmInt8x16AddSaturate: {
   1824       __ vqadd(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1825                i.InputSimd128Register(1));
   1826       break;
   1827     }
   1828     case kArmInt8x16Sub: {
   1829       __ vsub(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1830               i.InputSimd128Register(1));
   1831       break;
   1832     }
   1833     case kArmInt8x16SubSaturate: {
   1834       __ vqsub(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1835                i.InputSimd128Register(1));
   1836       break;
   1837     }
   1838     case kArmInt8x16Mul: {
   1839       __ vmul(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1840               i.InputSimd128Register(1));
   1841       break;
   1842     }
   1843     case kArmInt8x16Min: {
   1844       __ vmin(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1845               i.InputSimd128Register(1));
   1846       break;
   1847     }
   1848     case kArmInt8x16Max: {
   1849       __ vmax(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1850               i.InputSimd128Register(1));
   1851       break;
   1852     }
   1853     case kArmInt8x16Equal: {
   1854       __ vceq(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1855               i.InputSimd128Register(1));
   1856       break;
   1857     }
   1858     case kArmInt8x16NotEqual: {
   1859       Simd128Register dst = i.OutputSimd128Register();
   1860       __ vceq(Neon8, dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
   1861       __ vmvn(dst, dst);
   1862       break;
   1863     }
   1864     case kArmInt8x16GreaterThan: {
   1865       __ vcgt(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1866               i.InputSimd128Register(1));
   1867       break;
   1868     }
   1869     case kArmInt8x16GreaterThanOrEqual: {
   1870       Simd128Register dst = i.OutputSimd128Register();
   1871       __ vcge(NeonS8, dst, i.InputSimd128Register(0),
   1872               i.InputSimd128Register(1));
   1873       break;
   1874     }
   1875     case kArmUint8x16ShiftRightByScalar: {
   1876       __ vshr(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1877               i.InputInt3(1));
   1878       break;
   1879     }
   1880     case kArmUint8x16AddSaturate: {
   1881       __ vqadd(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1882                i.InputSimd128Register(1));
   1883       break;
   1884     }
   1885     case kArmUint8x16SubSaturate: {
   1886       __ vqsub(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1887                i.InputSimd128Register(1));
   1888       break;
   1889     }
   1890     case kArmUint8x16Min: {
   1891       __ vmin(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1892               i.InputSimd128Register(1));
   1893       break;
   1894     }
   1895     case kArmUint8x16Max: {
   1896       __ vmax(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1897               i.InputSimd128Register(1));
   1898       break;
   1899     }
   1900     case kArmUint8x16GreaterThan: {
   1901       __ vcgt(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
   1902               i.InputSimd128Register(1));
   1903       break;
   1904     }
   1905     case kArmUint8x16GreaterThanOrEqual: {
   1906       Simd128Register dst = i.OutputSimd128Register();
   1907       __ vcge(NeonU8, dst, i.InputSimd128Register(0),
   1908               i.InputSimd128Register(1));
   1909       break;
   1910     }
   1911     case kArmSimd128And: {
   1912       __ vand(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1913               i.InputSimd128Register(1));
   1914       break;
   1915     }
   1916     case kArmSimd128Or: {
   1917       __ vorr(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1918               i.InputSimd128Register(1));
   1919       break;
   1920     }
   1921     case kArmSimd128Xor: {
   1922       __ veor(i.OutputSimd128Register(), i.InputSimd128Register(0),
   1923               i.InputSimd128Register(1));
   1924       break;
   1925     }
   1926     case kArmSimd128Not: {
   1927       __ vmvn(i.OutputSimd128Register(), i.InputSimd128Register(0));
   1928       break;
   1929     }
   1930     case kArmSimd32x4Select:
   1931     case kArmSimd16x8Select:
   1932     case kArmSimd8x16Select: {
   1933       // vbsl clobbers the mask input so make sure it was DefineSameAsFirst.
   1934       DCHECK(i.OutputSimd128Register().is(i.InputSimd128Register(0)));
   1935       __ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1),
   1936               i.InputSimd128Register(2));
   1937       break;
   1938     }
   1939     case kCheckedLoadInt8:
   1940       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
   1941       break;
   1942     case kCheckedLoadUint8:
   1943       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
   1944       break;
   1945     case kCheckedLoadInt16:
   1946       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
   1947       break;
   1948     case kCheckedLoadUint16:
   1949       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
   1950       break;
   1951     case kCheckedLoadWord32:
   1952       ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
   1953       break;
   1954     case kCheckedLoadFloat32:
   1955       ASSEMBLE_CHECKED_LOAD_FP(Float);
   1956       break;
   1957     case kCheckedLoadFloat64:
   1958       ASSEMBLE_CHECKED_LOAD_FP(Double);
   1959       break;
   1960     case kCheckedStoreWord8:
   1961       ASSEMBLE_CHECKED_STORE_INTEGER(strb);
   1962       break;
   1963     case kCheckedStoreWord16:
   1964       ASSEMBLE_CHECKED_STORE_INTEGER(strh);
   1965       break;
   1966     case kCheckedStoreWord32:
   1967       ASSEMBLE_CHECKED_STORE_INTEGER(str);
   1968       break;
   1969     case kCheckedStoreFloat32:
   1970       ASSEMBLE_CHECKED_STORE_FP(Float);
   1971       break;
   1972     case kCheckedStoreFloat64:
   1973       ASSEMBLE_CHECKED_STORE_FP(Double);
   1974       break;
   1975     case kCheckedLoadWord64:
   1976     case kCheckedStoreWord64:
   1977       UNREACHABLE();  // currently unsupported checked int64 load/store.
   1978       break;
   1979 
   1980     case kAtomicLoadInt8:
   1981       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsb);
   1982       break;
   1983     case kAtomicLoadUint8:
   1984       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrb);
   1985       break;
   1986     case kAtomicLoadInt16:
   1987       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsh);
   1988       break;
   1989     case kAtomicLoadUint16:
   1990       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrh);
   1991       break;
   1992     case kAtomicLoadWord32:
   1993       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldr);
   1994       break;
   1995 
   1996     case kAtomicStoreWord8:
   1997       ASSEMBLE_ATOMIC_STORE_INTEGER(strb);
   1998       break;
   1999     case kAtomicStoreWord16:
   2000       ASSEMBLE_ATOMIC_STORE_INTEGER(strh);
   2001       break;
   2002     case kAtomicStoreWord32:
   2003       ASSEMBLE_ATOMIC_STORE_INTEGER(str);
   2004       break;
   2005   }
   2006   return kSuccess;
   2007 }  // NOLINT(readability/fn_size)
   2008 
   2009 
   2010 // Assembles branches after an instruction.
   2011 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   2012   ArmOperandConverter i(this, instr);
   2013   Label* tlabel = branch->true_label;
   2014   Label* flabel = branch->false_label;
   2015   Condition cc = FlagsConditionToCondition(branch->condition);
   2016   __ b(cc, tlabel);
   2017   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
   2018 }
   2019 
   2020 
   2021 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   2022   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
   2023 }
   2024 
   2025 void CodeGenerator::AssembleArchTrap(Instruction* instr,
   2026                                      FlagsCondition condition) {
   2027   class OutOfLineTrap final : public OutOfLineCode {
   2028    public:
   2029     OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
   2030         : OutOfLineCode(gen),
   2031           frame_elided_(frame_elided),
   2032           instr_(instr),
   2033           gen_(gen) {}
   2034 
   2035     void Generate() final {
   2036       ArmOperandConverter i(gen_, instr_);
   2037 
   2038       Builtins::Name trap_id =
   2039           static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
   2040       bool old_has_frame = __ has_frame();
   2041       if (frame_elided_) {
   2042         __ set_has_frame(true);
   2043         __ EnterFrame(StackFrame::WASM_COMPILED);
   2044       }
   2045       GenerateCallToTrap(trap_id);
   2046       if (frame_elided_) {
   2047         __ set_has_frame(old_has_frame);
   2048       }
   2049     }
   2050 
   2051    private:
   2052     void GenerateCallToTrap(Builtins::Name trap_id) {
   2053       if (trap_id == Builtins::builtin_count) {
   2054         // We cannot test calls to the runtime in cctest/test-run-wasm.
   2055         // Therefore we emit a call to C here instead of a call to the runtime.
   2056         // We use the context register as the scratch register, because we do
   2057         // not have a context here.
   2058         __ PrepareCallCFunction(0, 0, cp);
   2059         __ CallCFunction(
   2060             ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
   2061             0);
   2062         __ LeaveFrame(StackFrame::WASM_COMPILED);
   2063         __ Ret();
   2064       } else {
   2065         gen_->AssembleSourcePosition(instr_);
   2066         __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()),
   2067                 RelocInfo::CODE_TARGET);
   2068         ReferenceMap* reference_map =
   2069             new (gen_->zone()) ReferenceMap(gen_->zone());
   2070         gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
   2071                               Safepoint::kNoLazyDeopt);
   2072         if (FLAG_debug_code) {
   2073           __ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
   2074         }
   2075       }
   2076     }
   2077 
   2078     bool frame_elided_;
   2079     Instruction* instr_;
   2080     CodeGenerator* gen_;
   2081   };
   2082   bool frame_elided = !frame_access_state()->has_frame();
   2083   auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
   2084   Label* tlabel = ool->entry();
   2085   Condition cc = FlagsConditionToCondition(condition);
   2086   __ b(cc, tlabel);
   2087 }
   2088 
   2089 // Assembles boolean materializations after an instruction.
   2090 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   2091                                         FlagsCondition condition) {
   2092   ArmOperandConverter i(this, instr);
   2093 
   2094   // Materialize a full 32-bit 1 or 0 value. The result register is always the
   2095   // last output of the instruction.
   2096   DCHECK_NE(0u, instr->OutputCount());
   2097   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   2098   Condition cc = FlagsConditionToCondition(condition);
   2099   __ mov(reg, Operand(0));
   2100   __ mov(reg, Operand(1), LeaveCC, cc);
   2101 }
   2102 
   2103 
   2104 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   2105   ArmOperandConverter i(this, instr);
   2106   Register input = i.InputRegister(0);
   2107   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   2108     __ cmp(input, Operand(i.InputInt32(index + 0)));
   2109     __ b(eq, GetLabel(i.InputRpo(index + 1)));
   2110   }
   2111   AssembleArchJump(i.InputRpo(1));
   2112 }
   2113 
   2114 
   2115 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   2116   ArmOperandConverter i(this, instr);
   2117   Register input = i.InputRegister(0);
   2118   size_t const case_count = instr->InputCount() - 2;
   2119   // Ensure to emit the constant pool first if necessary.
   2120   __ CheckConstPool(true, true);
   2121   __ cmp(input, Operand(case_count));
   2122   __ BlockConstPoolFor(case_count + 2);
   2123   __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo);
   2124   __ b(GetLabel(i.InputRpo(1)));
   2125   for (size_t index = 0; index < case_count; ++index) {
   2126     __ b(GetLabel(i.InputRpo(index + 2)));
   2127   }
   2128 }
   2129 
   2130 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
   2131     int deoptimization_id, SourcePosition pos) {
   2132   DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
   2133   DeoptimizeReason deoptimization_reason =
   2134       GetDeoptimizationReason(deoptimization_id);
   2135   Deoptimizer::BailoutType bailout_type =
   2136       deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
   2137                                                    : Deoptimizer::EAGER;
   2138   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   2139       isolate(), deoptimization_id, bailout_type);
   2140   // TODO(turbofan): We should be able to generate better code by sharing the
   2141   // actual final call site and just bl'ing to it here, similar to what we do
   2142   // in the lithium backend.
   2143   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
   2144   __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
   2145   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   2146   __ CheckConstPool(false, false);
   2147   return kSuccess;
   2148 }
   2149 
   2150 void CodeGenerator::FinishFrame(Frame* frame) {
   2151   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2152 
   2153   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2154   if (saves_fp != 0) {
   2155     frame->AlignSavedCalleeRegisterSlots();
   2156   }
   2157 
   2158   if (saves_fp != 0) {
   2159     // Save callee-saved FP registers.
   2160     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   2161     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   2162     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   2163     DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
   2164     frame->AllocateSavedCalleeRegisterSlots((last - first + 1) *
   2165                                             (kDoubleSize / kPointerSize));
   2166   }
   2167   const RegList saves = FLAG_enable_embedded_constant_pool
   2168                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   2169                             : descriptor->CalleeSavedRegisters();
   2170   if (saves != 0) {
   2171     // Save callee-saved registers.
   2172     frame->AllocateSavedCalleeRegisterSlots(
   2173         base::bits::CountPopulation32(saves));
   2174   }
   2175 }
   2176 
   2177 void CodeGenerator::AssembleConstructFrame() {
   2178   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2179   if (frame_access_state()->has_frame()) {
   2180     if (descriptor->IsCFunctionCall()) {
   2181       if (FLAG_enable_embedded_constant_pool) {
   2182         __ Push(lr, fp, pp);
   2183         // Adjust FP to point to saved FP.
   2184         __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
   2185       } else {
   2186         __ Push(lr, fp);
   2187         __ mov(fp, sp);
   2188       }
   2189     } else if (descriptor->IsJSFunctionCall()) {
   2190       __ Prologue(this->info()->GeneratePreagedPrologue());
   2191       if (descriptor->PushArgumentCount()) {
   2192         __ Push(kJavaScriptCallArgCountRegister);
   2193       }
   2194     } else {
   2195       __ StubPrologue(info()->GetOutputStackFrameType());
   2196     }
   2197 
   2198     if (!info()->GeneratePreagedPrologue()) {
   2199       unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
   2200     }
   2201   }
   2202 
   2203   int shrink_slots =
   2204       frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
   2205 
   2206   if (info()->is_osr()) {
   2207     // TurboFan OSR-compiled functions cannot be entered directly.
   2208     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   2209 
   2210     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   2211     // frame is still on the stack. Optimized code uses OSR values directly from
   2212     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   2213     // remaining stack slots.
   2214     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   2215     osr_pc_offset_ = __ pc_offset();
   2216     shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
   2217   }
   2218 
   2219   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2220   if (shrink_slots > 0) {
   2221     __ sub(sp, sp, Operand(shrink_slots * kPointerSize));
   2222   }
   2223 
   2224   if (saves_fp != 0) {
   2225     // Save callee-saved FP registers.
   2226     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   2227     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   2228     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   2229     DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
   2230     __ vstm(db_w, sp, DwVfpRegister::from_code(first),
   2231             DwVfpRegister::from_code(last));
   2232   }
   2233   const RegList saves = FLAG_enable_embedded_constant_pool
   2234                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   2235                             : descriptor->CalleeSavedRegisters();
   2236   if (saves != 0) {
   2237     // Save callee-saved registers.
   2238     __ stm(db_w, sp, saves);
   2239   }
   2240 }
   2241 
   2242 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
   2243   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2244   int pop_count = static_cast<int>(descriptor->StackParameterCount());
   2245 
   2246   // Restore registers.
   2247   const RegList saves = FLAG_enable_embedded_constant_pool
   2248                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   2249                             : descriptor->CalleeSavedRegisters();
   2250   if (saves != 0) {
   2251     __ ldm(ia_w, sp, saves);
   2252   }
   2253 
   2254   // Restore FP registers.
   2255   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2256   if (saves_fp != 0) {
   2257     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   2258     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   2259     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   2260     __ vldm(ia_w, sp, DwVfpRegister::from_code(first),
   2261             DwVfpRegister::from_code(last));
   2262   }
   2263 
   2264   unwinding_info_writer_.MarkBlockWillExit();
   2265 
   2266   ArmOperandConverter g(this, nullptr);
   2267   if (descriptor->IsCFunctionCall()) {
   2268     AssembleDeconstructFrame();
   2269   } else if (frame_access_state()->has_frame()) {
   2270     // Canonicalize JSFunction return sites for now unless they have an variable
   2271     // number of stack slot pops.
   2272     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
   2273       if (return_label_.is_bound()) {
   2274         __ b(&return_label_);
   2275         return;
   2276       } else {
   2277         __ bind(&return_label_);
   2278         AssembleDeconstructFrame();
   2279       }
   2280     } else {
   2281       AssembleDeconstructFrame();
   2282     }
   2283   }
   2284 
   2285   if (pop->IsImmediate()) {
   2286     DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
   2287     pop_count += g.ToConstant(pop).ToInt32();
   2288   } else {
   2289     __ Drop(g.ToRegister(pop));
   2290   }
   2291   __ Drop(pop_count);
   2292   __ Ret();
   2293 }
   2294 
   2295 void CodeGenerator::AssembleMove(InstructionOperand* source,
   2296                                  InstructionOperand* destination) {
   2297   ArmOperandConverter g(this, nullptr);
   2298   // Dispatch on the source and destination operand kinds.  Not all
   2299   // combinations are possible.
   2300   if (source->IsRegister()) {
   2301     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2302     Register src = g.ToRegister(source);
   2303     if (destination->IsRegister()) {
   2304       __ mov(g.ToRegister(destination), src);
   2305     } else {
   2306       __ str(src, g.ToMemOperand(destination));
   2307     }
   2308   } else if (source->IsStackSlot()) {
   2309     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2310     MemOperand src = g.ToMemOperand(source);
   2311     if (destination->IsRegister()) {
   2312       __ ldr(g.ToRegister(destination), src);
   2313     } else {
   2314       Register temp = kScratchReg;
   2315       __ ldr(temp, src);
   2316       __ str(temp, g.ToMemOperand(destination));
   2317     }
   2318   } else if (source->IsConstant()) {
   2319     Constant src = g.ToConstant(source);
   2320     if (destination->IsRegister() || destination->IsStackSlot()) {
   2321       Register dst =
   2322           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
   2323       switch (src.type()) {
   2324         case Constant::kInt32:
   2325           if (RelocInfo::IsWasmReference(src.rmode())) {
   2326             __ mov(dst, Operand(src.ToInt32(), src.rmode()));
   2327           } else {
   2328             __ mov(dst, Operand(src.ToInt32()));
   2329           }
   2330           break;
   2331         case Constant::kInt64:
   2332           UNREACHABLE();
   2333           break;
   2334         case Constant::kFloat32:
   2335           __ Move(dst,
   2336                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   2337           break;
   2338         case Constant::kFloat64:
   2339           __ Move(dst,
   2340                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   2341           break;
   2342         case Constant::kExternalReference:
   2343           __ mov(dst, Operand(src.ToExternalReference()));
   2344           break;
   2345         case Constant::kHeapObject: {
   2346           Handle<HeapObject> src_object = src.ToHeapObject();
   2347           Heap::RootListIndex index;
   2348           if (IsMaterializableFromRoot(src_object, &index)) {
   2349             __ LoadRoot(dst, index);
   2350           } else {
   2351             __ Move(dst, src_object);
   2352           }
   2353           break;
   2354         }
   2355         case Constant::kRpoNumber:
   2356           UNREACHABLE();  // TODO(dcarney): loading RPO constants on arm.
   2357           break;
   2358       }
   2359       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
   2360     } else if (src.type() == Constant::kFloat32) {
   2361       if (destination->IsFloatStackSlot()) {
   2362         MemOperand dst = g.ToMemOperand(destination);
   2363         __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
   2364         __ str(ip, dst);
   2365       } else {
   2366         SwVfpRegister dst = g.ToFloatRegister(destination);
   2367         __ vmov(dst, src.ToFloat32());
   2368       }
   2369     } else {
   2370       DCHECK_EQ(Constant::kFloat64, src.type());
   2371       DwVfpRegister dst = destination->IsFPRegister()
   2372                               ? g.ToDoubleRegister(destination)
   2373                               : kScratchDoubleReg;
   2374       __ vmov(dst, src.ToFloat64(), kScratchReg);
   2375       if (destination->IsDoubleStackSlot()) {
   2376         __ vstr(dst, g.ToMemOperand(destination));
   2377       }
   2378     }
   2379   } else if (source->IsFPRegister()) {
   2380     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2381     if (rep == MachineRepresentation::kFloat64) {
   2382       DwVfpRegister src = g.ToDoubleRegister(source);
   2383       if (destination->IsDoubleRegister()) {
   2384         DwVfpRegister dst = g.ToDoubleRegister(destination);
   2385         __ Move(dst, src);
   2386       } else {
   2387         DCHECK(destination->IsDoubleStackSlot());
   2388         __ vstr(src, g.ToMemOperand(destination));
   2389       }
   2390     } else if (rep == MachineRepresentation::kFloat32) {
   2391       // GapResolver may give us reg codes that don't map to actual s-registers.
   2392       // Generate code to work around those cases.
   2393       int src_code = LocationOperand::cast(source)->register_code();
   2394       if (destination->IsFloatRegister()) {
   2395         int dst_code = LocationOperand::cast(destination)->register_code();
   2396         __ VmovExtended(dst_code, src_code, kScratchReg);
   2397       } else {
   2398         DCHECK(destination->IsFloatStackSlot());
   2399         __ VmovExtended(g.ToMemOperand(destination), src_code, kScratchReg);
   2400       }
   2401     } else {
   2402       DCHECK_EQ(MachineRepresentation::kSimd128, rep);
   2403       QwNeonRegister src = g.ToSimd128Register(source);
   2404       if (destination->IsSimd128Register()) {
   2405         QwNeonRegister dst = g.ToSimd128Register(destination);
   2406         __ Move(dst, src);
   2407       } else {
   2408         DCHECK(destination->IsSimd128StackSlot());
   2409         MemOperand dst = g.ToMemOperand(destination);
   2410         __ add(kScratchReg, dst.rn(), Operand(dst.offset()));
   2411         __ vst1(Neon8, NeonListOperand(src.low(), 2),
   2412                 NeonMemOperand(kScratchReg));
   2413       }
   2414     }
   2415   } else if (source->IsFPStackSlot()) {
   2416     MemOperand src = g.ToMemOperand(source);
   2417     MachineRepresentation rep =
   2418         LocationOperand::cast(destination)->representation();
   2419     if (destination->IsFPRegister()) {
   2420       if (rep == MachineRepresentation::kFloat64) {
   2421         __ vldr(g.ToDoubleRegister(destination), src);
   2422       } else if (rep == MachineRepresentation::kFloat32) {
   2423         // GapResolver may give us reg codes that don't map to actual
   2424         // s-registers. Generate code to work around those cases.
   2425         int dst_code = LocationOperand::cast(destination)->register_code();
   2426         __ VmovExtended(dst_code, src, kScratchReg);
   2427       } else {
   2428         DCHECK_EQ(MachineRepresentation::kSimd128, rep);
   2429         QwNeonRegister dst = g.ToSimd128Register(destination);
   2430         __ add(kScratchReg, src.rn(), Operand(src.offset()));
   2431         __ vld1(Neon8, NeonListOperand(dst.low(), 2),
   2432                 NeonMemOperand(kScratchReg));
   2433       }
   2434     } else if (rep == MachineRepresentation::kFloat64) {
   2435       DCHECK(destination->IsFPStackSlot());
   2436       if (rep == MachineRepresentation::kFloat64) {
   2437         DwVfpRegister temp = kScratchDoubleReg;
   2438         __ vldr(temp, src);
   2439         __ vstr(temp, g.ToMemOperand(destination));
   2440       } else if (rep == MachineRepresentation::kFloat32) {
   2441         SwVfpRegister temp = kScratchDoubleReg.low();
   2442         __ vldr(temp, src);
   2443         __ vstr(temp, g.ToMemOperand(destination));
   2444       } else {
   2445         DCHECK_EQ(MachineRepresentation::kSimd128, rep);
   2446         MemOperand dst = g.ToMemOperand(destination);
   2447         __ add(kScratchReg, src.rn(), Operand(src.offset()));
   2448         __ vld1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2),
   2449                 NeonMemOperand(kScratchReg));
   2450         __ add(kScratchReg, dst.rn(), Operand(dst.offset()));
   2451         __ vst1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2),
   2452                 NeonMemOperand(kScratchReg));
   2453         __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero);
   2454       }
   2455     }
   2456   } else {
   2457     UNREACHABLE();
   2458   }
   2459 }
   2460 
   2461 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   2462                                  InstructionOperand* destination) {
   2463   ArmOperandConverter g(this, nullptr);
   2464   // Dispatch on the source and destination operand kinds.  Not all
   2465   // combinations are possible.
   2466   if (source->IsRegister()) {
   2467     // Register-register.
   2468     Register temp = kScratchReg;
   2469     Register src = g.ToRegister(source);
   2470     if (destination->IsRegister()) {
   2471       Register dst = g.ToRegister(destination);
   2472       __ Move(temp, src);
   2473       __ Move(src, dst);
   2474       __ Move(dst, temp);
   2475     } else {
   2476       DCHECK(destination->IsStackSlot());
   2477       MemOperand dst = g.ToMemOperand(destination);
   2478       __ mov(temp, src);
   2479       __ ldr(src, dst);
   2480       __ str(temp, dst);
   2481     }
   2482   } else if (source->IsStackSlot()) {
   2483     DCHECK(destination->IsStackSlot());
   2484     Register temp_0 = kScratchReg;
   2485     SwVfpRegister temp_1 = kScratchDoubleReg.low();
   2486     MemOperand src = g.ToMemOperand(source);
   2487     MemOperand dst = g.ToMemOperand(destination);
   2488     __ ldr(temp_0, src);
   2489     __ vldr(temp_1, dst);
   2490     __ str(temp_0, dst);
   2491     __ vstr(temp_1, src);
   2492   } else if (source->IsFPRegister()) {
   2493     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2494     LowDwVfpRegister temp = kScratchDoubleReg;
   2495     if (rep == MachineRepresentation::kFloat64) {
   2496       DwVfpRegister src = g.ToDoubleRegister(source);
   2497       if (destination->IsFPRegister()) {
   2498         DwVfpRegister dst = g.ToDoubleRegister(destination);
   2499         __ Swap(src, dst);
   2500       } else {
   2501         DCHECK(destination->IsFPStackSlot());
   2502         MemOperand dst = g.ToMemOperand(destination);
   2503         __ Move(temp, src);
   2504         __ vldr(src, dst);
   2505         __ vstr(temp, dst);
   2506       }
   2507     } else if (rep == MachineRepresentation::kFloat32) {
   2508       int src_code = LocationOperand::cast(source)->register_code();
   2509       if (destination->IsFPRegister()) {
   2510         int dst_code = LocationOperand::cast(destination)->register_code();
   2511         __ VmovExtended(temp.low().code(), src_code, kScratchReg);
   2512         __ VmovExtended(src_code, dst_code, kScratchReg);
   2513         __ VmovExtended(dst_code, temp.low().code(), kScratchReg);
   2514       } else {
   2515         DCHECK(destination->IsFPStackSlot());
   2516         MemOperand dst = g.ToMemOperand(destination);
   2517         __ VmovExtended(temp.low().code(), src_code, kScratchReg);
   2518         __ VmovExtended(src_code, dst, kScratchReg);
   2519         __ vstr(temp.low(), dst);
   2520       }
   2521     } else {
   2522       DCHECK_EQ(MachineRepresentation::kSimd128, rep);
   2523       QwNeonRegister src = g.ToSimd128Register(source);
   2524       if (destination->IsFPRegister()) {
   2525         QwNeonRegister dst = g.ToSimd128Register(destination);
   2526         __ Swap(src, dst);
   2527       } else {
   2528         DCHECK(destination->IsFPStackSlot());
   2529         MemOperand dst = g.ToMemOperand(destination);
   2530         __ Move(kScratchQuadReg, src);
   2531         __ add(kScratchReg, dst.rn(), Operand(dst.offset()));
   2532         __ vld1(Neon8, NeonListOperand(src.low(), 2),
   2533                 NeonMemOperand(kScratchReg));
   2534         __ vst1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2),
   2535                 NeonMemOperand(kScratchReg));
   2536         __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero);
   2537       }
   2538     }
   2539   } else if (source->IsFPStackSlot()) {
   2540     DCHECK(destination->IsFPStackSlot());
   2541     MemOperand src = g.ToMemOperand(source);
   2542     MemOperand dst = g.ToMemOperand(destination);
   2543     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2544     if (rep == MachineRepresentation::kFloat64) {
   2545       __ vldr(kScratchDoubleReg, dst);
   2546       __ vldr(kDoubleRegZero, src);
   2547       __ vstr(kScratchDoubleReg, src);
   2548       __ vstr(kDoubleRegZero, dst);
   2549       // Restore the 0 register.
   2550       __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero);
   2551     } else if (rep == MachineRepresentation::kFloat32) {
   2552       __ vldr(kScratchDoubleReg.low(), dst);
   2553       __ vldr(kScratchDoubleReg.high(), src);
   2554       __ vstr(kScratchDoubleReg.low(), src);
   2555       __ vstr(kScratchDoubleReg.high(), dst);
   2556     } else {
   2557       DCHECK_EQ(MachineRepresentation::kSimd128, rep);
   2558       __ vldr(kScratchDoubleReg, dst);
   2559       __ vldr(kDoubleRegZero, src);
   2560       __ vstr(kScratchDoubleReg, src);
   2561       __ vstr(kDoubleRegZero, dst);
   2562       src.set_offset(src.offset() + kDoubleSize);
   2563       dst.set_offset(dst.offset() + kDoubleSize);
   2564       __ vldr(kScratchDoubleReg, dst);
   2565       __ vldr(kDoubleRegZero, src);
   2566       __ vstr(kScratchDoubleReg, src);
   2567       __ vstr(kDoubleRegZero, dst);
   2568       // Restore the 0 register.
   2569       __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero);
   2570     }
   2571   } else {
   2572     // No other combinations are possible.
   2573     UNREACHABLE();
   2574   }
   2575 }
   2576 
   2577 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   2578   // On 32-bit ARM we emit the jump tables inline.
   2579   UNREACHABLE();
   2580 }
   2581 
   2582 
   2583 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   2584   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   2585     return;
   2586   }
   2587 
   2588   int space_needed = Deoptimizer::patch_size();
   2589   // Ensure that we have enough space after the previous lazy-bailout
   2590   // instruction for patching the code here.
   2591   int current_pc = masm()->pc_offset();
   2592   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   2593     // Block literal pool emission for duration of padding.
   2594     v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
   2595     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   2596     DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
   2597     while (padding_size > 0) {
   2598       __ nop();
   2599       padding_size -= v8::internal::Assembler::kInstrSize;
   2600     }
   2601   }
   2602 }
   2603 
   2604 #undef __
   2605 
   2606 }  // namespace compiler
   2607 }  // namespace internal
   2608 }  // namespace v8
   2609