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/ast/scopes.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         return SetCC;
     36       case kFlags_none:
     37         return LeaveCC;
     38     }
     39     UNREACHABLE();
     40     return LeaveCC;
     41   }
     42 
     43   Operand InputImmediate(size_t index) {
     44     Constant constant = ToConstant(instr_->InputAt(index));
     45     switch (constant.type()) {
     46       case Constant::kInt32:
     47         return Operand(constant.ToInt32());
     48       case Constant::kFloat32:
     49         return Operand(
     50             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
     51       case Constant::kFloat64:
     52         return Operand(
     53             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
     54       case Constant::kInt64:
     55       case Constant::kExternalReference:
     56       case Constant::kHeapObject:
     57       case Constant::kRpoNumber:
     58         break;
     59     }
     60     UNREACHABLE();
     61     return Operand::Zero();
     62   }
     63 
     64   Operand InputOperand2(size_t first_index) {
     65     const size_t index = first_index;
     66     switch (AddressingModeField::decode(instr_->opcode())) {
     67       case kMode_None:
     68       case kMode_Offset_RI:
     69       case kMode_Offset_RR:
     70         break;
     71       case kMode_Operand2_I:
     72         return InputImmediate(index + 0);
     73       case kMode_Operand2_R:
     74         return Operand(InputRegister(index + 0));
     75       case kMode_Operand2_R_ASR_I:
     76         return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1));
     77       case kMode_Operand2_R_ASR_R:
     78         return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1));
     79       case kMode_Operand2_R_LSL_I:
     80         return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1));
     81       case kMode_Operand2_R_LSL_R:
     82         return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1));
     83       case kMode_Operand2_R_LSR_I:
     84         return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
     85       case kMode_Operand2_R_LSR_R:
     86         return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
     87       case kMode_Operand2_R_ROR_I:
     88         return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
     89       case kMode_Operand2_R_ROR_R:
     90         return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
     91     }
     92     UNREACHABLE();
     93     return Operand::Zero();
     94   }
     95 
     96   MemOperand InputOffset(size_t* first_index) {
     97     const size_t index = *first_index;
     98     switch (AddressingModeField::decode(instr_->opcode())) {
     99       case kMode_None:
    100       case kMode_Operand2_I:
    101       case kMode_Operand2_R:
    102       case kMode_Operand2_R_ASR_I:
    103       case kMode_Operand2_R_ASR_R:
    104       case kMode_Operand2_R_LSL_R:
    105       case kMode_Operand2_R_LSR_I:
    106       case kMode_Operand2_R_LSR_R:
    107       case kMode_Operand2_R_ROR_I:
    108       case kMode_Operand2_R_ROR_R:
    109         break;
    110       case kMode_Operand2_R_LSL_I:
    111         *first_index += 3;
    112         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
    113                           LSL, InputInt32(index + 2));
    114       case kMode_Offset_RI:
    115         *first_index += 2;
    116         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
    117       case kMode_Offset_RR:
    118         *first_index += 2;
    119         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
    120     }
    121     UNREACHABLE();
    122     return MemOperand(r0);
    123   }
    124 
    125   MemOperand InputOffset(size_t first_index = 0) {
    126     return InputOffset(&first_index);
    127   }
    128 
    129   MemOperand ToMemOperand(InstructionOperand* op) const {
    130     DCHECK_NOT_NULL(op);
    131     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
    132     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
    133   }
    134 
    135   MemOperand SlotToMemOperand(int slot) const {
    136     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
    137     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
    138   }
    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       : OutOfLineCode(gen),
    193         object_(object),
    194         index_(index),
    195         index_immediate_(0),
    196         value_(value),
    197         scratch0_(scratch0),
    198         scratch1_(scratch1),
    199         mode_(mode),
    200         must_save_lr_(!gen->frame_access_state()->has_frame()) {}
    201 
    202   OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
    203                        Register value, Register scratch0, Register scratch1,
    204                        RecordWriteMode mode)
    205       : OutOfLineCode(gen),
    206         object_(object),
    207         index_(no_reg),
    208         index_immediate_(index),
    209         value_(value),
    210         scratch0_(scratch0),
    211         scratch1_(scratch1),
    212         mode_(mode),
    213         must_save_lr_(!gen->frame_access_state()->has_frame()) {}
    214 
    215   void Generate() final {
    216     if (mode_ > RecordWriteMode::kValueIsPointer) {
    217       __ JumpIfSmi(value_, exit());
    218     }
    219     __ CheckPageFlag(value_, scratch0_,
    220                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
    221                      exit());
    222     RememberedSetAction const remembered_set_action =
    223         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
    224                                              : OMIT_REMEMBERED_SET;
    225     SaveFPRegsMode const save_fp_mode =
    226         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    227     if (must_save_lr_) {
    228       // We need to save and restore lr if the frame was elided.
    229       __ Push(lr);
    230     }
    231     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    232                          remembered_set_action, save_fp_mode);
    233     if (index_.is(no_reg)) {
    234       __ add(scratch1_, object_, Operand(index_immediate_));
    235     } else {
    236       DCHECK_EQ(0, index_immediate_);
    237       __ add(scratch1_, object_, Operand(index_));
    238     }
    239     __ CallStub(&stub);
    240     if (must_save_lr_) {
    241       __ Pop(lr);
    242     }
    243   }
    244 
    245  private:
    246   Register const object_;
    247   Register const index_;
    248   int32_t const index_immediate_;  // Valid if index_.is(no_reg).
    249   Register const value_;
    250   Register const scratch0_;
    251   Register const scratch1_;
    252   RecordWriteMode const mode_;
    253   bool must_save_lr_;
    254 };
    255 
    256 
    257 Condition FlagsConditionToCondition(FlagsCondition condition) {
    258   switch (condition) {
    259     case kEqual:
    260       return eq;
    261     case kNotEqual:
    262       return ne;
    263     case kSignedLessThan:
    264       return lt;
    265     case kSignedGreaterThanOrEqual:
    266       return ge;
    267     case kSignedLessThanOrEqual:
    268       return le;
    269     case kSignedGreaterThan:
    270       return gt;
    271     case kUnsignedLessThan:
    272       return lo;
    273     case kUnsignedGreaterThanOrEqual:
    274       return hs;
    275     case kUnsignedLessThanOrEqual:
    276       return ls;
    277     case kUnsignedGreaterThan:
    278       return hi;
    279     case kFloatLessThanOrUnordered:
    280       return lt;
    281     case kFloatGreaterThanOrEqual:
    282       return ge;
    283     case kFloatLessThanOrEqual:
    284       return ls;
    285     case kFloatGreaterThanOrUnordered:
    286       return hi;
    287     case kFloatLessThan:
    288       return lo;
    289     case kFloatGreaterThanOrEqualOrUnordered:
    290       return hs;
    291     case kFloatLessThanOrEqualOrUnordered:
    292       return le;
    293     case kFloatGreaterThan:
    294       return gt;
    295     case kOverflow:
    296       return vs;
    297     case kNotOverflow:
    298       return vc;
    299     default:
    300       break;
    301   }
    302   UNREACHABLE();
    303   return kNoCondition;
    304 }
    305 
    306 }  // namespace
    307 
    308 #define ASSEMBLE_CHECKED_LOAD_FP(Type)                         \
    309   do {                                                         \
    310     auto result = i.Output##Type##Register();                  \
    311     auto offset = i.InputRegister(0);                          \
    312     if (instr->InputAt(1)->IsRegister()) {                     \
    313       __ cmp(offset, i.InputRegister(1));                      \
    314     } else {                                                   \
    315       __ cmp(offset, i.InputImmediate(1));                     \
    316     }                                                          \
    317     auto ool = new (zone()) OutOfLineLoad##Type(this, result); \
    318     __ b(hs, ool->entry());                                    \
    319     __ vldr(result, i.InputOffset(2));                         \
    320     __ bind(ool->exit());                                      \
    321     DCHECK_EQ(LeaveCC, i.OutputSBit());                        \
    322   } while (0)
    323 
    324 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                \
    325   do {                                                          \
    326     auto result = i.OutputRegister();                           \
    327     auto offset = i.InputRegister(0);                           \
    328     if (instr->InputAt(1)->IsRegister()) {                      \
    329       __ cmp(offset, i.InputRegister(1));                       \
    330     } else {                                                    \
    331       __ cmp(offset, i.InputImmediate(1));                      \
    332     }                                                           \
    333     auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
    334     __ b(hs, ool->entry());                                     \
    335     __ asm_instr(result, i.InputOffset(2));                     \
    336     __ bind(ool->exit());                                       \
    337     DCHECK_EQ(LeaveCC, i.OutputSBit());                         \
    338   } while (0)
    339 
    340 #define ASSEMBLE_CHECKED_STORE_FP(Type)      \
    341   do {                                       \
    342     auto offset = i.InputRegister(0);        \
    343     if (instr->InputAt(1)->IsRegister()) {   \
    344       __ cmp(offset, i.InputRegister(1));    \
    345     } else {                                 \
    346       __ cmp(offset, i.InputImmediate(1));   \
    347     }                                        \
    348     auto value = i.Input##Type##Register(2); \
    349     __ vstr(value, i.InputOffset(3), lo);    \
    350     DCHECK_EQ(LeaveCC, i.OutputSBit());      \
    351   } while (0)
    352 
    353 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
    354   do {                                            \
    355     auto offset = i.InputRegister(0);             \
    356     if (instr->InputAt(1)->IsRegister()) {        \
    357       __ cmp(offset, i.InputRegister(1));         \
    358     } else {                                      \
    359       __ cmp(offset, i.InputImmediate(1));        \
    360     }                                             \
    361     auto value = i.InputRegister(2);              \
    362     __ asm_instr(value, i.InputOffset(3), lo);    \
    363     DCHECK_EQ(LeaveCC, i.OutputSBit());           \
    364   } while (0)
    365 
    366 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)                       \
    367   do {                                                                \
    368     __ asm_instr(i.OutputRegister(),                                  \
    369                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    370     __ dmb(ISH);                                                      \
    371   } while (0)
    372 
    373 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)                      \
    374   do {                                                                \
    375     __ dmb(ISH);                                                      \
    376     __ asm_instr(i.InputRegister(2),                                  \
    377                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    378     __ dmb(ISH);                                                      \
    379   } while (0)
    380 
    381 #define ASSEMBLE_IEEE754_BINOP(name)                                           \
    382   do {                                                                         \
    383     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
    384     /* and generate a CallAddress instruction instead. */                      \
    385     FrameScope scope(masm(), StackFrame::MANUAL);                              \
    386     __ PrepareCallCFunction(0, 2, kScratchReg);                                \
    387     __ MovToFloatParameters(i.InputDoubleRegister(0),                          \
    388                             i.InputDoubleRegister(1));                         \
    389     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
    390                      0, 2);                                                    \
    391     /* Move the result in the double result register. */                       \
    392     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
    393     DCHECK_EQ(LeaveCC, i.OutputSBit());                                        \
    394   } while (0)
    395 
    396 #define ASSEMBLE_IEEE754_UNOP(name)                                            \
    397   do {                                                                         \
    398     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
    399     /* and generate a CallAddress instruction instead. */                      \
    400     FrameScope scope(masm(), StackFrame::MANUAL);                              \
    401     __ PrepareCallCFunction(0, 1, kScratchReg);                                \
    402     __ MovToFloatParameter(i.InputDoubleRegister(0));                          \
    403     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
    404                      0, 1);                                                    \
    405     /* Move the result in the double result register. */                       \
    406     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
    407     DCHECK_EQ(LeaveCC, i.OutputSBit());                                        \
    408   } while (0)
    409 
    410 void CodeGenerator::AssembleDeconstructFrame() {
    411   __ LeaveFrame(StackFrame::MANUAL);
    412 }
    413 
    414 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
    415   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    416   if (sp_slot_delta > 0) {
    417     __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
    418   }
    419   frame_access_state()->SetFrameAccessToDefault();
    420 }
    421 
    422 
    423 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
    424   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    425   if (sp_slot_delta < 0) {
    426     __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
    427     frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
    428   }
    429   if (frame_access_state()->has_frame()) {
    430     if (FLAG_enable_embedded_constant_pool) {
    431       __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
    432     }
    433     __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    434     __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    435   }
    436   frame_access_state()->SetFrameAccessToSP();
    437 }
    438 
    439 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
    440                                                      Register scratch1,
    441                                                      Register scratch2,
    442                                                      Register scratch3) {
    443   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
    444   Label done;
    445 
    446   // Check if current frame is an arguments adaptor frame.
    447   __ ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
    448   __ cmp(scratch1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
    449   __ b(ne, &done);
    450 
    451   // Load arguments count from current arguments adaptor frame (note, it
    452   // does not include receiver).
    453   Register caller_args_count_reg = scratch1;
    454   __ ldr(caller_args_count_reg,
    455          MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
    456   __ SmiUntag(caller_args_count_reg);
    457 
    458   ParameterCount callee_args_count(args_reg);
    459   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
    460                         scratch3);
    461   __ bind(&done);
    462 }
    463 
    464 // Assembles an instruction after register allocation, producing machine code.
    465 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    466     Instruction* instr) {
    467   ArmOperandConverter i(this, instr);
    468 
    469   __ MaybeCheckConstPool();
    470   InstructionCode opcode = instr->opcode();
    471   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
    472   switch (arch_opcode) {
    473     case kArchCallCodeObject: {
    474       EnsureSpaceForLazyDeopt();
    475       if (instr->InputAt(0)->IsImmediate()) {
    476         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
    477                 RelocInfo::CODE_TARGET);
    478       } else {
    479         __ add(ip, i.InputRegister(0),
    480                Operand(Code::kHeaderSize - kHeapObjectTag));
    481         __ Call(ip);
    482       }
    483       RecordCallPosition(instr);
    484       DCHECK_EQ(LeaveCC, i.OutputSBit());
    485       frame_access_state()->ClearSPDelta();
    486       break;
    487     }
    488     case kArchTailCallCodeObjectFromJSFunction:
    489     case kArchTailCallCodeObject: {
    490       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    491       AssembleDeconstructActivationRecord(stack_param_delta);
    492       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
    493         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    494                                          i.TempRegister(0), i.TempRegister(1),
    495                                          i.TempRegister(2));
    496       }
    497       if (instr->InputAt(0)->IsImmediate()) {
    498         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
    499                 RelocInfo::CODE_TARGET);
    500       } else {
    501         __ add(ip, i.InputRegister(0),
    502                Operand(Code::kHeaderSize - kHeapObjectTag));
    503         __ Jump(ip);
    504       }
    505       DCHECK_EQ(LeaveCC, i.OutputSBit());
    506       frame_access_state()->ClearSPDelta();
    507       break;
    508     }
    509     case kArchTailCallAddress: {
    510       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    511       AssembleDeconstructActivationRecord(stack_param_delta);
    512       CHECK(!instr->InputAt(0)->IsImmediate());
    513       __ Jump(i.InputRegister(0));
    514       frame_access_state()->ClearSPDelta();
    515       break;
    516     }
    517     case kArchCallJSFunction: {
    518       EnsureSpaceForLazyDeopt();
    519       Register func = i.InputRegister(0);
    520       if (FLAG_debug_code) {
    521         // Check the function's context matches the context argument.
    522         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    523         __ cmp(cp, kScratchReg);
    524         __ Assert(eq, kWrongFunctionContext);
    525       }
    526       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    527       __ Call(ip);
    528       RecordCallPosition(instr);
    529       DCHECK_EQ(LeaveCC, i.OutputSBit());
    530       frame_access_state()->ClearSPDelta();
    531       break;
    532     }
    533     case kArchTailCallJSFunctionFromJSFunction:
    534     case kArchTailCallJSFunction: {
    535       Register func = i.InputRegister(0);
    536       if (FLAG_debug_code) {
    537         // Check the function's context matches the context argument.
    538         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    539         __ cmp(cp, kScratchReg);
    540         __ Assert(eq, kWrongFunctionContext);
    541       }
    542       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    543       AssembleDeconstructActivationRecord(stack_param_delta);
    544       if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
    545         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    546                                          i.TempRegister(0), i.TempRegister(1),
    547                                          i.TempRegister(2));
    548       }
    549       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    550       __ Jump(ip);
    551       DCHECK_EQ(LeaveCC, i.OutputSBit());
    552       frame_access_state()->ClearSPDelta();
    553       break;
    554     }
    555     case kArchPrepareCallCFunction: {
    556       int const num_parameters = MiscField::decode(instr->opcode());
    557       __ PrepareCallCFunction(num_parameters, kScratchReg);
    558       // Frame alignment requires using FP-relative frame addressing.
    559       frame_access_state()->SetFrameAccessToFP();
    560       break;
    561     }
    562     case kArchPrepareTailCall:
    563       AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
    564       break;
    565     case kArchCallCFunction: {
    566       int const num_parameters = MiscField::decode(instr->opcode());
    567       if (instr->InputAt(0)->IsImmediate()) {
    568         ExternalReference ref = i.InputExternalReference(0);
    569         __ CallCFunction(ref, num_parameters);
    570       } else {
    571         Register func = i.InputRegister(0);
    572         __ CallCFunction(func, num_parameters);
    573       }
    574       frame_access_state()->SetFrameAccessToDefault();
    575       frame_access_state()->ClearSPDelta();
    576       break;
    577     }
    578     case kArchJmp:
    579       AssembleArchJump(i.InputRpo(0));
    580       DCHECK_EQ(LeaveCC, i.OutputSBit());
    581       break;
    582     case kArchLookupSwitch:
    583       AssembleArchLookupSwitch(instr);
    584       DCHECK_EQ(LeaveCC, i.OutputSBit());
    585       break;
    586     case kArchTableSwitch:
    587       AssembleArchTableSwitch(instr);
    588       DCHECK_EQ(LeaveCC, i.OutputSBit());
    589       break;
    590     case kArchDebugBreak:
    591       __ stop("kArchDebugBreak");
    592       break;
    593     case kArchComment: {
    594       Address comment_string = i.InputExternalReference(0).address();
    595       __ RecordComment(reinterpret_cast<const char*>(comment_string));
    596       break;
    597     }
    598     case kArchNop:
    599     case kArchThrowTerminator:
    600       // don't emit code for nops.
    601       DCHECK_EQ(LeaveCC, i.OutputSBit());
    602       break;
    603     case kArchDeoptimize: {
    604       int deopt_state_id =
    605           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    606       Deoptimizer::BailoutType bailout_type =
    607           Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
    608       CodeGenResult result =
    609           AssembleDeoptimizerCall(deopt_state_id, bailout_type);
    610       if (result != kSuccess) return result;
    611       break;
    612     }
    613     case kArchRet:
    614       AssembleReturn();
    615       DCHECK_EQ(LeaveCC, i.OutputSBit());
    616       break;
    617     case kArchStackPointer:
    618       __ mov(i.OutputRegister(), sp);
    619       DCHECK_EQ(LeaveCC, i.OutputSBit());
    620       break;
    621     case kArchFramePointer:
    622       __ mov(i.OutputRegister(), fp);
    623       DCHECK_EQ(LeaveCC, i.OutputSBit());
    624       break;
    625     case kArchParentFramePointer:
    626       if (frame_access_state()->has_frame()) {
    627         __ ldr(i.OutputRegister(), MemOperand(fp, 0));
    628       } else {
    629         __ mov(i.OutputRegister(), fp);
    630       }
    631       break;
    632     case kArchTruncateDoubleToI:
    633       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
    634       DCHECK_EQ(LeaveCC, i.OutputSBit());
    635       break;
    636     case kArchStoreWithWriteBarrier: {
    637       RecordWriteMode mode =
    638           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    639       Register object = i.InputRegister(0);
    640       Register value = i.InputRegister(2);
    641       Register scratch0 = i.TempRegister(0);
    642       Register scratch1 = i.TempRegister(1);
    643       OutOfLineRecordWrite* ool;
    644 
    645       AddressingMode addressing_mode =
    646           AddressingModeField::decode(instr->opcode());
    647       if (addressing_mode == kMode_Offset_RI) {
    648         int32_t index = i.InputInt32(1);
    649         ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
    650                                                 scratch0, scratch1, mode);
    651         __ str(value, MemOperand(object, index));
    652       } else {
    653         DCHECK_EQ(kMode_Offset_RR, addressing_mode);
    654         Register index(i.InputRegister(1));
    655         ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
    656                                                 scratch0, scratch1, mode);
    657         __ str(value, MemOperand(object, index));
    658       }
    659       __ CheckPageFlag(object, scratch0,
    660                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
    661                        ool->entry());
    662       __ bind(ool->exit());
    663       break;
    664     }
    665     case kArchStackSlot: {
    666       FrameOffset offset =
    667           frame_access_state()->GetFrameOffset(i.InputInt32(0));
    668       Register base;
    669       if (offset.from_stack_pointer()) {
    670         base = sp;
    671       } else {
    672         base = fp;
    673       }
    674       __ add(i.OutputRegister(0), base, Operand(offset.offset()));
    675       break;
    676     }
    677     case kIeee754Float64Atan:
    678       ASSEMBLE_IEEE754_UNOP(atan);
    679       break;
    680     case kIeee754Float64Atan2:
    681       ASSEMBLE_IEEE754_BINOP(atan2);
    682       break;
    683     case kIeee754Float64Cbrt:
    684       ASSEMBLE_IEEE754_UNOP(cbrt);
    685       break;
    686     case kIeee754Float64Cos:
    687       ASSEMBLE_IEEE754_UNOP(cos);
    688       break;
    689     case kIeee754Float64Exp:
    690       ASSEMBLE_IEEE754_UNOP(exp);
    691       break;
    692     case kIeee754Float64Expm1:
    693       ASSEMBLE_IEEE754_UNOP(expm1);
    694       break;
    695     case kIeee754Float64Atanh:
    696       ASSEMBLE_IEEE754_UNOP(atanh);
    697       break;
    698     case kIeee754Float64Log:
    699       ASSEMBLE_IEEE754_UNOP(log);
    700       break;
    701     case kIeee754Float64Log1p:
    702       ASSEMBLE_IEEE754_UNOP(log1p);
    703       break;
    704     case kIeee754Float64Log2:
    705       ASSEMBLE_IEEE754_UNOP(log2);
    706       break;
    707     case kIeee754Float64Log10:
    708       ASSEMBLE_IEEE754_UNOP(log10);
    709       break;
    710     case kIeee754Float64Sin:
    711       ASSEMBLE_IEEE754_UNOP(sin);
    712       break;
    713     case kIeee754Float64Tan:
    714       ASSEMBLE_IEEE754_UNOP(tan);
    715       break;
    716     case kArmAdd:
    717       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    718              i.OutputSBit());
    719       break;
    720     case kArmAnd:
    721       __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    722               i.OutputSBit());
    723       break;
    724     case kArmBic:
    725       __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    726              i.OutputSBit());
    727       break;
    728     case kArmMul:
    729       __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    730              i.OutputSBit());
    731       break;
    732     case kArmMla:
    733       __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    734              i.InputRegister(2), i.OutputSBit());
    735       break;
    736     case kArmMls: {
    737       CpuFeatureScope scope(masm(), ARMv7);
    738       __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    739              i.InputRegister(2));
    740       DCHECK_EQ(LeaveCC, i.OutputSBit());
    741       break;
    742     }
    743     case kArmSmmul:
    744       __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    745       DCHECK_EQ(LeaveCC, i.OutputSBit());
    746       break;
    747     case kArmSmmla:
    748       __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    749                i.InputRegister(2));
    750       DCHECK_EQ(LeaveCC, i.OutputSBit());
    751       break;
    752     case kArmUmull:
    753       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    754                i.InputRegister(1), i.OutputSBit());
    755       break;
    756     case kArmSdiv: {
    757       CpuFeatureScope scope(masm(), SUDIV);
    758       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    759       DCHECK_EQ(LeaveCC, i.OutputSBit());
    760       break;
    761     }
    762     case kArmUdiv: {
    763       CpuFeatureScope scope(masm(), SUDIV);
    764       __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    765       DCHECK_EQ(LeaveCC, i.OutputSBit());
    766       break;
    767     }
    768     case kArmMov:
    769       __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
    770       break;
    771     case kArmMvn:
    772       __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
    773       break;
    774     case kArmOrr:
    775       __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    776              i.OutputSBit());
    777       break;
    778     case kArmEor:
    779       __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    780              i.OutputSBit());
    781       break;
    782     case kArmSub:
    783       __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    784              i.OutputSBit());
    785       break;
    786     case kArmRsb:
    787       __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
    788              i.OutputSBit());
    789       break;
    790     case kArmBfc: {
    791       CpuFeatureScope scope(masm(), ARMv7);
    792       __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
    793       DCHECK_EQ(LeaveCC, i.OutputSBit());
    794       break;
    795     }
    796     case kArmUbfx: {
    797       CpuFeatureScope scope(masm(), ARMv7);
    798       __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
    799               i.InputInt8(2));
    800       DCHECK_EQ(LeaveCC, i.OutputSBit());
    801       break;
    802     }
    803     case kArmSbfx: {
    804       CpuFeatureScope scope(masm(), ARMv7);
    805       __ sbfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
    806               i.InputInt8(2));
    807       DCHECK_EQ(LeaveCC, i.OutputSBit());
    808       break;
    809     }
    810     case kArmSxtb:
    811       __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    812       DCHECK_EQ(LeaveCC, i.OutputSBit());
    813       break;
    814     case kArmSxth:
    815       __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    816       DCHECK_EQ(LeaveCC, i.OutputSBit());
    817       break;
    818     case kArmSxtab:
    819       __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    820                i.InputInt32(2));
    821       DCHECK_EQ(LeaveCC, i.OutputSBit());
    822       break;
    823     case kArmSxtah:
    824       __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    825                i.InputInt32(2));
    826       DCHECK_EQ(LeaveCC, i.OutputSBit());
    827       break;
    828     case kArmUxtb:
    829       __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    830       DCHECK_EQ(LeaveCC, i.OutputSBit());
    831       break;
    832     case kArmUxth:
    833       __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
    834       DCHECK_EQ(LeaveCC, i.OutputSBit());
    835       break;
    836     case kArmUxtab:
    837       __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    838                i.InputInt32(2));
    839       DCHECK_EQ(LeaveCC, i.OutputSBit());
    840       break;
    841     case kArmUxtah:
    842       __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    843                i.InputInt32(2));
    844       DCHECK_EQ(LeaveCC, i.OutputSBit());
    845       break;
    846     case kArmRbit: {
    847       CpuFeatureScope scope(masm(), ARMv7);
    848       __ rbit(i.OutputRegister(), i.InputRegister(0));
    849       DCHECK_EQ(LeaveCC, i.OutputSBit());
    850       break;
    851     }
    852     case kArmClz:
    853       __ clz(i.OutputRegister(), i.InputRegister(0));
    854       DCHECK_EQ(LeaveCC, i.OutputSBit());
    855       break;
    856     case kArmCmp:
    857       __ cmp(i.InputRegister(0), i.InputOperand2(1));
    858       DCHECK_EQ(SetCC, i.OutputSBit());
    859       break;
    860     case kArmCmn:
    861       __ cmn(i.InputRegister(0), i.InputOperand2(1));
    862       DCHECK_EQ(SetCC, i.OutputSBit());
    863       break;
    864     case kArmTst:
    865       __ tst(i.InputRegister(0), i.InputOperand2(1));
    866       DCHECK_EQ(SetCC, i.OutputSBit());
    867       break;
    868     case kArmTeq:
    869       __ teq(i.InputRegister(0), i.InputOperand2(1));
    870       DCHECK_EQ(SetCC, i.OutputSBit());
    871       break;
    872     case kArmAddPair:
    873       // i.InputRegister(0) ... left low word.
    874       // i.InputRegister(1) ... left high word.
    875       // i.InputRegister(2) ... right low word.
    876       // i.InputRegister(3) ... right high word.
    877       __ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
    878              SBit::SetCC);
    879       __ adc(i.OutputRegister(1), i.InputRegister(1),
    880              Operand(i.InputRegister(3)));
    881       DCHECK_EQ(LeaveCC, i.OutputSBit());
    882       break;
    883     case kArmSubPair:
    884       // i.InputRegister(0) ... left low word.
    885       // i.InputRegister(1) ... left high word.
    886       // i.InputRegister(2) ... right low word.
    887       // i.InputRegister(3) ... right high word.
    888       __ sub(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
    889              SBit::SetCC);
    890       __ sbc(i.OutputRegister(1), i.InputRegister(1),
    891              Operand(i.InputRegister(3)));
    892       DCHECK_EQ(LeaveCC, i.OutputSBit());
    893       break;
    894     case kArmMulPair:
    895       // i.InputRegister(0) ... left low word.
    896       // i.InputRegister(1) ... left high word.
    897       // i.InputRegister(2) ... right low word.
    898       // i.InputRegister(3) ... right high word.
    899       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    900                i.InputRegister(2));
    901       __ mla(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(3),
    902              i.OutputRegister(1));
    903       __ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1),
    904              i.OutputRegister(1));
    905       break;
    906     case kArmLslPair:
    907       if (instr->InputAt(2)->IsImmediate()) {
    908         __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    909                    i.InputRegister(1), i.InputInt32(2));
    910       } else {
    911         __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    912                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
    913       }
    914       break;
    915     case kArmLsrPair:
    916       if (instr->InputAt(2)->IsImmediate()) {
    917         __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    918                    i.InputRegister(1), i.InputInt32(2));
    919       } else {
    920         __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    921                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
    922       }
    923       break;
    924     case kArmAsrPair:
    925       if (instr->InputAt(2)->IsImmediate()) {
    926         __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    927                    i.InputRegister(1), i.InputInt32(2));
    928       } else {
    929         __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
    930                    i.InputRegister(1), kScratchReg, i.InputRegister(2));
    931       }
    932       break;
    933     case kArmVcmpF32:
    934       if (instr->InputAt(1)->IsFPRegister()) {
    935         __ VFPCompareAndSetFlags(i.InputFloatRegister(0),
    936                                  i.InputFloatRegister(1));
    937       } else {
    938         DCHECK(instr->InputAt(1)->IsImmediate());
    939         // 0.0 is the only immediate supported by vcmp instructions.
    940         DCHECK(i.InputFloat32(1) == 0.0f);
    941         __ VFPCompareAndSetFlags(i.InputFloatRegister(0), i.InputFloat32(1));
    942       }
    943       DCHECK_EQ(SetCC, i.OutputSBit());
    944       break;
    945     case kArmVaddF32:
    946       __ vadd(i.OutputFloatRegister(), i.InputFloatRegister(0),
    947               i.InputFloatRegister(1));
    948       DCHECK_EQ(LeaveCC, i.OutputSBit());
    949       break;
    950     case kArmVsubF32:
    951       __ vsub(i.OutputFloatRegister(), i.InputFloatRegister(0),
    952               i.InputFloatRegister(1));
    953       DCHECK_EQ(LeaveCC, i.OutputSBit());
    954       break;
    955     case kArmVmulF32:
    956       __ vmul(i.OutputFloatRegister(), i.InputFloatRegister(0),
    957               i.InputFloatRegister(1));
    958       DCHECK_EQ(LeaveCC, i.OutputSBit());
    959       break;
    960     case kArmVmlaF32:
    961       __ vmla(i.OutputFloatRegister(), i.InputFloatRegister(1),
    962               i.InputFloatRegister(2));
    963       DCHECK_EQ(LeaveCC, i.OutputSBit());
    964       break;
    965     case kArmVmlsF32:
    966       __ vmls(i.OutputFloatRegister(), i.InputFloatRegister(1),
    967               i.InputFloatRegister(2));
    968       DCHECK_EQ(LeaveCC, i.OutputSBit());
    969       break;
    970     case kArmVdivF32:
    971       __ vdiv(i.OutputFloatRegister(), i.InputFloatRegister(0),
    972               i.InputFloatRegister(1));
    973       DCHECK_EQ(LeaveCC, i.OutputSBit());
    974       break;
    975     case kArmVsqrtF32:
    976       __ vsqrt(i.OutputFloatRegister(), i.InputFloatRegister(0));
    977       break;
    978     case kArmVabsF32:
    979       __ vabs(i.OutputFloatRegister(), i.InputFloatRegister(0));
    980       break;
    981     case kArmVnegF32:
    982       __ vneg(i.OutputFloatRegister(), i.InputFloatRegister(0));
    983       break;
    984     case kArmVcmpF64:
    985       if (instr->InputAt(1)->IsFPRegister()) {
    986         __ VFPCompareAndSetFlags(i.InputDoubleRegister(0),
    987                                  i.InputDoubleRegister(1));
    988       } else {
    989         DCHECK(instr->InputAt(1)->IsImmediate());
    990         // 0.0 is the only immediate supported by vcmp instructions.
    991         DCHECK(i.InputDouble(1) == 0.0);
    992         __ VFPCompareAndSetFlags(i.InputDoubleRegister(0), i.InputDouble(1));
    993       }
    994       DCHECK_EQ(SetCC, i.OutputSBit());
    995       break;
    996     case kArmVaddF64:
    997       __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
    998               i.InputDoubleRegister(1));
    999       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1000       break;
   1001     case kArmVsubF64:
   1002       __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1003               i.InputDoubleRegister(1));
   1004       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1005       break;
   1006     case kArmVmulF64:
   1007       __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1008               i.InputDoubleRegister(1));
   1009       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1010       break;
   1011     case kArmVmlaF64:
   1012       __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1013               i.InputDoubleRegister(2));
   1014       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1015       break;
   1016     case kArmVmlsF64:
   1017       __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1018               i.InputDoubleRegister(2));
   1019       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1020       break;
   1021     case kArmVdivF64:
   1022       __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1023               i.InputDoubleRegister(1));
   1024       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1025       break;
   1026     case kArmVmodF64: {
   1027       // TODO(bmeurer): We should really get rid of this special instruction,
   1028       // and generate a CallAddress instruction instead.
   1029       FrameScope scope(masm(), StackFrame::MANUAL);
   1030       __ PrepareCallCFunction(0, 2, kScratchReg);
   1031       __ MovToFloatParameters(i.InputDoubleRegister(0),
   1032                               i.InputDoubleRegister(1));
   1033       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
   1034                        0, 2);
   1035       // Move the result in the double result register.
   1036       __ MovFromFloatResult(i.OutputDoubleRegister());
   1037       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1038       break;
   1039     }
   1040     case kArmVsqrtF64:
   1041       __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1042       break;
   1043     case kArmVabsF64:
   1044       __ vabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1045       break;
   1046     case kArmVnegF64:
   1047       __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1048       break;
   1049     case kArmVrintmF32:
   1050       __ vrintm(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1051       break;
   1052     case kArmVrintmF64:
   1053       __ vrintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1054       break;
   1055     case kArmVrintpF32:
   1056       __ vrintp(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1057       break;
   1058     case kArmVrintpF64:
   1059       __ vrintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1060       break;
   1061     case kArmVrintzF32:
   1062       __ vrintz(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1063       break;
   1064     case kArmVrintzF64:
   1065       __ vrintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1066       break;
   1067     case kArmVrintaF64:
   1068       __ vrinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1069       break;
   1070     case kArmVrintnF32:
   1071       __ vrintn(i.OutputFloatRegister(), i.InputFloatRegister(0));
   1072       break;
   1073     case kArmVrintnF64:
   1074       __ vrintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1075       break;
   1076     case kArmVcvtF32F64: {
   1077       __ vcvt_f32_f64(i.OutputFloatRegister(), i.InputDoubleRegister(0));
   1078       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1079       break;
   1080     }
   1081     case kArmVcvtF64F32: {
   1082       __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloatRegister(0));
   1083       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1084       break;
   1085     }
   1086     case kArmVcvtF32S32: {
   1087       SwVfpRegister scratch = kScratchDoubleReg.low();
   1088       __ vmov(scratch, i.InputRegister(0));
   1089       __ vcvt_f32_s32(i.OutputFloatRegister(), scratch);
   1090       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1091       break;
   1092     }
   1093     case kArmVcvtF32U32: {
   1094       SwVfpRegister scratch = kScratchDoubleReg.low();
   1095       __ vmov(scratch, i.InputRegister(0));
   1096       __ vcvt_f32_u32(i.OutputFloatRegister(), scratch);
   1097       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1098       break;
   1099     }
   1100     case kArmVcvtF64S32: {
   1101       SwVfpRegister scratch = kScratchDoubleReg.low();
   1102       __ vmov(scratch, i.InputRegister(0));
   1103       __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch);
   1104       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1105       break;
   1106     }
   1107     case kArmVcvtF64U32: {
   1108       SwVfpRegister scratch = kScratchDoubleReg.low();
   1109       __ vmov(scratch, i.InputRegister(0));
   1110       __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch);
   1111       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1112       break;
   1113     }
   1114     case kArmVcvtS32F32: {
   1115       SwVfpRegister scratch = kScratchDoubleReg.low();
   1116       __ vcvt_s32_f32(scratch, i.InputFloatRegister(0));
   1117       __ vmov(i.OutputRegister(), scratch);
   1118       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1119       break;
   1120     }
   1121     case kArmVcvtU32F32: {
   1122       SwVfpRegister scratch = kScratchDoubleReg.low();
   1123       __ vcvt_u32_f32(scratch, i.InputFloatRegister(0));
   1124       __ vmov(i.OutputRegister(), scratch);
   1125       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1126       break;
   1127     }
   1128     case kArmVcvtS32F64: {
   1129       SwVfpRegister scratch = kScratchDoubleReg.low();
   1130       __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0));
   1131       __ vmov(i.OutputRegister(), scratch);
   1132       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1133       break;
   1134     }
   1135     case kArmVcvtU32F64: {
   1136       SwVfpRegister scratch = kScratchDoubleReg.low();
   1137       __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0));
   1138       __ vmov(i.OutputRegister(), scratch);
   1139       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1140       break;
   1141     }
   1142     case kArmVmovU32F32:
   1143       __ vmov(i.OutputRegister(), i.InputFloatRegister(0));
   1144       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1145       break;
   1146     case kArmVmovF32U32:
   1147       __ vmov(i.OutputFloatRegister(), i.InputRegister(0));
   1148       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1149       break;
   1150     case kArmVmovLowU32F64:
   1151       __ VmovLow(i.OutputRegister(), i.InputDoubleRegister(0));
   1152       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1153       break;
   1154     case kArmVmovLowF64U32:
   1155       __ VmovLow(i.OutputDoubleRegister(), i.InputRegister(1));
   1156       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1157       break;
   1158     case kArmVmovHighU32F64:
   1159       __ VmovHigh(i.OutputRegister(), i.InputDoubleRegister(0));
   1160       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1161       break;
   1162     case kArmVmovHighF64U32:
   1163       __ VmovHigh(i.OutputDoubleRegister(), i.InputRegister(1));
   1164       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1165       break;
   1166     case kArmVmovF64U32U32:
   1167       __ vmov(i.OutputDoubleRegister(), i.InputRegister(0), i.InputRegister(1));
   1168       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1169       break;
   1170     case kArmLdrb:
   1171       __ ldrb(i.OutputRegister(), i.InputOffset());
   1172       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1173       break;
   1174     case kArmLdrsb:
   1175       __ ldrsb(i.OutputRegister(), i.InputOffset());
   1176       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1177       break;
   1178     case kArmStrb:
   1179       __ strb(i.InputRegister(0), i.InputOffset(1));
   1180       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1181       break;
   1182     case kArmLdrh:
   1183       __ ldrh(i.OutputRegister(), i.InputOffset());
   1184       break;
   1185     case kArmLdrsh:
   1186       __ ldrsh(i.OutputRegister(), i.InputOffset());
   1187       break;
   1188     case kArmStrh:
   1189       __ strh(i.InputRegister(0), i.InputOffset(1));
   1190       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1191       break;
   1192     case kArmLdr:
   1193       __ ldr(i.OutputRegister(), i.InputOffset());
   1194       break;
   1195     case kArmStr:
   1196       __ str(i.InputRegister(0), i.InputOffset(1));
   1197       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1198       break;
   1199     case kArmVldrF32: {
   1200       __ vldr(i.OutputFloatRegister(), i.InputOffset());
   1201       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1202       break;
   1203     }
   1204     case kArmVstrF32:
   1205       __ vstr(i.InputFloatRegister(0), i.InputOffset(1));
   1206       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1207       break;
   1208     case kArmVldrF64:
   1209       __ vldr(i.OutputDoubleRegister(), i.InputOffset());
   1210       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1211       break;
   1212     case kArmVstrF64:
   1213       __ vstr(i.InputDoubleRegister(0), i.InputOffset(1));
   1214       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1215       break;
   1216     case kArmFloat32Max: {
   1217       CpuFeatureScope scope(masm(), ARMv8);
   1218       // (b < a) ? a : b
   1219       SwVfpRegister a = i.InputFloatRegister(0);
   1220       SwVfpRegister b = i.InputFloatRegister(1);
   1221       SwVfpRegister result = i.OutputFloatRegister();
   1222       __ VFPCompareAndSetFlags(a, b);
   1223       __ vsel(gt, result, a, b);
   1224       break;
   1225     }
   1226     case kArmFloat32Min: {
   1227       CpuFeatureScope scope(masm(), ARMv8);
   1228       // (a < b) ? a : b
   1229       SwVfpRegister a = i.InputFloatRegister(0);
   1230       SwVfpRegister b = i.InputFloatRegister(1);
   1231       SwVfpRegister result = i.OutputFloatRegister();
   1232       __ VFPCompareAndSetFlags(b, a);
   1233       __ vsel(gt, result, a, b);
   1234       break;
   1235     }
   1236     case kArmFloat64Max: {
   1237       CpuFeatureScope scope(masm(), ARMv8);
   1238       // (b < a) ? a : b
   1239       DwVfpRegister a = i.InputDoubleRegister(0);
   1240       DwVfpRegister b = i.InputDoubleRegister(1);
   1241       DwVfpRegister result = i.OutputDoubleRegister();
   1242       __ VFPCompareAndSetFlags(a, b);
   1243       __ vsel(gt, result, a, b);
   1244       break;
   1245     }
   1246     case kArmFloat64Min: {
   1247       CpuFeatureScope scope(masm(), ARMv8);
   1248       // (a < b) ? a : b
   1249       DwVfpRegister a = i.InputDoubleRegister(0);
   1250       DwVfpRegister b = i.InputDoubleRegister(1);
   1251       DwVfpRegister result = i.OutputDoubleRegister();
   1252       __ VFPCompareAndSetFlags(b, a);
   1253       __ vsel(gt, result, a, b);
   1254       break;
   1255     }
   1256     case kArmFloat64SilenceNaN: {
   1257       DwVfpRegister value = i.InputDoubleRegister(0);
   1258       DwVfpRegister result = i.OutputDoubleRegister();
   1259       __ VFPCanonicalizeNaN(result, value);
   1260       break;
   1261     }
   1262     case kArmPush:
   1263       if (instr->InputAt(0)->IsFPRegister()) {
   1264         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
   1265         if (op->representation() == MachineRepresentation::kFloat64) {
   1266           __ vpush(i.InputDoubleRegister(0));
   1267           frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   1268         } else {
   1269           DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
   1270           __ vpush(i.InputFloatRegister(0));
   1271           frame_access_state()->IncreaseSPDelta(1);
   1272         }
   1273       } else {
   1274         __ push(i.InputRegister(0));
   1275         frame_access_state()->IncreaseSPDelta(1);
   1276       }
   1277       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1278       break;
   1279     case kArmPoke: {
   1280       int const slot = MiscField::decode(instr->opcode());
   1281       __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
   1282       DCHECK_EQ(LeaveCC, i.OutputSBit());
   1283       break;
   1284     }
   1285     case kCheckedLoadInt8:
   1286       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
   1287       break;
   1288     case kCheckedLoadUint8:
   1289       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
   1290       break;
   1291     case kCheckedLoadInt16:
   1292       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
   1293       break;
   1294     case kCheckedLoadUint16:
   1295       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
   1296       break;
   1297     case kCheckedLoadWord32:
   1298       ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
   1299       break;
   1300     case kCheckedLoadFloat32:
   1301       ASSEMBLE_CHECKED_LOAD_FP(Float);
   1302       break;
   1303     case kCheckedLoadFloat64:
   1304       ASSEMBLE_CHECKED_LOAD_FP(Double);
   1305       break;
   1306     case kCheckedStoreWord8:
   1307       ASSEMBLE_CHECKED_STORE_INTEGER(strb);
   1308       break;
   1309     case kCheckedStoreWord16:
   1310       ASSEMBLE_CHECKED_STORE_INTEGER(strh);
   1311       break;
   1312     case kCheckedStoreWord32:
   1313       ASSEMBLE_CHECKED_STORE_INTEGER(str);
   1314       break;
   1315     case kCheckedStoreFloat32:
   1316       ASSEMBLE_CHECKED_STORE_FP(Float);
   1317       break;
   1318     case kCheckedStoreFloat64:
   1319       ASSEMBLE_CHECKED_STORE_FP(Double);
   1320       break;
   1321     case kCheckedLoadWord64:
   1322     case kCheckedStoreWord64:
   1323       UNREACHABLE();  // currently unsupported checked int64 load/store.
   1324       break;
   1325 
   1326     case kAtomicLoadInt8:
   1327       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsb);
   1328       break;
   1329     case kAtomicLoadUint8:
   1330       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrb);
   1331       break;
   1332     case kAtomicLoadInt16:
   1333       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsh);
   1334       break;
   1335     case kAtomicLoadUint16:
   1336       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrh);
   1337       break;
   1338     case kAtomicLoadWord32:
   1339       ASSEMBLE_ATOMIC_LOAD_INTEGER(ldr);
   1340       break;
   1341 
   1342     case kAtomicStoreWord8:
   1343       ASSEMBLE_ATOMIC_STORE_INTEGER(strb);
   1344       break;
   1345     case kAtomicStoreWord16:
   1346       ASSEMBLE_ATOMIC_STORE_INTEGER(strh);
   1347       break;
   1348     case kAtomicStoreWord32:
   1349       ASSEMBLE_ATOMIC_STORE_INTEGER(str);
   1350       break;
   1351   }
   1352   return kSuccess;
   1353 }  // NOLINT(readability/fn_size)
   1354 
   1355 
   1356 // Assembles branches after an instruction.
   1357 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   1358   ArmOperandConverter i(this, instr);
   1359   Label* tlabel = branch->true_label;
   1360   Label* flabel = branch->false_label;
   1361   Condition cc = FlagsConditionToCondition(branch->condition);
   1362   __ b(cc, tlabel);
   1363   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
   1364 }
   1365 
   1366 
   1367 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   1368   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
   1369 }
   1370 
   1371 
   1372 // Assembles boolean materializations after an instruction.
   1373 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   1374                                         FlagsCondition condition) {
   1375   ArmOperandConverter i(this, instr);
   1376 
   1377   // Materialize a full 32-bit 1 or 0 value. The result register is always the
   1378   // last output of the instruction.
   1379   DCHECK_NE(0u, instr->OutputCount());
   1380   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   1381   Condition cc = FlagsConditionToCondition(condition);
   1382   __ mov(reg, Operand(0));
   1383   __ mov(reg, Operand(1), LeaveCC, cc);
   1384 }
   1385 
   1386 
   1387 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   1388   ArmOperandConverter i(this, instr);
   1389   Register input = i.InputRegister(0);
   1390   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   1391     __ cmp(input, Operand(i.InputInt32(index + 0)));
   1392     __ b(eq, GetLabel(i.InputRpo(index + 1)));
   1393   }
   1394   AssembleArchJump(i.InputRpo(1));
   1395 }
   1396 
   1397 
   1398 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   1399   ArmOperandConverter i(this, instr);
   1400   Register input = i.InputRegister(0);
   1401   size_t const case_count = instr->InputCount() - 2;
   1402   // Ensure to emit the constant pool first if necessary.
   1403   __ CheckConstPool(true, true);
   1404   __ cmp(input, Operand(case_count));
   1405   __ BlockConstPoolFor(case_count + 2);
   1406   __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo);
   1407   __ b(GetLabel(i.InputRpo(1)));
   1408   for (size_t index = 0; index < case_count; ++index) {
   1409     __ b(GetLabel(i.InputRpo(index + 2)));
   1410   }
   1411 }
   1412 
   1413 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
   1414     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   1415   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   1416       isolate(), deoptimization_id, bailout_type);
   1417   // TODO(turbofan): We should be able to generate better code by sharing the
   1418   // actual final call site and just bl'ing to it here, similar to what we do
   1419   // in the lithium backend.
   1420   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
   1421   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   1422   __ CheckConstPool(false, false);
   1423   return kSuccess;
   1424 }
   1425 
   1426 void CodeGenerator::FinishFrame(Frame* frame) {
   1427   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1428 
   1429   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   1430   if (saves_fp != 0) {
   1431     frame->AlignSavedCalleeRegisterSlots();
   1432   }
   1433 
   1434   if (saves_fp != 0) {
   1435     // Save callee-saved FP registers.
   1436     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   1437     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   1438     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   1439     DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
   1440     frame->AllocateSavedCalleeRegisterSlots((last - first + 1) *
   1441                                             (kDoubleSize / kPointerSize));
   1442   }
   1443   const RegList saves = FLAG_enable_embedded_constant_pool
   1444                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   1445                             : descriptor->CalleeSavedRegisters();
   1446   if (saves != 0) {
   1447     // Save callee-saved registers.
   1448     frame->AllocateSavedCalleeRegisterSlots(
   1449         base::bits::CountPopulation32(saves));
   1450   }
   1451 }
   1452 
   1453 void CodeGenerator::AssembleConstructFrame() {
   1454   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1455   if (frame_access_state()->has_frame()) {
   1456     if (descriptor->IsCFunctionCall()) {
   1457       if (FLAG_enable_embedded_constant_pool) {
   1458         __ Push(lr, fp, pp);
   1459         // Adjust FP to point to saved FP.
   1460         __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
   1461       } else {
   1462         __ Push(lr, fp);
   1463         __ mov(fp, sp);
   1464       }
   1465     } else if (descriptor->IsJSFunctionCall()) {
   1466       __ Prologue(this->info()->GeneratePreagedPrologue());
   1467     } else {
   1468       __ StubPrologue(info()->GetOutputStackFrameType());
   1469     }
   1470   }
   1471 
   1472   int shrink_slots = frame()->GetSpillSlotCount();
   1473 
   1474   if (info()->is_osr()) {
   1475     // TurboFan OSR-compiled functions cannot be entered directly.
   1476     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   1477 
   1478     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   1479     // frame is still on the stack. Optimized code uses OSR values directly from
   1480     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   1481     // remaining stack slots.
   1482     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   1483     osr_pc_offset_ = __ pc_offset();
   1484     shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
   1485   }
   1486 
   1487   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   1488   if (shrink_slots > 0) {
   1489     __ sub(sp, sp, Operand(shrink_slots * kPointerSize));
   1490   }
   1491 
   1492   if (saves_fp != 0) {
   1493     // Save callee-saved FP registers.
   1494     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   1495     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   1496     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   1497     DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
   1498     __ vstm(db_w, sp, DwVfpRegister::from_code(first),
   1499             DwVfpRegister::from_code(last));
   1500   }
   1501   const RegList saves = FLAG_enable_embedded_constant_pool
   1502                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   1503                             : descriptor->CalleeSavedRegisters();
   1504   if (saves != 0) {
   1505     // Save callee-saved registers.
   1506     __ stm(db_w, sp, saves);
   1507   }
   1508 }
   1509 
   1510 
   1511 void CodeGenerator::AssembleReturn() {
   1512   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1513   int pop_count = static_cast<int>(descriptor->StackParameterCount());
   1514 
   1515   // Restore registers.
   1516   const RegList saves = FLAG_enable_embedded_constant_pool
   1517                             ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
   1518                             : descriptor->CalleeSavedRegisters();
   1519   if (saves != 0) {
   1520     __ ldm(ia_w, sp, saves);
   1521   }
   1522 
   1523   // Restore FP registers.
   1524   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   1525   if (saves_fp != 0) {
   1526     STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
   1527     uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
   1528     uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
   1529     __ vldm(ia_w, sp, DwVfpRegister::from_code(first),
   1530             DwVfpRegister::from_code(last));
   1531   }
   1532 
   1533   if (descriptor->IsCFunctionCall()) {
   1534     AssembleDeconstructFrame();
   1535   } else if (frame_access_state()->has_frame()) {
   1536     // Canonicalize JSFunction return sites for now.
   1537     if (return_label_.is_bound()) {
   1538       __ b(&return_label_);
   1539       return;
   1540     } else {
   1541       __ bind(&return_label_);
   1542       AssembleDeconstructFrame();
   1543     }
   1544   }
   1545   __ Ret(pop_count);
   1546 }
   1547 
   1548 
   1549 void CodeGenerator::AssembleMove(InstructionOperand* source,
   1550                                  InstructionOperand* destination) {
   1551   ArmOperandConverter g(this, nullptr);
   1552   // Dispatch on the source and destination operand kinds.  Not all
   1553   // combinations are possible.
   1554   if (source->IsRegister()) {
   1555     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1556     Register src = g.ToRegister(source);
   1557     if (destination->IsRegister()) {
   1558       __ mov(g.ToRegister(destination), src);
   1559     } else {
   1560       __ str(src, g.ToMemOperand(destination));
   1561     }
   1562   } else if (source->IsStackSlot()) {
   1563     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1564     MemOperand src = g.ToMemOperand(source);
   1565     if (destination->IsRegister()) {
   1566       __ ldr(g.ToRegister(destination), src);
   1567     } else {
   1568       Register temp = kScratchReg;
   1569       __ ldr(temp, src);
   1570       __ str(temp, g.ToMemOperand(destination));
   1571     }
   1572   } else if (source->IsConstant()) {
   1573     Constant src = g.ToConstant(source);
   1574     if (destination->IsRegister() || destination->IsStackSlot()) {
   1575       Register dst =
   1576           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
   1577       switch (src.type()) {
   1578         case Constant::kInt32:
   1579           if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
   1580               src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
   1581               src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
   1582             __ mov(dst, Operand(src.ToInt32(), src.rmode()));
   1583           } else {
   1584             __ mov(dst, Operand(src.ToInt32()));
   1585           }
   1586           break;
   1587         case Constant::kInt64:
   1588           UNREACHABLE();
   1589           break;
   1590         case Constant::kFloat32:
   1591           __ Move(dst,
   1592                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   1593           break;
   1594         case Constant::kFloat64:
   1595           __ Move(dst,
   1596                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   1597           break;
   1598         case Constant::kExternalReference:
   1599           __ mov(dst, Operand(src.ToExternalReference()));
   1600           break;
   1601         case Constant::kHeapObject: {
   1602           Handle<HeapObject> src_object = src.ToHeapObject();
   1603           Heap::RootListIndex index;
   1604           int slot;
   1605           if (IsMaterializableFromFrame(src_object, &slot)) {
   1606             __ ldr(dst, g.SlotToMemOperand(slot));
   1607           } else if (IsMaterializableFromRoot(src_object, &index)) {
   1608             __ LoadRoot(dst, index);
   1609           } else {
   1610             __ Move(dst, src_object);
   1611           }
   1612           break;
   1613         }
   1614         case Constant::kRpoNumber:
   1615           UNREACHABLE();  // TODO(dcarney): loading RPO constants on arm.
   1616           break;
   1617       }
   1618       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
   1619     } else if (src.type() == Constant::kFloat32) {
   1620       if (destination->IsFPStackSlot()) {
   1621         MemOperand dst = g.ToMemOperand(destination);
   1622         __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
   1623         __ str(ip, dst);
   1624       } else {
   1625         SwVfpRegister dst = g.ToFloatRegister(destination);
   1626         __ vmov(dst, src.ToFloat32());
   1627       }
   1628     } else {
   1629       DCHECK_EQ(Constant::kFloat64, src.type());
   1630       DwVfpRegister dst = destination->IsFPRegister()
   1631                               ? g.ToDoubleRegister(destination)
   1632                               : kScratchDoubleReg;
   1633       __ vmov(dst, src.ToFloat64(), kScratchReg);
   1634       if (destination->IsFPStackSlot()) {
   1635         __ vstr(dst, g.ToMemOperand(destination));
   1636       }
   1637     }
   1638   } else if (source->IsFPRegister()) {
   1639     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   1640     if (rep == MachineRepresentation::kFloat64) {
   1641       DwVfpRegister src = g.ToDoubleRegister(source);
   1642       if (destination->IsFPRegister()) {
   1643         DwVfpRegister dst = g.ToDoubleRegister(destination);
   1644         __ Move(dst, src);
   1645       } else {
   1646         DCHECK(destination->IsFPStackSlot());
   1647         __ vstr(src, g.ToMemOperand(destination));
   1648       }
   1649     } else {
   1650       DCHECK_EQ(MachineRepresentation::kFloat32, rep);
   1651       SwVfpRegister src = g.ToFloatRegister(source);
   1652       if (destination->IsFPRegister()) {
   1653         SwVfpRegister dst = g.ToFloatRegister(destination);
   1654         __ Move(dst, src);
   1655       } else {
   1656         DCHECK(destination->IsFPStackSlot());
   1657         __ vstr(src, g.ToMemOperand(destination));
   1658       }
   1659     }
   1660   } else if (source->IsFPStackSlot()) {
   1661     MemOperand src = g.ToMemOperand(source);
   1662     MachineRepresentation rep =
   1663         LocationOperand::cast(destination)->representation();
   1664     if (destination->IsFPRegister()) {
   1665       if (rep == MachineRepresentation::kFloat64) {
   1666         __ vldr(g.ToDoubleRegister(destination), src);
   1667       } else {
   1668         DCHECK_EQ(MachineRepresentation::kFloat32, rep);
   1669         __ vldr(g.ToFloatRegister(destination), src);
   1670       }
   1671     } else {
   1672       DCHECK(destination->IsFPStackSlot());
   1673       if (rep == MachineRepresentation::kFloat64) {
   1674         DwVfpRegister temp = kScratchDoubleReg;
   1675         __ vldr(temp, src);
   1676         __ vstr(temp, g.ToMemOperand(destination));
   1677       } else {
   1678         DCHECK_EQ(MachineRepresentation::kFloat32, rep);
   1679         SwVfpRegister temp = kScratchDoubleReg.low();
   1680         __ vldr(temp, src);
   1681         __ vstr(temp, g.ToMemOperand(destination));
   1682       }
   1683     }
   1684   } else {
   1685     UNREACHABLE();
   1686   }
   1687 }
   1688 
   1689 
   1690 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   1691                                  InstructionOperand* destination) {
   1692   ArmOperandConverter g(this, nullptr);
   1693   // Dispatch on the source and destination operand kinds.  Not all
   1694   // combinations are possible.
   1695   if (source->IsRegister()) {
   1696     // Register-register.
   1697     Register temp = kScratchReg;
   1698     Register src = g.ToRegister(source);
   1699     if (destination->IsRegister()) {
   1700       Register dst = g.ToRegister(destination);
   1701       __ Move(temp, src);
   1702       __ Move(src, dst);
   1703       __ Move(dst, temp);
   1704     } else {
   1705       DCHECK(destination->IsStackSlot());
   1706       MemOperand dst = g.ToMemOperand(destination);
   1707       __ mov(temp, src);
   1708       __ ldr(src, dst);
   1709       __ str(temp, dst);
   1710     }
   1711   } else if (source->IsStackSlot()) {
   1712     DCHECK(destination->IsStackSlot());
   1713     Register temp_0 = kScratchReg;
   1714     SwVfpRegister temp_1 = kScratchDoubleReg.low();
   1715     MemOperand src = g.ToMemOperand(source);
   1716     MemOperand dst = g.ToMemOperand(destination);
   1717     __ ldr(temp_0, src);
   1718     __ vldr(temp_1, dst);
   1719     __ str(temp_0, dst);
   1720     __ vstr(temp_1, src);
   1721   } else if (source->IsFPRegister()) {
   1722     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   1723     LowDwVfpRegister temp = kScratchDoubleReg;
   1724     if (rep == MachineRepresentation::kFloat64) {
   1725       DwVfpRegister src = g.ToDoubleRegister(source);
   1726       if (destination->IsFPRegister()) {
   1727         DwVfpRegister dst = g.ToDoubleRegister(destination);
   1728         __ Move(temp, src);
   1729         __ Move(src, dst);
   1730         __ Move(dst, temp);
   1731       } else {
   1732         DCHECK(destination->IsFPStackSlot());
   1733         MemOperand dst = g.ToMemOperand(destination);
   1734         __ Move(temp, src);
   1735         __ vldr(src, dst);
   1736         __ vstr(temp, dst);
   1737       }
   1738     } else {
   1739       DCHECK_EQ(MachineRepresentation::kFloat32, rep);
   1740       SwVfpRegister src = g.ToFloatRegister(source);
   1741       if (destination->IsFPRegister()) {
   1742         SwVfpRegister dst = g.ToFloatRegister(destination);
   1743         __ Move(temp.low(), src);
   1744         __ Move(src, dst);
   1745         __ Move(dst, temp.low());
   1746       } else {
   1747         DCHECK(destination->IsFPStackSlot());
   1748         MemOperand dst = g.ToMemOperand(destination);
   1749         __ Move(temp.low(), src);
   1750         __ vldr(src, dst);
   1751         __ vstr(temp.low(), dst);
   1752       }
   1753     }
   1754   } else if (source->IsFPStackSlot()) {
   1755     DCHECK(destination->IsFPStackSlot());
   1756     Register temp_0 = kScratchReg;
   1757     LowDwVfpRegister temp_1 = kScratchDoubleReg;
   1758     MemOperand src0 = g.ToMemOperand(source);
   1759     MemOperand dst0 = g.ToMemOperand(destination);
   1760     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   1761     if (rep == MachineRepresentation::kFloat64) {
   1762       MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
   1763       MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
   1764       __ vldr(temp_1, dst0);  // Save destination in temp_1.
   1765       __ ldr(temp_0, src0);   // Then use temp_0 to copy source to destination.
   1766       __ str(temp_0, dst0);
   1767       __ ldr(temp_0, src1);
   1768       __ str(temp_0, dst1);
   1769       __ vstr(temp_1, src0);
   1770     } else {
   1771       DCHECK_EQ(MachineRepresentation::kFloat32, rep);
   1772       __ vldr(temp_1.low(), dst0);  // Save destination in temp_1.
   1773       __ ldr(temp_0, src0);  // Then use temp_0 to copy source to destination.
   1774       __ str(temp_0, dst0);
   1775       __ vstr(temp_1.low(), src0);
   1776     }
   1777   } else {
   1778     // No other combinations are possible.
   1779     UNREACHABLE();
   1780   }
   1781 }
   1782 
   1783 
   1784 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   1785   // On 32-bit ARM we emit the jump tables inline.
   1786   UNREACHABLE();
   1787 }
   1788 
   1789 
   1790 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   1791   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   1792     return;
   1793   }
   1794 
   1795   int space_needed = Deoptimizer::patch_size();
   1796   // Ensure that we have enough space after the previous lazy-bailout
   1797   // instruction for patching the code here.
   1798   int current_pc = masm()->pc_offset();
   1799   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   1800     // Block literal pool emission for duration of padding.
   1801     v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
   1802     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   1803     DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
   1804     while (padding_size > 0) {
   1805       __ nop();
   1806       padding_size -= v8::internal::Assembler::kInstrSize;
   1807     }
   1808   }
   1809 }
   1810 
   1811 #undef __
   1812 
   1813 }  // namespace compiler
   1814 }  // namespace internal
   1815 }  // namespace v8
   1816