Home | History | Annotate | Download | only in arm64
      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/arm64/frames-arm64.h"
      8 #include "src/arm64/macro-assembler-arm64.h"
      9 #include "src/compilation-info.h"
     10 #include "src/compiler/code-generator-impl.h"
     11 #include "src/compiler/gap-resolver.h"
     12 #include "src/compiler/node-matchers.h"
     13 #include "src/compiler/osr.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 #define __ masm()->
     20 
     21 
     22 // Adds Arm64-specific methods to convert InstructionOperands.
     23 class Arm64OperandConverter final : public InstructionOperandConverter {
     24  public:
     25   Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
     26       : InstructionOperandConverter(gen, instr) {}
     27 
     28   DoubleRegister InputFloat32Register(size_t index) {
     29     return InputDoubleRegister(index).S();
     30   }
     31 
     32   DoubleRegister InputFloat64Register(size_t index) {
     33     return InputDoubleRegister(index);
     34   }
     35 
     36   CPURegister InputFloat32OrZeroRegister(size_t index) {
     37     if (instr_->InputAt(index)->IsImmediate()) {
     38       DCHECK(bit_cast<int32_t>(InputFloat32(index)) == 0);
     39       return wzr;
     40     }
     41     DCHECK(instr_->InputAt(index)->IsFPRegister());
     42     return InputDoubleRegister(index).S();
     43   }
     44 
     45   CPURegister InputFloat64OrZeroRegister(size_t index) {
     46     if (instr_->InputAt(index)->IsImmediate()) {
     47       DCHECK(bit_cast<int64_t>(InputDouble(index)) == 0);
     48       return xzr;
     49     }
     50     DCHECK(instr_->InputAt(index)->IsDoubleRegister());
     51     return InputDoubleRegister(index);
     52   }
     53 
     54   size_t OutputCount() { return instr_->OutputCount(); }
     55 
     56   DoubleRegister OutputFloat32Register() { return OutputDoubleRegister().S(); }
     57 
     58   DoubleRegister OutputFloat64Register() { return OutputDoubleRegister(); }
     59 
     60   Register InputRegister32(size_t index) {
     61     return ToRegister(instr_->InputAt(index)).W();
     62   }
     63 
     64   Register InputOrZeroRegister32(size_t index) {
     65     DCHECK(instr_->InputAt(index)->IsRegister() ||
     66            (instr_->InputAt(index)->IsImmediate() && (InputInt32(index) == 0)));
     67     if (instr_->InputAt(index)->IsImmediate()) {
     68       return wzr;
     69     }
     70     return InputRegister32(index);
     71   }
     72 
     73   Register InputRegister64(size_t index) { return InputRegister(index); }
     74 
     75   Register InputOrZeroRegister64(size_t index) {
     76     DCHECK(instr_->InputAt(index)->IsRegister() ||
     77            (instr_->InputAt(index)->IsImmediate() && (InputInt64(index) == 0)));
     78     if (instr_->InputAt(index)->IsImmediate()) {
     79       return xzr;
     80     }
     81     return InputRegister64(index);
     82   }
     83 
     84   Operand InputImmediate(size_t index) {
     85     return ToImmediate(instr_->InputAt(index));
     86   }
     87 
     88   Operand InputOperand(size_t index) {
     89     return ToOperand(instr_->InputAt(index));
     90   }
     91 
     92   Operand InputOperand64(size_t index) { return InputOperand(index); }
     93 
     94   Operand InputOperand32(size_t index) {
     95     return ToOperand32(instr_->InputAt(index));
     96   }
     97 
     98   Register OutputRegister64() { return OutputRegister(); }
     99 
    100   Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
    101 
    102   Operand InputOperand2_32(size_t index) {
    103     switch (AddressingModeField::decode(instr_->opcode())) {
    104       case kMode_None:
    105         return InputOperand32(index);
    106       case kMode_Operand2_R_LSL_I:
    107         return Operand(InputRegister32(index), LSL, InputInt5(index + 1));
    108       case kMode_Operand2_R_LSR_I:
    109         return Operand(InputRegister32(index), LSR, InputInt5(index + 1));
    110       case kMode_Operand2_R_ASR_I:
    111         return Operand(InputRegister32(index), ASR, InputInt5(index + 1));
    112       case kMode_Operand2_R_ROR_I:
    113         return Operand(InputRegister32(index), ROR, InputInt5(index + 1));
    114       case kMode_Operand2_R_UXTB:
    115         return Operand(InputRegister32(index), UXTB);
    116       case kMode_Operand2_R_UXTH:
    117         return Operand(InputRegister32(index), UXTH);
    118       case kMode_Operand2_R_SXTB:
    119         return Operand(InputRegister32(index), SXTB);
    120       case kMode_Operand2_R_SXTH:
    121         return Operand(InputRegister32(index), SXTH);
    122       case kMode_Operand2_R_SXTW:
    123         return Operand(InputRegister32(index), SXTW);
    124       case kMode_MRI:
    125       case kMode_MRR:
    126         break;
    127     }
    128     UNREACHABLE();
    129     return Operand(-1);
    130   }
    131 
    132   Operand InputOperand2_64(size_t index) {
    133     switch (AddressingModeField::decode(instr_->opcode())) {
    134       case kMode_None:
    135         return InputOperand64(index);
    136       case kMode_Operand2_R_LSL_I:
    137         return Operand(InputRegister64(index), LSL, InputInt6(index + 1));
    138       case kMode_Operand2_R_LSR_I:
    139         return Operand(InputRegister64(index), LSR, InputInt6(index + 1));
    140       case kMode_Operand2_R_ASR_I:
    141         return Operand(InputRegister64(index), ASR, InputInt6(index + 1));
    142       case kMode_Operand2_R_ROR_I:
    143         return Operand(InputRegister64(index), ROR, InputInt6(index + 1));
    144       case kMode_Operand2_R_UXTB:
    145         return Operand(InputRegister64(index), UXTB);
    146       case kMode_Operand2_R_UXTH:
    147         return Operand(InputRegister64(index), UXTH);
    148       case kMode_Operand2_R_SXTB:
    149         return Operand(InputRegister64(index), SXTB);
    150       case kMode_Operand2_R_SXTH:
    151         return Operand(InputRegister64(index), SXTH);
    152       case kMode_Operand2_R_SXTW:
    153         return Operand(InputRegister64(index), SXTW);
    154       case kMode_MRI:
    155       case kMode_MRR:
    156         break;
    157     }
    158     UNREACHABLE();
    159     return Operand(-1);
    160   }
    161 
    162   MemOperand MemoryOperand(size_t* first_index) {
    163     const size_t index = *first_index;
    164     switch (AddressingModeField::decode(instr_->opcode())) {
    165       case kMode_None:
    166       case kMode_Operand2_R_LSR_I:
    167       case kMode_Operand2_R_ASR_I:
    168       case kMode_Operand2_R_ROR_I:
    169       case kMode_Operand2_R_UXTB:
    170       case kMode_Operand2_R_UXTH:
    171       case kMode_Operand2_R_SXTB:
    172       case kMode_Operand2_R_SXTH:
    173       case kMode_Operand2_R_SXTW:
    174         break;
    175       case kMode_Operand2_R_LSL_I:
    176         *first_index += 3;
    177         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
    178                           LSL, InputInt32(index + 2));
    179       case kMode_MRI:
    180         *first_index += 2;
    181         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
    182       case kMode_MRR:
    183         *first_index += 2;
    184         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
    185     }
    186     UNREACHABLE();
    187     return MemOperand(no_reg);
    188   }
    189 
    190   MemOperand MemoryOperand(size_t first_index = 0) {
    191     return MemoryOperand(&first_index);
    192   }
    193 
    194   Operand ToOperand(InstructionOperand* op) {
    195     if (op->IsRegister()) {
    196       return Operand(ToRegister(op));
    197     }
    198     return ToImmediate(op);
    199   }
    200 
    201   Operand ToOperand32(InstructionOperand* op) {
    202     if (op->IsRegister()) {
    203       return Operand(ToRegister(op).W());
    204     }
    205     return ToImmediate(op);
    206   }
    207 
    208   Operand ToImmediate(InstructionOperand* operand) {
    209     Constant constant = ToConstant(operand);
    210     switch (constant.type()) {
    211       case Constant::kInt32:
    212         if (RelocInfo::IsWasmSizeReference(constant.rmode())) {
    213           return Operand(constant.ToInt32(), constant.rmode());
    214         } else {
    215           return Operand(constant.ToInt32());
    216         }
    217       case Constant::kInt64:
    218         if (RelocInfo::IsWasmPtrReference(constant.rmode())) {
    219           return Operand(constant.ToInt64(), constant.rmode());
    220         } else {
    221           DCHECK(!RelocInfo::IsWasmSizeReference(constant.rmode()));
    222           return Operand(constant.ToInt64());
    223         }
    224       case Constant::kFloat32:
    225         return Operand(
    226             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
    227       case Constant::kFloat64:
    228         return Operand(
    229             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
    230       case Constant::kExternalReference:
    231         return Operand(constant.ToExternalReference());
    232       case Constant::kHeapObject:
    233         return Operand(constant.ToHeapObject());
    234       case Constant::kRpoNumber:
    235         UNREACHABLE();  // TODO(dcarney): RPO immediates on arm64.
    236         break;
    237     }
    238     UNREACHABLE();
    239     return Operand(-1);
    240   }
    241 
    242   MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const {
    243     DCHECK_NOT_NULL(op);
    244     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
    245     return SlotToMemOperand(AllocatedOperand::cast(op)->index(), masm);
    246   }
    247 
    248   MemOperand SlotToMemOperand(int slot, MacroAssembler* masm) const {
    249     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
    250     if (offset.from_frame_pointer()) {
    251       int from_sp = offset.offset() + frame_access_state()->GetSPToFPOffset();
    252       // Convert FP-offsets to SP-offsets if it results in better code.
    253       if (Assembler::IsImmLSUnscaled(from_sp) ||
    254           Assembler::IsImmLSScaled(from_sp, LSDoubleWord)) {
    255         offset = FrameOffset::FromStackPointer(from_sp);
    256       }
    257     }
    258     return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
    259                       offset.offset());
    260   }
    261 };
    262 
    263 
    264 namespace {
    265 
    266 class OutOfLineLoadNaN32 final : public OutOfLineCode {
    267  public:
    268   OutOfLineLoadNaN32(CodeGenerator* gen, DoubleRegister result)
    269       : OutOfLineCode(gen), result_(result) {}
    270 
    271   void Generate() final {
    272     __ Fmov(result_, std::numeric_limits<float>::quiet_NaN());
    273   }
    274 
    275  private:
    276   DoubleRegister const result_;
    277 };
    278 
    279 
    280 class OutOfLineLoadNaN64 final : public OutOfLineCode {
    281  public:
    282   OutOfLineLoadNaN64(CodeGenerator* gen, DoubleRegister result)
    283       : OutOfLineCode(gen), result_(result) {}
    284 
    285   void Generate() final {
    286     __ Fmov(result_, std::numeric_limits<double>::quiet_NaN());
    287   }
    288 
    289  private:
    290   DoubleRegister const result_;
    291 };
    292 
    293 
    294 class OutOfLineLoadZero final : public OutOfLineCode {
    295  public:
    296   OutOfLineLoadZero(CodeGenerator* gen, Register result)
    297       : OutOfLineCode(gen), result_(result) {}
    298 
    299   void Generate() final { __ Mov(result_, 0); }
    300 
    301  private:
    302   Register const result_;
    303 };
    304 
    305 
    306 class OutOfLineRecordWrite final : public OutOfLineCode {
    307  public:
    308   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand index,
    309                        Register value, Register scratch0, Register scratch1,
    310                        RecordWriteMode mode,
    311                        UnwindingInfoWriter* unwinding_info_writer)
    312       : OutOfLineCode(gen),
    313         object_(object),
    314         index_(index),
    315         value_(value),
    316         scratch0_(scratch0),
    317         scratch1_(scratch1),
    318         mode_(mode),
    319         must_save_lr_(!gen->frame_access_state()->has_frame()),
    320         unwinding_info_writer_(unwinding_info_writer) {}
    321 
    322   void Generate() final {
    323     if (mode_ > RecordWriteMode::kValueIsPointer) {
    324       __ JumpIfSmi(value_, exit());
    325     }
    326     __ CheckPageFlagClear(value_, scratch0_,
    327                           MemoryChunk::kPointersToHereAreInterestingMask,
    328                           exit());
    329     RememberedSetAction const remembered_set_action =
    330         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
    331                                              : OMIT_REMEMBERED_SET;
    332     SaveFPRegsMode const save_fp_mode =
    333         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    334     if (must_save_lr_) {
    335       // We need to save and restore lr if the frame was elided.
    336       __ Push(lr);
    337       unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset(),
    338                                                            __ StackPointer());
    339     }
    340     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    341                          remembered_set_action, save_fp_mode);
    342     __ Add(scratch1_, object_, index_);
    343     __ CallStub(&stub);
    344     if (must_save_lr_) {
    345       __ Pop(lr);
    346       unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
    347     }
    348   }
    349 
    350  private:
    351   Register const object_;
    352   Operand const index_;
    353   Register const value_;
    354   Register const scratch0_;
    355   Register const scratch1_;
    356   RecordWriteMode const mode_;
    357   bool must_save_lr_;
    358   UnwindingInfoWriter* const unwinding_info_writer_;
    359 };
    360 
    361 
    362 Condition FlagsConditionToCondition(FlagsCondition condition) {
    363   switch (condition) {
    364     case kEqual:
    365       return eq;
    366     case kNotEqual:
    367       return ne;
    368     case kSignedLessThan:
    369       return lt;
    370     case kSignedGreaterThanOrEqual:
    371       return ge;
    372     case kSignedLessThanOrEqual:
    373       return le;
    374     case kSignedGreaterThan:
    375       return gt;
    376     case kUnsignedLessThan:
    377       return lo;
    378     case kUnsignedGreaterThanOrEqual:
    379       return hs;
    380     case kUnsignedLessThanOrEqual:
    381       return ls;
    382     case kUnsignedGreaterThan:
    383       return hi;
    384     case kFloatLessThanOrUnordered:
    385       return lt;
    386     case kFloatGreaterThanOrEqual:
    387       return ge;
    388     case kFloatLessThanOrEqual:
    389       return ls;
    390     case kFloatGreaterThanOrUnordered:
    391       return hi;
    392     case kFloatLessThan:
    393       return lo;
    394     case kFloatGreaterThanOrEqualOrUnordered:
    395       return hs;
    396     case kFloatLessThanOrEqualOrUnordered:
    397       return le;
    398     case kFloatGreaterThan:
    399       return gt;
    400     case kOverflow:
    401       return vs;
    402     case kNotOverflow:
    403       return vc;
    404     case kUnorderedEqual:
    405     case kUnorderedNotEqual:
    406       break;
    407     case kPositiveOrZero:
    408       return pl;
    409     case kNegative:
    410       return mi;
    411   }
    412   UNREACHABLE();
    413   return nv;
    414 }
    415 
    416 }  // namespace
    417 
    418 #define ASSEMBLE_BOUNDS_CHECK(offset, length, out_of_bounds)   \
    419   do {                                                         \
    420     if (length.IsImmediate() &&                                \
    421         base::bits::IsPowerOfTwo64(length.ImmediateValue())) { \
    422       __ Tst(offset, ~(length.ImmediateValue() - 1));          \
    423       __ B(ne, out_of_bounds);                                 \
    424     } else {                                                   \
    425       __ Cmp(offset, length);                                  \
    426       __ B(hs, out_of_bounds);                                 \
    427     }                                                          \
    428   } while (0)
    429 
    430 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width)                         \
    431   do {                                                             \
    432     auto result = i.OutputFloat##width##Register();                \
    433     auto buffer = i.InputRegister(0);                              \
    434     auto offset = i.InputRegister32(1);                            \
    435     auto length = i.InputOperand32(2);                             \
    436     auto ool = new (zone()) OutOfLineLoadNaN##width(this, result); \
    437     ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry());           \
    438     __ Ldr(result, MemOperand(buffer, offset, UXTW));              \
    439     __ Bind(ool->exit());                                          \
    440   } while (0)
    441 
    442 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)             \
    443   do {                                                       \
    444     auto result = i.OutputRegister32();                      \
    445     auto buffer = i.InputRegister(0);                        \
    446     auto offset = i.InputRegister32(1);                      \
    447     auto length = i.InputOperand32(2);                       \
    448     auto ool = new (zone()) OutOfLineLoadZero(this, result); \
    449     ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry());     \
    450     __ asm_instr(result, MemOperand(buffer, offset, UXTW));  \
    451     __ Bind(ool->exit());                                    \
    452   } while (0)
    453 
    454 #define ASSEMBLE_CHECKED_LOAD_INTEGER_64(asm_instr)          \
    455   do {                                                       \
    456     auto result = i.OutputRegister();                        \
    457     auto buffer = i.InputRegister(0);                        \
    458     auto offset = i.InputRegister32(1);                      \
    459     auto length = i.InputOperand32(2);                       \
    460     auto ool = new (zone()) OutOfLineLoadZero(this, result); \
    461     ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry());     \
    462     __ asm_instr(result, MemOperand(buffer, offset, UXTW));  \
    463     __ Bind(ool->exit());                                    \
    464   } while (0)
    465 
    466 #define ASSEMBLE_CHECKED_STORE_FLOAT(width)              \
    467   do {                                                   \
    468     auto buffer = i.InputRegister(0);                    \
    469     auto offset = i.InputRegister32(1);                  \
    470     auto length = i.InputOperand32(2);                   \
    471     auto value = i.InputFloat##width##OrZeroRegister(3); \
    472     Label done;                                          \
    473     ASSEMBLE_BOUNDS_CHECK(offset, length, &done);        \
    474     __ Str(value, MemOperand(buffer, offset, UXTW));     \
    475     __ Bind(&done);                                      \
    476   } while (0)
    477 
    478 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)          \
    479   do {                                                     \
    480     auto buffer = i.InputRegister(0);                      \
    481     auto offset = i.InputRegister32(1);                    \
    482     auto length = i.InputOperand32(2);                     \
    483     auto value = i.InputOrZeroRegister32(3);               \
    484     Label done;                                            \
    485     ASSEMBLE_BOUNDS_CHECK(offset, length, &done);          \
    486     __ asm_instr(value, MemOperand(buffer, offset, UXTW)); \
    487     __ Bind(&done);                                        \
    488   } while (0)
    489 
    490 #define ASSEMBLE_CHECKED_STORE_INTEGER_64(asm_instr)       \
    491   do {                                                     \
    492     auto buffer = i.InputRegister(0);                      \
    493     auto offset = i.InputRegister32(1);                    \
    494     auto length = i.InputOperand32(2);                     \
    495     auto value = i.InputOrZeroRegister64(3);               \
    496     Label done;                                            \
    497     ASSEMBLE_BOUNDS_CHECK(offset, length, &done);          \
    498     __ asm_instr(value, MemOperand(buffer, offset, UXTW)); \
    499     __ Bind(&done);                                        \
    500   } while (0)
    501 
    502 #define ASSEMBLE_SHIFT(asm_instr, width)                                    \
    503   do {                                                                      \
    504     if (instr->InputAt(1)->IsRegister()) {                                  \
    505       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0),    \
    506                    i.InputRegister##width(1));                              \
    507     } else {                                                                \
    508       uint32_t imm =                                                        \
    509           static_cast<uint32_t>(i.InputOperand##width(1).ImmediateValue()); \
    510       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0),    \
    511                    imm % (width));                                          \
    512     }                                                                       \
    513   } while (0)
    514 
    515 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)                       \
    516   do {                                                                \
    517     __ asm_instr(i.OutputRegister(),                                  \
    518                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    519     __ Dmb(InnerShareable, BarrierAll);                               \
    520   } while (0)
    521 
    522 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)                      \
    523   do {                                                                \
    524     __ Dmb(InnerShareable, BarrierAll);                               \
    525     __ asm_instr(i.InputRegister(2),                                  \
    526                  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
    527     __ Dmb(InnerShareable, BarrierAll);                               \
    528   } while (0)
    529 
    530 #define ASSEMBLE_IEEE754_BINOP(name)                                          \
    531   do {                                                                        \
    532     FrameScope scope(masm(), StackFrame::MANUAL);                             \
    533     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    534                      0, 2);                                                   \
    535   } while (0)
    536 
    537 #define ASSEMBLE_IEEE754_UNOP(name)                                           \
    538   do {                                                                        \
    539     FrameScope scope(masm(), StackFrame::MANUAL);                             \
    540     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    541                      0, 1);                                                   \
    542   } while (0)
    543 
    544 void CodeGenerator::AssembleDeconstructFrame() {
    545   const CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
    546   if (descriptor->IsCFunctionCall() || descriptor->UseNativeStack()) {
    547     __ Mov(csp, fp);
    548   } else {
    549     __ Mov(jssp, fp);
    550   }
    551   __ Pop(fp, lr);
    552 
    553   unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
    554 }
    555 
    556 void CodeGenerator::AssemblePrepareTailCall() {
    557   if (frame_access_state()->has_frame()) {
    558     __ Ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    559     __ Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    560   }
    561   frame_access_state()->SetFrameAccessToSP();
    562 }
    563 
    564 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
    565                                                      Register scratch1,
    566                                                      Register scratch2,
    567                                                      Register scratch3) {
    568   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
    569   Label done;
    570 
    571   // Check if current frame is an arguments adaptor frame.
    572   __ Ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
    573   __ Cmp(scratch1,
    574          Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
    575   __ B(ne, &done);
    576 
    577   // Load arguments count from current arguments adaptor frame (note, it
    578   // does not include receiver).
    579   Register caller_args_count_reg = scratch1;
    580   __ Ldr(caller_args_count_reg,
    581          MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
    582   __ SmiUntag(caller_args_count_reg);
    583 
    584   ParameterCount callee_args_count(args_reg);
    585   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
    586                         scratch3);
    587   __ bind(&done);
    588 }
    589 
    590 namespace {
    591 
    592 void AdjustStackPointerForTailCall(MacroAssembler* masm,
    593                                    FrameAccessState* state,
    594                                    int new_slot_above_sp,
    595                                    bool allow_shrinkage = true) {
    596   int current_sp_offset = state->GetSPToFPSlotCount() +
    597                           StandardFrameConstants::kFixedSlotCountAboveFp;
    598   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
    599   if (stack_slot_delta > 0) {
    600     masm->Claim(stack_slot_delta);
    601     state->IncreaseSPDelta(stack_slot_delta);
    602   } else if (allow_shrinkage && stack_slot_delta < 0) {
    603     masm->Drop(-stack_slot_delta);
    604     state->IncreaseSPDelta(stack_slot_delta);
    605   }
    606 }
    607 
    608 }  // namespace
    609 
    610 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
    611                                               int first_unused_stack_slot) {
    612   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    613                                 first_unused_stack_slot, false);
    614 }
    615 
    616 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
    617                                              int first_unused_stack_slot) {
    618   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    619                                 first_unused_stack_slot);
    620 }
    621 
    622 // Assembles an instruction after register allocation, producing machine code.
    623 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    624     Instruction* instr) {
    625   Arm64OperandConverter i(this, instr);
    626   InstructionCode opcode = instr->opcode();
    627   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
    628   switch (arch_opcode) {
    629     case kArchCallCodeObject: {
    630       EnsureSpaceForLazyDeopt();
    631       if (instr->InputAt(0)->IsImmediate()) {
    632         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
    633                 RelocInfo::CODE_TARGET);
    634       } else {
    635         Register target = i.InputRegister(0);
    636         __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
    637         __ Call(target);
    638       }
    639       RecordCallPosition(instr);
    640       // TODO(titzer): this is ugly. JSSP should be a caller-save register
    641       // in this case, but it is not possible to express in the register
    642       // allocator.
    643       CallDescriptor::Flags flags(MiscField::decode(opcode));
    644       if (flags & CallDescriptor::kRestoreJSSP) {
    645         __ Ldr(jssp, MemOperand(csp));
    646         __ Mov(csp, jssp);
    647       }
    648       if (flags & CallDescriptor::kRestoreCSP) {
    649         __ Mov(csp, jssp);
    650         __ AssertCspAligned();
    651       }
    652       frame_access_state()->ClearSPDelta();
    653       break;
    654     }
    655     case kArchTailCallCodeObjectFromJSFunction:
    656     case kArchTailCallCodeObject: {
    657       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
    658         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    659                                          i.TempRegister(0), i.TempRegister(1),
    660                                          i.TempRegister(2));
    661       }
    662       if (instr->InputAt(0)->IsImmediate()) {
    663         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
    664                 RelocInfo::CODE_TARGET);
    665       } else {
    666         Register target = i.InputRegister(0);
    667         __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
    668         __ Jump(target);
    669       }
    670       unwinding_info_writer_.MarkBlockWillExit();
    671       frame_access_state()->ClearSPDelta();
    672       frame_access_state()->SetFrameAccessToDefault();
    673       break;
    674     }
    675     case kArchTailCallAddress: {
    676       CHECK(!instr->InputAt(0)->IsImmediate());
    677       __ Jump(i.InputRegister(0));
    678       unwinding_info_writer_.MarkBlockWillExit();
    679       frame_access_state()->ClearSPDelta();
    680       frame_access_state()->SetFrameAccessToDefault();
    681       break;
    682     }
    683     case kArchCallJSFunction: {
    684       EnsureSpaceForLazyDeopt();
    685       Register func = i.InputRegister(0);
    686       if (FLAG_debug_code) {
    687         // Check the function's context matches the context argument.
    688         UseScratchRegisterScope scope(masm());
    689         Register temp = scope.AcquireX();
    690         __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset));
    691         __ cmp(cp, temp);
    692         __ Assert(eq, kWrongFunctionContext);
    693       }
    694       __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    695       __ Call(x10);
    696       RecordCallPosition(instr);
    697       // TODO(titzer): this is ugly. JSSP should be a caller-save register
    698       // in this case, but it is not possible to express in the register
    699       // allocator.
    700       CallDescriptor::Flags flags(MiscField::decode(opcode));
    701       if (flags & CallDescriptor::kRestoreJSSP) {
    702         __ Ldr(jssp, MemOperand(csp));
    703         __ Mov(csp, jssp);
    704       }
    705       if (flags & CallDescriptor::kRestoreCSP) {
    706         __ Mov(csp, jssp);
    707         __ AssertCspAligned();
    708       }
    709       frame_access_state()->ClearSPDelta();
    710       break;
    711     }
    712     case kArchTailCallJSFunctionFromJSFunction: {
    713       Register func = i.InputRegister(0);
    714       if (FLAG_debug_code) {
    715         // Check the function's context matches the context argument.
    716         UseScratchRegisterScope scope(masm());
    717         Register temp = scope.AcquireX();
    718         __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset));
    719         __ cmp(cp, temp);
    720         __ Assert(eq, kWrongFunctionContext);
    721       }
    722       AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    723                                        i.TempRegister(0), i.TempRegister(1),
    724                                        i.TempRegister(2));
    725       __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    726       __ Jump(x10);
    727       frame_access_state()->ClearSPDelta();
    728       frame_access_state()->SetFrameAccessToDefault();
    729       break;
    730     }
    731     case kArchPrepareCallCFunction:
    732       // We don't need kArchPrepareCallCFunction on arm64 as the instruction
    733       // selector already perform a Claim to reserve space on the stack and
    734       // guarantee correct alignment of stack pointer.
    735       UNREACHABLE();
    736       break;
    737     case kArchPrepareTailCall:
    738       AssemblePrepareTailCall();
    739       break;
    740     case kArchCallCFunction: {
    741       int const num_parameters = MiscField::decode(instr->opcode());
    742       if (instr->InputAt(0)->IsImmediate()) {
    743         ExternalReference ref = i.InputExternalReference(0);
    744         __ CallCFunction(ref, num_parameters, 0);
    745       } else {
    746         Register func = i.InputRegister(0);
    747         __ CallCFunction(func, num_parameters, 0);
    748       }
    749       // CallCFunction only supports register arguments so we never need to call
    750       // frame()->ClearOutgoingParameterSlots() here.
    751       DCHECK(frame_access_state()->sp_delta() == 0);
    752       break;
    753     }
    754     case kArchJmp:
    755       AssembleArchJump(i.InputRpo(0));
    756       break;
    757     case kArchTableSwitch:
    758       AssembleArchTableSwitch(instr);
    759       break;
    760     case kArchLookupSwitch:
    761       AssembleArchLookupSwitch(instr);
    762       break;
    763     case kArchDebugBreak:
    764       __ Debug("kArchDebugBreak", 0, BREAK);
    765       break;
    766     case kArchComment: {
    767       Address comment_string = i.InputExternalReference(0).address();
    768       __ RecordComment(reinterpret_cast<const char*>(comment_string));
    769       break;
    770     }
    771     case kArchNop:
    772     case kArchThrowTerminator:
    773       // don't emit code for nops.
    774       break;
    775     case kArchDeoptimize: {
    776       int deopt_state_id =
    777           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    778       CodeGenResult result =
    779           AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
    780       if (result != kSuccess) return result;
    781       break;
    782     }
    783     case kArchRet:
    784       AssembleReturn(instr->InputAt(0));
    785       break;
    786     case kArchStackPointer:
    787       __ mov(i.OutputRegister(), masm()->StackPointer());
    788       break;
    789     case kArchFramePointer:
    790       __ mov(i.OutputRegister(), fp);
    791       break;
    792     case kArchParentFramePointer:
    793       if (frame_access_state()->has_frame()) {
    794         __ ldr(i.OutputRegister(), MemOperand(fp, 0));
    795       } else {
    796         __ mov(i.OutputRegister(), fp);
    797       }
    798       break;
    799     case kArchTruncateDoubleToI:
    800       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
    801       break;
    802     case kArchStoreWithWriteBarrier: {
    803       RecordWriteMode mode =
    804           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    805       AddressingMode addressing_mode =
    806           AddressingModeField::decode(instr->opcode());
    807       Register object = i.InputRegister(0);
    808       Operand index(0);
    809       if (addressing_mode == kMode_MRI) {
    810         index = Operand(i.InputInt64(1));
    811       } else {
    812         DCHECK_EQ(addressing_mode, kMode_MRR);
    813         index = Operand(i.InputRegister(1));
    814       }
    815       Register value = i.InputRegister(2);
    816       Register scratch0 = i.TempRegister(0);
    817       Register scratch1 = i.TempRegister(1);
    818       auto ool = new (zone())
    819           OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
    820                                mode, &unwinding_info_writer_);
    821       __ Str(value, MemOperand(object, index));
    822       __ CheckPageFlagSet(object, scratch0,
    823                           MemoryChunk::kPointersFromHereAreInterestingMask,
    824                           ool->entry());
    825       __ Bind(ool->exit());
    826       break;
    827     }
    828     case kArchStackSlot: {
    829       FrameOffset offset =
    830           frame_access_state()->GetFrameOffset(i.InputInt32(0));
    831       Register base;
    832       if (offset.from_stack_pointer()) {
    833         base = __ StackPointer();
    834       } else {
    835         base = fp;
    836       }
    837       __ Add(i.OutputRegister(0), base, Operand(offset.offset()));
    838       break;
    839     }
    840     case kIeee754Float64Acos:
    841       ASSEMBLE_IEEE754_UNOP(acos);
    842       break;
    843     case kIeee754Float64Acosh:
    844       ASSEMBLE_IEEE754_UNOP(acosh);
    845       break;
    846     case kIeee754Float64Asin:
    847       ASSEMBLE_IEEE754_UNOP(asin);
    848       break;
    849     case kIeee754Float64Asinh:
    850       ASSEMBLE_IEEE754_UNOP(asinh);
    851       break;
    852     case kIeee754Float64Atan:
    853       ASSEMBLE_IEEE754_UNOP(atan);
    854       break;
    855     case kIeee754Float64Atanh:
    856       ASSEMBLE_IEEE754_UNOP(atanh);
    857       break;
    858     case kIeee754Float64Atan2:
    859       ASSEMBLE_IEEE754_BINOP(atan2);
    860       break;
    861     case kIeee754Float64Cos:
    862       ASSEMBLE_IEEE754_UNOP(cos);
    863       break;
    864     case kIeee754Float64Cosh:
    865       ASSEMBLE_IEEE754_UNOP(cosh);
    866       break;
    867     case kIeee754Float64Cbrt:
    868       ASSEMBLE_IEEE754_UNOP(cbrt);
    869       break;
    870     case kIeee754Float64Exp:
    871       ASSEMBLE_IEEE754_UNOP(exp);
    872       break;
    873     case kIeee754Float64Expm1:
    874       ASSEMBLE_IEEE754_UNOP(expm1);
    875       break;
    876     case kIeee754Float64Log:
    877       ASSEMBLE_IEEE754_UNOP(log);
    878       break;
    879     case kIeee754Float64Log1p:
    880       ASSEMBLE_IEEE754_UNOP(log1p);
    881       break;
    882     case kIeee754Float64Log2:
    883       ASSEMBLE_IEEE754_UNOP(log2);
    884       break;
    885     case kIeee754Float64Log10:
    886       ASSEMBLE_IEEE754_UNOP(log10);
    887       break;
    888     case kIeee754Float64Pow: {
    889       MathPowStub stub(isolate(), MathPowStub::DOUBLE);
    890       __ CallStub(&stub);
    891       break;
    892     }
    893     case kIeee754Float64Sin:
    894       ASSEMBLE_IEEE754_UNOP(sin);
    895       break;
    896     case kIeee754Float64Sinh:
    897       ASSEMBLE_IEEE754_UNOP(sinh);
    898       break;
    899     case kIeee754Float64Tan:
    900       ASSEMBLE_IEEE754_UNOP(tan);
    901       break;
    902     case kIeee754Float64Tanh:
    903       ASSEMBLE_IEEE754_UNOP(tanh);
    904       break;
    905     case kArm64Float32RoundDown:
    906       __ Frintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
    907       break;
    908     case kArm64Float64RoundDown:
    909       __ Frintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
    910       break;
    911     case kArm64Float32RoundUp:
    912       __ Frintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
    913       break;
    914     case kArm64Float64RoundUp:
    915       __ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
    916       break;
    917     case kArm64Float64RoundTiesAway:
    918       __ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
    919       break;
    920     case kArm64Float32RoundTruncate:
    921       __ Frintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
    922       break;
    923     case kArm64Float64RoundTruncate:
    924       __ Frintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
    925       break;
    926     case kArm64Float32RoundTiesEven:
    927       __ Frintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
    928       break;
    929     case kArm64Float64RoundTiesEven:
    930       __ Frintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
    931       break;
    932     case kArm64Add:
    933       if (FlagsModeField::decode(opcode) != kFlags_none) {
    934         __ Adds(i.OutputRegister(), i.InputOrZeroRegister64(0),
    935                 i.InputOperand2_64(1));
    936       } else {
    937       __ Add(i.OutputRegister(), i.InputOrZeroRegister64(0),
    938              i.InputOperand2_64(1));
    939       }
    940       break;
    941     case kArm64Add32:
    942       if (FlagsModeField::decode(opcode) != kFlags_none) {
    943         __ Adds(i.OutputRegister32(), i.InputOrZeroRegister32(0),
    944                 i.InputOperand2_32(1));
    945       } else {
    946         __ Add(i.OutputRegister32(), i.InputOrZeroRegister32(0),
    947                i.InputOperand2_32(1));
    948       }
    949       break;
    950     case kArm64And:
    951       if (FlagsModeField::decode(opcode) != kFlags_none) {
    952         // The ands instruction only sets N and Z, so only the following
    953         // conditions make sense.
    954         DCHECK(FlagsConditionField::decode(opcode) == kEqual ||
    955                FlagsConditionField::decode(opcode) == kNotEqual ||
    956                FlagsConditionField::decode(opcode) == kPositiveOrZero ||
    957                FlagsConditionField::decode(opcode) == kNegative);
    958         __ Ands(i.OutputRegister(), i.InputOrZeroRegister64(0),
    959                 i.InputOperand2_64(1));
    960       } else {
    961         __ And(i.OutputRegister(), i.InputOrZeroRegister64(0),
    962                i.InputOperand2_64(1));
    963       }
    964       break;
    965     case kArm64And32:
    966       if (FlagsModeField::decode(opcode) != kFlags_none) {
    967         // The ands instruction only sets N and Z, so only the following
    968         // conditions make sense.
    969         DCHECK(FlagsConditionField::decode(opcode) == kEqual ||
    970                FlagsConditionField::decode(opcode) == kNotEqual ||
    971                FlagsConditionField::decode(opcode) == kPositiveOrZero ||
    972                FlagsConditionField::decode(opcode) == kNegative);
    973         __ Ands(i.OutputRegister32(), i.InputOrZeroRegister32(0),
    974                 i.InputOperand2_32(1));
    975       } else {
    976         __ And(i.OutputRegister32(), i.InputOrZeroRegister32(0),
    977                i.InputOperand2_32(1));
    978       }
    979       break;
    980     case kArm64Bic:
    981       __ Bic(i.OutputRegister(), i.InputOrZeroRegister64(0),
    982              i.InputOperand2_64(1));
    983       break;
    984     case kArm64Bic32:
    985       __ Bic(i.OutputRegister32(), i.InputOrZeroRegister32(0),
    986              i.InputOperand2_32(1));
    987       break;
    988     case kArm64Mul:
    989       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    990       break;
    991     case kArm64Mul32:
    992       __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
    993       break;
    994     case kArm64Smull:
    995       __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
    996       break;
    997     case kArm64Umull:
    998       __ Umull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
    999       break;
   1000     case kArm64Madd:
   1001       __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
   1002               i.InputRegister(2));
   1003       break;
   1004     case kArm64Madd32:
   1005       __ Madd(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
   1006               i.InputRegister32(2));
   1007       break;
   1008     case kArm64Msub:
   1009       __ Msub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
   1010               i.InputRegister(2));
   1011       break;
   1012     case kArm64Msub32:
   1013       __ Msub(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
   1014               i.InputRegister32(2));
   1015       break;
   1016     case kArm64Mneg:
   1017       __ Mneg(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1018       break;
   1019     case kArm64Mneg32:
   1020       __ Mneg(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
   1021       break;
   1022     case kArm64Idiv:
   1023       __ Sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1024       break;
   1025     case kArm64Idiv32:
   1026       __ Sdiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
   1027       break;
   1028     case kArm64Udiv:
   1029       __ Udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1030       break;
   1031     case kArm64Udiv32:
   1032       __ Udiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
   1033       break;
   1034     case kArm64Imod: {
   1035       UseScratchRegisterScope scope(masm());
   1036       Register temp = scope.AcquireX();
   1037       __ Sdiv(temp, i.InputRegister(0), i.InputRegister(1));
   1038       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
   1039       break;
   1040     }
   1041     case kArm64Imod32: {
   1042       UseScratchRegisterScope scope(masm());
   1043       Register temp = scope.AcquireW();
   1044       __ Sdiv(temp, i.InputRegister32(0), i.InputRegister32(1));
   1045       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
   1046               i.InputRegister32(0));
   1047       break;
   1048     }
   1049     case kArm64Umod: {
   1050       UseScratchRegisterScope scope(masm());
   1051       Register temp = scope.AcquireX();
   1052       __ Udiv(temp, i.InputRegister(0), i.InputRegister(1));
   1053       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
   1054       break;
   1055     }
   1056     case kArm64Umod32: {
   1057       UseScratchRegisterScope scope(masm());
   1058       Register temp = scope.AcquireW();
   1059       __ Udiv(temp, i.InputRegister32(0), i.InputRegister32(1));
   1060       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
   1061               i.InputRegister32(0));
   1062       break;
   1063     }
   1064     case kArm64Not:
   1065       __ Mvn(i.OutputRegister(), i.InputOperand(0));
   1066       break;
   1067     case kArm64Not32:
   1068       __ Mvn(i.OutputRegister32(), i.InputOperand32(0));
   1069       break;
   1070     case kArm64Or:
   1071       __ Orr(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1072              i.InputOperand2_64(1));
   1073       break;
   1074     case kArm64Or32:
   1075       __ Orr(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1076              i.InputOperand2_32(1));
   1077       break;
   1078     case kArm64Orn:
   1079       __ Orn(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1080              i.InputOperand2_64(1));
   1081       break;
   1082     case kArm64Orn32:
   1083       __ Orn(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1084              i.InputOperand2_32(1));
   1085       break;
   1086     case kArm64Eor:
   1087       __ Eor(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1088              i.InputOperand2_64(1));
   1089       break;
   1090     case kArm64Eor32:
   1091       __ Eor(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1092              i.InputOperand2_32(1));
   1093       break;
   1094     case kArm64Eon:
   1095       __ Eon(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1096              i.InputOperand2_64(1));
   1097       break;
   1098     case kArm64Eon32:
   1099       __ Eon(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1100              i.InputOperand2_32(1));
   1101       break;
   1102     case kArm64Sub:
   1103       if (FlagsModeField::decode(opcode) != kFlags_none) {
   1104         __ Subs(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1105                 i.InputOperand2_64(1));
   1106       } else {
   1107       __ Sub(i.OutputRegister(), i.InputOrZeroRegister64(0),
   1108              i.InputOperand2_64(1));
   1109       }
   1110       break;
   1111     case kArm64Sub32:
   1112       if (FlagsModeField::decode(opcode) != kFlags_none) {
   1113         __ Subs(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1114                 i.InputOperand2_32(1));
   1115       } else {
   1116         __ Sub(i.OutputRegister32(), i.InputOrZeroRegister32(0),
   1117                i.InputOperand2_32(1));
   1118       }
   1119       break;
   1120     case kArm64Lsl:
   1121       ASSEMBLE_SHIFT(Lsl, 64);
   1122       break;
   1123     case kArm64Lsl32:
   1124       ASSEMBLE_SHIFT(Lsl, 32);
   1125       break;
   1126     case kArm64Lsr:
   1127       ASSEMBLE_SHIFT(Lsr, 64);
   1128       break;
   1129     case kArm64Lsr32:
   1130       ASSEMBLE_SHIFT(Lsr, 32);
   1131       break;
   1132     case kArm64Asr:
   1133       ASSEMBLE_SHIFT(Asr, 64);
   1134       break;
   1135     case kArm64Asr32:
   1136       ASSEMBLE_SHIFT(Asr, 32);
   1137       break;
   1138     case kArm64Ror:
   1139       ASSEMBLE_SHIFT(Ror, 64);
   1140       break;
   1141     case kArm64Ror32:
   1142       ASSEMBLE_SHIFT(Ror, 32);
   1143       break;
   1144     case kArm64Mov32:
   1145       __ Mov(i.OutputRegister32(), i.InputRegister32(0));
   1146       break;
   1147     case kArm64Sxtb32:
   1148       __ Sxtb(i.OutputRegister32(), i.InputRegister32(0));
   1149       break;
   1150     case kArm64Sxth32:
   1151       __ Sxth(i.OutputRegister32(), i.InputRegister32(0));
   1152       break;
   1153     case kArm64Sxtw:
   1154       __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
   1155       break;
   1156     case kArm64Sbfx32:
   1157       __ Sbfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt5(1),
   1158               i.InputInt5(2));
   1159       break;
   1160     case kArm64Ubfx:
   1161       __ Ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt6(1),
   1162               i.InputInt6(2));
   1163       break;
   1164     case kArm64Ubfx32:
   1165       __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt5(1),
   1166               i.InputInt5(2));
   1167       break;
   1168     case kArm64Ubfiz32:
   1169       __ Ubfiz(i.OutputRegister32(), i.InputRegister32(0), i.InputInt5(1),
   1170                i.InputInt5(2));
   1171       break;
   1172     case kArm64Bfi:
   1173       __ Bfi(i.OutputRegister(), i.InputRegister(1), i.InputInt6(2),
   1174              i.InputInt6(3));
   1175       break;
   1176     case kArm64TestAndBranch32:
   1177     case kArm64TestAndBranch:
   1178       // Pseudo instructions turned into tbz/tbnz in AssembleArchBranch.
   1179       break;
   1180     case kArm64CompareAndBranch32:
   1181     case kArm64CompareAndBranch:
   1182       // Pseudo instruction turned into cbz/cbnz in AssembleArchBranch.
   1183       break;
   1184     case kArm64ClaimCSP: {
   1185       int count = RoundUp(i.InputInt32(0), 2);
   1186       Register prev = __ StackPointer();
   1187       if (prev.Is(jssp)) {
   1188         // TODO(titzer): make this a macro-assembler method.
   1189         // Align the CSP and store the previous JSSP on the stack.
   1190         UseScratchRegisterScope scope(masm());
   1191         Register tmp = scope.AcquireX();
   1192 
   1193         int sp_alignment = __ ActivationFrameAlignment();
   1194         __ Sub(tmp, jssp, kPointerSize);
   1195         __ And(tmp, tmp, Operand(~static_cast<uint64_t>(sp_alignment - 1)));
   1196         __ Mov(csp, tmp);
   1197         __ Str(jssp, MemOperand(csp));
   1198         if (count > 0) {
   1199           __ SetStackPointer(csp);
   1200           __ Claim(count);
   1201           __ SetStackPointer(prev);
   1202         }
   1203       } else {
   1204         __ AssertCspAligned();
   1205         if (count > 0) {
   1206           __ Claim(count);
   1207           frame_access_state()->IncreaseSPDelta(count);
   1208         }
   1209       }
   1210       break;
   1211     }
   1212     case kArm64ClaimJSSP: {
   1213       int count = i.InputInt32(0);
   1214       if (csp.Is(__ StackPointer())) {
   1215         // No JSSP is set up. Compute it from the CSP.
   1216         __ AssertCspAligned();
   1217         if (count > 0) {
   1218           int even = RoundUp(count, 2);
   1219           __ Sub(jssp, csp, count * kPointerSize);
   1220           __ Sub(csp, csp, even * kPointerSize);  // Must always be aligned.
   1221           frame_access_state()->IncreaseSPDelta(even);
   1222         } else {
   1223           __ Mov(jssp, csp);
   1224         }
   1225       } else {
   1226         // JSSP is the current stack pointer, just use regular Claim().
   1227         __ Claim(count);
   1228         frame_access_state()->IncreaseSPDelta(count);
   1229       }
   1230       break;
   1231     }
   1232     case kArm64PokeCSP:  // fall through
   1233     case kArm64PokeJSSP: {
   1234       Register prev = __ StackPointer();
   1235       __ SetStackPointer(arch_opcode == kArm64PokeCSP ? csp : jssp);
   1236       Operand operand(i.InputInt32(1) * kPointerSize);
   1237       if (instr->InputAt(0)->IsFPRegister()) {
   1238         __ Poke(i.InputFloat64Register(0), operand);
   1239       } else {
   1240         __ Poke(i.InputRegister(0), operand);
   1241       }
   1242       __ SetStackPointer(prev);
   1243       break;
   1244     }
   1245     case kArm64PokePair: {
   1246       int slot = i.InputInt32(2) - 1;
   1247       if (instr->InputAt(0)->IsFPRegister()) {
   1248         __ PokePair(i.InputFloat64Register(1), i.InputFloat64Register(0),
   1249                     slot * kPointerSize);
   1250       } else {
   1251         __ PokePair(i.InputRegister(1), i.InputRegister(0),
   1252                     slot * kPointerSize);
   1253       }
   1254       break;
   1255     }
   1256     case kArm64Clz:
   1257       __ Clz(i.OutputRegister64(), i.InputRegister64(0));
   1258       break;
   1259     case kArm64Clz32:
   1260       __ Clz(i.OutputRegister32(), i.InputRegister32(0));
   1261       break;
   1262     case kArm64Rbit:
   1263       __ Rbit(i.OutputRegister64(), i.InputRegister64(0));
   1264       break;
   1265     case kArm64Rbit32:
   1266       __ Rbit(i.OutputRegister32(), i.InputRegister32(0));
   1267       break;
   1268     case kArm64Cmp:
   1269       __ Cmp(i.InputOrZeroRegister64(0), i.InputOperand2_64(1));
   1270       break;
   1271     case kArm64Cmp32:
   1272       __ Cmp(i.InputOrZeroRegister32(0), i.InputOperand2_32(1));
   1273       break;
   1274     case kArm64Cmn:
   1275       __ Cmn(i.InputOrZeroRegister64(0), i.InputOperand2_64(1));
   1276       break;
   1277     case kArm64Cmn32:
   1278       __ Cmn(i.InputOrZeroRegister32(0), i.InputOperand2_32(1));
   1279       break;
   1280     case kArm64Tst:
   1281       __ Tst(i.InputOrZeroRegister64(0), i.InputOperand(1));
   1282       break;
   1283     case kArm64Tst32:
   1284       __ Tst(i.InputOrZeroRegister32(0), i.InputOperand32(1));
   1285       break;
   1286     case kArm64Float32Cmp:
   1287       if (instr->InputAt(1)->IsFPRegister()) {
   1288         __ Fcmp(i.InputFloat32Register(0), i.InputFloat32Register(1));
   1289       } else {
   1290         DCHECK(instr->InputAt(1)->IsImmediate());
   1291         // 0.0 is the only immediate supported by fcmp instructions.
   1292         DCHECK(i.InputFloat32(1) == 0.0f);
   1293         __ Fcmp(i.InputFloat32Register(0), i.InputFloat32(1));
   1294       }
   1295       break;
   1296     case kArm64Float32Add:
   1297       __ Fadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1298               i.InputFloat32Register(1));
   1299       break;
   1300     case kArm64Float32Sub:
   1301       __ Fsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1302               i.InputFloat32Register(1));
   1303       break;
   1304     case kArm64Float32Mul:
   1305       __ Fmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1306               i.InputFloat32Register(1));
   1307       break;
   1308     case kArm64Float32Div:
   1309       __ Fdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1310               i.InputFloat32Register(1));
   1311       break;
   1312     case kArm64Float32Abs:
   1313       __ Fabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
   1314       break;
   1315     case kArm64Float32Neg:
   1316       __ Fneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
   1317       break;
   1318     case kArm64Float32Sqrt:
   1319       __ Fsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
   1320       break;
   1321     case kArm64Float64Cmp:
   1322       if (instr->InputAt(1)->IsFPRegister()) {
   1323         __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1324       } else {
   1325         DCHECK(instr->InputAt(1)->IsImmediate());
   1326         // 0.0 is the only immediate supported by fcmp instructions.
   1327         DCHECK(i.InputDouble(1) == 0.0);
   1328         __ Fcmp(i.InputDoubleRegister(0), i.InputDouble(1));
   1329       }
   1330       break;
   1331     case kArm64Float64Add:
   1332       __ Fadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1333               i.InputDoubleRegister(1));
   1334       break;
   1335     case kArm64Float64Sub:
   1336       __ Fsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1337               i.InputDoubleRegister(1));
   1338       break;
   1339     case kArm64Float64Mul:
   1340       __ Fmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1341               i.InputDoubleRegister(1));
   1342       break;
   1343     case kArm64Float64Div:
   1344       __ Fdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1345               i.InputDoubleRegister(1));
   1346       break;
   1347     case kArm64Float64Mod: {
   1348       // TODO(dcarney): implement directly. See note in lithium-codegen-arm64.cc
   1349       FrameScope scope(masm(), StackFrame::MANUAL);
   1350       DCHECK(d0.is(i.InputDoubleRegister(0)));
   1351       DCHECK(d1.is(i.InputDoubleRegister(1)));
   1352       DCHECK(d0.is(i.OutputDoubleRegister()));
   1353       // TODO(dcarney): make sure this saves all relevant registers.
   1354       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
   1355                        0, 2);
   1356       break;
   1357     }
   1358     case kArm64Float32Max: {
   1359       __ Fmax(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1360               i.InputFloat32Register(1));
   1361       break;
   1362     }
   1363     case kArm64Float64Max: {
   1364       __ Fmax(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1365               i.InputDoubleRegister(1));
   1366       break;
   1367     }
   1368     case kArm64Float32Min: {
   1369       __ Fmin(i.OutputFloat32Register(), i.InputFloat32Register(0),
   1370               i.InputFloat32Register(1));
   1371       break;
   1372     }
   1373     case kArm64Float64Min: {
   1374       __ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1375               i.InputDoubleRegister(1));
   1376       break;
   1377     }
   1378     case kArm64Float64Abs:
   1379       __ Fabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1380       break;
   1381     case kArm64Float64Neg:
   1382       __ Fneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1383       break;
   1384     case kArm64Float64Sqrt:
   1385       __ Fsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1386       break;
   1387     case kArm64Float32ToFloat64:
   1388       __ Fcvt(i.OutputDoubleRegister(), i.InputDoubleRegister(0).S());
   1389       break;
   1390     case kArm64Float64ToFloat32:
   1391       __ Fcvt(i.OutputDoubleRegister().S(), i.InputDoubleRegister(0));
   1392       break;
   1393     case kArm64Float32ToInt32:
   1394       __ Fcvtzs(i.OutputRegister32(), i.InputFloat32Register(0));
   1395       // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
   1396       // because INT32_MIN allows easier out-of-bounds detection.
   1397       __ Cmn(i.OutputRegister32(), 1);
   1398       __ Csinc(i.OutputRegister32(), i.OutputRegister32(), i.OutputRegister32(),
   1399                vc);
   1400       break;
   1401     case kArm64Float64ToInt32:
   1402       __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
   1403       break;
   1404     case kArm64Float32ToUint32:
   1405       __ Fcvtzu(i.OutputRegister32(), i.InputFloat32Register(0));
   1406       // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
   1407       // because 0 allows easier out-of-bounds detection.
   1408       __ Cmn(i.OutputRegister32(), 1);
   1409       __ Adc(i.OutputRegister32(), i.OutputRegister32(), Operand(0));
   1410       break;
   1411     case kArm64Float64ToUint32:
   1412       __ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
   1413       break;
   1414     case kArm64Float32ToInt64:
   1415       __ Fcvtzs(i.OutputRegister64(), i.InputFloat32Register(0));
   1416       if (i.OutputCount() > 1) {
   1417         __ Mov(i.OutputRegister(1), 1);
   1418         Label done;
   1419         __ Cmp(i.OutputRegister(0), 1);
   1420         __ Ccmp(i.OutputRegister(0), -1, VFlag, vc);
   1421         __ Fccmp(i.InputFloat32Register(0), i.InputFloat32Register(0), VFlag,
   1422                  vc);
   1423         __ B(vc, &done);
   1424         __ Fcmp(i.InputFloat32Register(0), static_cast<float>(INT64_MIN));
   1425         __ Cset(i.OutputRegister(1), eq);
   1426         __ Bind(&done);
   1427       }
   1428       break;
   1429     case kArm64Float64ToInt64:
   1430       __ Fcvtzs(i.OutputRegister(0), i.InputDoubleRegister(0));
   1431       if (i.OutputCount() > 1) {
   1432         __ Mov(i.OutputRegister(1), 1);
   1433         Label done;
   1434         __ Cmp(i.OutputRegister(0), 1);
   1435         __ Ccmp(i.OutputRegister(0), -1, VFlag, vc);
   1436         __ Fccmp(i.InputDoubleRegister(0), i.InputDoubleRegister(0), VFlag, vc);
   1437         __ B(vc, &done);
   1438         __ Fcmp(i.InputDoubleRegister(0), static_cast<double>(INT64_MIN));
   1439         __ Cset(i.OutputRegister(1), eq);
   1440         __ Bind(&done);
   1441       }
   1442       break;
   1443     case kArm64Float32ToUint64:
   1444       __ Fcvtzu(i.OutputRegister64(), i.InputFloat32Register(0));
   1445       if (i.OutputCount() > 1) {
   1446         __ Fcmp(i.InputFloat32Register(0), -1.0);
   1447         __ Ccmp(i.OutputRegister(0), -1, ZFlag, gt);
   1448         __ Cset(i.OutputRegister(1), ne);
   1449       }
   1450       break;
   1451     case kArm64Float64ToUint64:
   1452       __ Fcvtzu(i.OutputRegister64(), i.InputDoubleRegister(0));
   1453       if (i.OutputCount() > 1) {
   1454         __ Fcmp(i.InputDoubleRegister(0), -1.0);
   1455         __ Ccmp(i.OutputRegister(0), -1, ZFlag, gt);
   1456         __ Cset(i.OutputRegister(1), ne);
   1457       }
   1458       break;
   1459     case kArm64Int32ToFloat32:
   1460       __ Scvtf(i.OutputFloat32Register(), i.InputRegister32(0));
   1461       break;
   1462     case kArm64Int32ToFloat64:
   1463       __ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
   1464       break;
   1465     case kArm64Int64ToFloat32:
   1466       __ Scvtf(i.OutputDoubleRegister().S(), i.InputRegister64(0));
   1467       break;
   1468     case kArm64Int64ToFloat64:
   1469       __ Scvtf(i.OutputDoubleRegister(), i.InputRegister64(0));
   1470       break;
   1471     case kArm64Uint32ToFloat32:
   1472       __ Ucvtf(i.OutputFloat32Register(), i.InputRegister32(0));
   1473       break;
   1474     case kArm64Uint32ToFloat64:
   1475       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
   1476       break;
   1477     case kArm64Uint64ToFloat32:
   1478       __ Ucvtf(i.OutputDoubleRegister().S(), i.InputRegister64(0));
   1479       break;
   1480     case kArm64Uint64ToFloat64:
   1481       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister64(0));
   1482       break;
   1483     case kArm64Float64ExtractLowWord32:
   1484       __ Fmov(i.OutputRegister32(), i.InputFloat32Register(0));
   1485       break;
   1486     case kArm64Float64ExtractHighWord32:
   1487       // TODO(arm64): This should use MOV (to general) when NEON is supported.
   1488       __ Fmov(i.OutputRegister(), i.InputFloat64Register(0));
   1489       __ Lsr(i.OutputRegister(), i.OutputRegister(), 32);
   1490       break;
   1491     case kArm64Float64InsertLowWord32: {
   1492       // TODO(arm64): This should use MOV (from general) when NEON is supported.
   1493       UseScratchRegisterScope scope(masm());
   1494       Register tmp = scope.AcquireX();
   1495       __ Fmov(tmp, i.InputFloat64Register(0));
   1496       __ Bfi(tmp, i.InputRegister(1), 0, 32);
   1497       __ Fmov(i.OutputFloat64Register(), tmp);
   1498       break;
   1499     }
   1500     case kArm64Float64InsertHighWord32: {
   1501       // TODO(arm64): This should use MOV (from general) when NEON is supported.
   1502       UseScratchRegisterScope scope(masm());
   1503       Register tmp = scope.AcquireX();
   1504       __ Fmov(tmp.W(), i.InputFloat32Register(0));
   1505       __ Bfi(tmp, i.InputRegister(1), 32, 32);
   1506       __ Fmov(i.OutputFloat64Register(), tmp);
   1507       break;
   1508     }
   1509     case kArm64Float64MoveU64:
   1510       __ Fmov(i.OutputFloat64Register(), i.InputRegister(0));
   1511       break;
   1512     case kArm64Float64SilenceNaN:
   1513       __ CanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1514       break;
   1515     case kArm64U64MoveFloat64:
   1516       __ Fmov(i.OutputRegister(), i.InputDoubleRegister(0));
   1517       break;
   1518     case kArm64Ldrb:
   1519       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
   1520       break;
   1521     case kArm64Ldrsb:
   1522       __ Ldrsb(i.OutputRegister(), i.MemoryOperand());
   1523       break;
   1524     case kArm64Strb:
   1525       __ Strb(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
   1526       break;
   1527     case kArm64Ldrh:
   1528       __ Ldrh(i.OutputRegister(), i.MemoryOperand());
   1529       break;
   1530     case kArm64Ldrsh:
   1531       __ Ldrsh(i.OutputRegister(), i.MemoryOperand());
   1532       break;
   1533     case kArm64Strh:
   1534       __ Strh(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
   1535       break;
   1536     case kArm64Ldrsw:
   1537       __ Ldrsw(i.OutputRegister(), i.MemoryOperand());
   1538       break;
   1539     case kArm64LdrW:
   1540       __ Ldr(i.OutputRegister32(), i.MemoryOperand());
   1541       break;
   1542     case kArm64StrW:
   1543       __ Str(i.InputOrZeroRegister32(0), i.MemoryOperand(1));
   1544       break;
   1545     case kArm64Ldr:
   1546       __ Ldr(i.OutputRegister(), i.MemoryOperand());
   1547       break;
   1548     case kArm64Str:
   1549       __ Str(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
   1550       break;
   1551     case kArm64LdrS:
   1552       __ Ldr(i.OutputDoubleRegister().S(), i.MemoryOperand());
   1553       break;
   1554     case kArm64StrS:
   1555       __ Str(i.InputFloat32OrZeroRegister(0), i.MemoryOperand(1));
   1556       break;
   1557     case kArm64LdrD:
   1558       __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
   1559       break;
   1560     case kArm64StrD:
   1561       __ Str(i.InputFloat64OrZeroRegister(0), i.MemoryOperand(1));
   1562       break;
   1563     case kCheckedLoadInt8:
   1564       ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrsb);
   1565       break;
   1566     case kCheckedLoadUint8:
   1567       ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrb);
   1568       break;
   1569     case kCheckedLoadInt16:
   1570       ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrsh);
   1571       break;
   1572     case kCheckedLoadUint16:
   1573       ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrh);
   1574       break;
   1575     case kCheckedLoadWord32:
   1576       ASSEMBLE_CHECKED_LOAD_INTEGER(Ldr);
   1577       break;
   1578     case kCheckedLoadWord64:
   1579       ASSEMBLE_CHECKED_LOAD_INTEGER_64(Ldr);
   1580       break;
   1581     case kCheckedLoadFloat32:
   1582       ASSEMBLE_CHECKED_LOAD_FLOAT(32);
   1583       break;
   1584     case kCheckedLoadFloat64:
   1585       ASSEMBLE_CHECKED_LOAD_FLOAT(64);
   1586       break;
   1587     case kCheckedStoreWord8:
   1588       ASSEMBLE_CHECKED_STORE_INTEGER(Strb);
   1589       break;
   1590     case kCheckedStoreWord16:
   1591       ASSEMBLE_CHECKED_STORE_INTEGER(Strh);
   1592       break;
   1593     case kCheckedStoreWord32:
   1594       ASSEMBLE_CHECKED_STORE_INTEGER(Str);
   1595       break;
   1596     case kCheckedStoreWord64:
   1597       ASSEMBLE_CHECKED_STORE_INTEGER_64(Str);
   1598       break;
   1599     case kCheckedStoreFloat32:
   1600       ASSEMBLE_CHECKED_STORE_FLOAT(32);
   1601       break;
   1602     case kCheckedStoreFloat64:
   1603       ASSEMBLE_CHECKED_STORE_FLOAT(64);
   1604       break;
   1605     case kAtomicLoadInt8:
   1606       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldrsb);
   1607       break;
   1608     case kAtomicLoadUint8:
   1609       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldrb);
   1610       break;
   1611     case kAtomicLoadInt16:
   1612       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldrsh);
   1613       break;
   1614     case kAtomicLoadUint16:
   1615       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldrh);
   1616       break;
   1617     case kAtomicLoadWord32:
   1618       __ Ldr(i.OutputRegister32(),
   1619              MemOperand(i.InputRegister(0), i.InputRegister(1)));
   1620       __ Dmb(InnerShareable, BarrierAll);
   1621       break;
   1622     case kAtomicStoreWord8:
   1623       ASSEMBLE_ATOMIC_STORE_INTEGER(Strb);
   1624       break;
   1625     case kAtomicStoreWord16:
   1626       ASSEMBLE_ATOMIC_STORE_INTEGER(Strh);
   1627       break;
   1628     case kAtomicStoreWord32:
   1629       __ Dmb(InnerShareable, BarrierAll);
   1630       __ Str(i.InputRegister32(2),
   1631              MemOperand(i.InputRegister(0), i.InputRegister(1)));
   1632       __ Dmb(InnerShareable, BarrierAll);
   1633       break;
   1634   }
   1635   return kSuccess;
   1636 }  // NOLINT(readability/fn_size)
   1637 
   1638 
   1639 // Assemble branches after this instruction.
   1640 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   1641   Arm64OperandConverter i(this, instr);
   1642   Label* tlabel = branch->true_label;
   1643   Label* flabel = branch->false_label;
   1644   FlagsCondition condition = branch->condition;
   1645   ArchOpcode opcode = instr->arch_opcode();
   1646 
   1647   if (opcode == kArm64CompareAndBranch32) {
   1648     switch (condition) {
   1649       case kEqual:
   1650         __ Cbz(i.InputRegister32(0), tlabel);
   1651         break;
   1652       case kNotEqual:
   1653         __ Cbnz(i.InputRegister32(0), tlabel);
   1654         break;
   1655       default:
   1656         UNREACHABLE();
   1657     }
   1658   } else if (opcode == kArm64CompareAndBranch) {
   1659     switch (condition) {
   1660       case kEqual:
   1661         __ Cbz(i.InputRegister64(0), tlabel);
   1662         break;
   1663       case kNotEqual:
   1664         __ Cbnz(i.InputRegister64(0), tlabel);
   1665         break;
   1666       default:
   1667         UNREACHABLE();
   1668     }
   1669   } else if (opcode == kArm64TestAndBranch32) {
   1670     switch (condition) {
   1671       case kEqual:
   1672         __ Tbz(i.InputRegister32(0), i.InputInt5(1), tlabel);
   1673         break;
   1674       case kNotEqual:
   1675         __ Tbnz(i.InputRegister32(0), i.InputInt5(1), tlabel);
   1676         break;
   1677       default:
   1678         UNREACHABLE();
   1679     }
   1680   } else if (opcode == kArm64TestAndBranch) {
   1681     switch (condition) {
   1682       case kEqual:
   1683         __ Tbz(i.InputRegister64(0), i.InputInt6(1), tlabel);
   1684         break;
   1685       case kNotEqual:
   1686         __ Tbnz(i.InputRegister64(0), i.InputInt6(1), tlabel);
   1687         break;
   1688       default:
   1689         UNREACHABLE();
   1690     }
   1691   } else {
   1692     Condition cc = FlagsConditionToCondition(condition);
   1693     __ B(cc, tlabel);
   1694   }
   1695   if (!branch->fallthru) __ B(flabel);  // no fallthru to flabel.
   1696 }
   1697 
   1698 
   1699 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   1700   if (!IsNextInAssemblyOrder(target)) __ B(GetLabel(target));
   1701 }
   1702 
   1703 void CodeGenerator::AssembleArchTrap(Instruction* instr,
   1704                                      FlagsCondition condition) {
   1705   class OutOfLineTrap final : public OutOfLineCode {
   1706    public:
   1707     OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
   1708         : OutOfLineCode(gen),
   1709           frame_elided_(frame_elided),
   1710           instr_(instr),
   1711           gen_(gen) {}
   1712     void Generate() final {
   1713       Arm64OperandConverter i(gen_, instr_);
   1714       Builtins::Name trap_id =
   1715           static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
   1716       bool old_has_frame = __ has_frame();
   1717       if (frame_elided_) {
   1718         __ set_has_frame(true);
   1719         __ EnterFrame(StackFrame::WASM_COMPILED);
   1720       }
   1721       GenerateCallToTrap(trap_id);
   1722       if (frame_elided_) {
   1723         __ set_has_frame(old_has_frame);
   1724       }
   1725     }
   1726 
   1727    private:
   1728     void GenerateCallToTrap(Builtins::Name trap_id) {
   1729       if (trap_id == Builtins::builtin_count) {
   1730         // We cannot test calls to the runtime in cctest/test-run-wasm.
   1731         // Therefore we emit a call to C here instead of a call to the runtime.
   1732         __ CallCFunction(
   1733             ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
   1734             0);
   1735         __ LeaveFrame(StackFrame::WASM_COMPILED);
   1736         __ Ret();
   1737       } else {
   1738         DCHECK(csp.Is(__ StackPointer()));
   1739         // Initialize the jssp because it is required for the runtime call.
   1740         __ Mov(jssp, csp);
   1741         gen_->AssembleSourcePosition(instr_);
   1742         __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()),
   1743                 RelocInfo::CODE_TARGET);
   1744         ReferenceMap* reference_map =
   1745             new (gen_->zone()) ReferenceMap(gen_->zone());
   1746         gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
   1747                               Safepoint::kNoLazyDeopt);
   1748         if (FLAG_debug_code) {
   1749           // The trap code should never return.
   1750           __ Brk(0);
   1751         }
   1752       }
   1753     }
   1754     bool frame_elided_;
   1755     Instruction* instr_;
   1756     CodeGenerator* gen_;
   1757   };
   1758   bool frame_elided = !frame_access_state()->has_frame();
   1759   auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
   1760   Label* tlabel = ool->entry();
   1761   Condition cc = FlagsConditionToCondition(condition);
   1762   __ B(cc, tlabel);
   1763 }
   1764 
   1765 // Assemble boolean materializations after this instruction.
   1766 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   1767                                         FlagsCondition condition) {
   1768   Arm64OperandConverter i(this, instr);
   1769 
   1770   // Materialize a full 64-bit 1 or 0 value. The result register is always the
   1771   // last output of the instruction.
   1772   DCHECK_NE(0u, instr->OutputCount());
   1773   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   1774   Condition cc = FlagsConditionToCondition(condition);
   1775   __ Cset(reg, cc);
   1776 }
   1777 
   1778 
   1779 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   1780   Arm64OperandConverter i(this, instr);
   1781   Register input = i.InputRegister32(0);
   1782   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   1783     __ Cmp(input, i.InputInt32(index + 0));
   1784     __ B(eq, GetLabel(i.InputRpo(index + 1)));
   1785   }
   1786   AssembleArchJump(i.InputRpo(1));
   1787 }
   1788 
   1789 
   1790 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   1791   Arm64OperandConverter i(this, instr);
   1792   UseScratchRegisterScope scope(masm());
   1793   Register input = i.InputRegister32(0);
   1794   Register temp = scope.AcquireX();
   1795   size_t const case_count = instr->InputCount() - 2;
   1796   Label table;
   1797   __ Cmp(input, case_count);
   1798   __ B(hs, GetLabel(i.InputRpo(1)));
   1799   __ Adr(temp, &table);
   1800   __ Add(temp, temp, Operand(input, UXTW, 2));
   1801   __ Br(temp);
   1802   __ StartBlockPools();
   1803   __ Bind(&table);
   1804   for (size_t index = 0; index < case_count; ++index) {
   1805     __ B(GetLabel(i.InputRpo(index + 2)));
   1806   }
   1807   __ EndBlockPools();
   1808 }
   1809 
   1810 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
   1811     int deoptimization_id, SourcePosition pos) {
   1812   DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
   1813   DeoptimizeReason deoptimization_reason =
   1814       GetDeoptimizationReason(deoptimization_id);
   1815   Deoptimizer::BailoutType bailout_type =
   1816       deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
   1817                                                    : Deoptimizer::EAGER;
   1818   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   1819       isolate(), deoptimization_id, bailout_type);
   1820   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
   1821   __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
   1822   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   1823   return kSuccess;
   1824 }
   1825 
   1826 void CodeGenerator::FinishFrame(Frame* frame) {
   1827   frame->AlignFrame(16);
   1828   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1829 
   1830   if (descriptor->UseNativeStack() || descriptor->IsCFunctionCall()) {
   1831     __ SetStackPointer(csp);
   1832   } else {
   1833     __ SetStackPointer(jssp);
   1834   }
   1835 
   1836   // Save FP registers.
   1837   CPURegList saves_fp = CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
   1838                                    descriptor->CalleeSavedFPRegisters());
   1839   int saved_count = saves_fp.Count();
   1840   if (saved_count != 0) {
   1841     DCHECK(saves_fp.list() == CPURegList::GetCalleeSavedFP().list());
   1842     frame->AllocateSavedCalleeRegisterSlots(saved_count *
   1843                                             (kDoubleSize / kPointerSize));
   1844   }
   1845 
   1846   CPURegList saves = CPURegList(CPURegister::kRegister, kXRegSizeInBits,
   1847                                 descriptor->CalleeSavedRegisters());
   1848   saved_count = saves.Count();
   1849   if (saved_count != 0) {
   1850     frame->AllocateSavedCalleeRegisterSlots(saved_count);
   1851   }
   1852 }
   1853 
   1854 void CodeGenerator::AssembleConstructFrame() {
   1855   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1856   if (descriptor->UseNativeStack()) {
   1857     __ AssertCspAligned();
   1858   }
   1859 
   1860   int fixed_frame_size = descriptor->CalculateFixedFrameSize();
   1861   int shrink_slots =
   1862       frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
   1863 
   1864   if (frame_access_state()->has_frame()) {
   1865     // Link the frame
   1866     if (descriptor->IsJSFunctionCall()) {
   1867       DCHECK(!descriptor->UseNativeStack());
   1868       __ Prologue(this->info()->GeneratePreagedPrologue());
   1869     } else {
   1870       __ Push(lr, fp);
   1871       __ Mov(fp, masm_.StackPointer());
   1872     }
   1873     if (!info()->GeneratePreagedPrologue()) {
   1874       unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
   1875     }
   1876 
   1877     // Create OSR entry if applicable
   1878     if (info()->is_osr()) {
   1879       // TurboFan OSR-compiled functions cannot be entered directly.
   1880       __ Abort(kShouldNotDirectlyEnterOsrFunction);
   1881 
   1882       // Unoptimized code jumps directly to this entrypoint while the
   1883       // unoptimized
   1884       // frame is still on the stack. Optimized code uses OSR values directly
   1885       // from
   1886       // the unoptimized frame. Thus, all that needs to be done is to allocate
   1887       // the
   1888       // remaining stack slots.
   1889       if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   1890       osr_pc_offset_ = __ pc_offset();
   1891       shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
   1892     }
   1893     // Build remainder of frame, including accounting for and filling-in
   1894     // frame-specific header information, e.g. claiming the extra slot that
   1895     // other platforms explicitly push for STUB frames and frames recording
   1896     // their argument count.
   1897     __ Claim(shrink_slots + (fixed_frame_size & 1));
   1898     if (descriptor->PushArgumentCount()) {
   1899       __ Str(kJavaScriptCallArgCountRegister,
   1900              MemOperand(fp, OptimizedBuiltinFrameConstants::kArgCOffset));
   1901     }
   1902     bool is_stub_frame =
   1903         !descriptor->IsJSFunctionCall() && !descriptor->IsCFunctionCall();
   1904     if (is_stub_frame) {
   1905       UseScratchRegisterScope temps(masm());
   1906       Register temp = temps.AcquireX();
   1907       __ Mov(temp, StackFrame::TypeToMarker(info()->GetOutputStackFrameType()));
   1908       __ Str(temp, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset));
   1909     }
   1910   }
   1911 
   1912   // Save FP registers.
   1913   CPURegList saves_fp = CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
   1914                                    descriptor->CalleeSavedFPRegisters());
   1915   int saved_count = saves_fp.Count();
   1916   if (saved_count != 0) {
   1917     DCHECK(saves_fp.list() == CPURegList::GetCalleeSavedFP().list());
   1918     __ PushCPURegList(saves_fp);
   1919   }
   1920   // Save registers.
   1921   // TODO(palfia): TF save list is not in sync with
   1922   // CPURegList::GetCalleeSaved(): x30 is missing.
   1923   // DCHECK(saves.list() == CPURegList::GetCalleeSaved().list());
   1924   CPURegList saves = CPURegList(CPURegister::kRegister, kXRegSizeInBits,
   1925                                 descriptor->CalleeSavedRegisters());
   1926   saved_count = saves.Count();
   1927   if (saved_count != 0) {
   1928     __ PushCPURegList(saves);
   1929   }
   1930 }
   1931 
   1932 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
   1933   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1934 
   1935   // Restore registers.
   1936   CPURegList saves = CPURegList(CPURegister::kRegister, kXRegSizeInBits,
   1937                                 descriptor->CalleeSavedRegisters());
   1938   if (saves.Count() != 0) {
   1939     __ PopCPURegList(saves);
   1940   }
   1941 
   1942   // Restore fp registers.
   1943   CPURegList saves_fp = CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
   1944                                    descriptor->CalleeSavedFPRegisters());
   1945   if (saves_fp.Count() != 0) {
   1946     __ PopCPURegList(saves_fp);
   1947   }
   1948 
   1949   unwinding_info_writer_.MarkBlockWillExit();
   1950 
   1951   Arm64OperandConverter g(this, nullptr);
   1952   int pop_count = static_cast<int>(descriptor->StackParameterCount());
   1953   if (descriptor->IsCFunctionCall()) {
   1954     AssembleDeconstructFrame();
   1955   } else if (frame_access_state()->has_frame()) {
   1956     // Canonicalize JSFunction return sites for now unless they have an variable
   1957     // number of stack slot pops.
   1958     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
   1959       if (return_label_.is_bound()) {
   1960         __ B(&return_label_);
   1961         return;
   1962       } else {
   1963         __ Bind(&return_label_);
   1964         AssembleDeconstructFrame();
   1965         if (descriptor->UseNativeStack()) {
   1966           pop_count += (pop_count & 1);  // align
   1967         }
   1968       }
   1969     } else {
   1970       AssembleDeconstructFrame();
   1971       if (descriptor->UseNativeStack()) {
   1972         pop_count += (pop_count & 1);  // align
   1973       }
   1974     }
   1975   } else if (descriptor->UseNativeStack()) {
   1976     pop_count += (pop_count & 1);  // align
   1977   }
   1978 
   1979   if (pop->IsImmediate()) {
   1980     DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
   1981     pop_count += g.ToConstant(pop).ToInt32();
   1982     __ Drop(pop_count);
   1983   } else {
   1984     Register pop_reg = g.ToRegister(pop);
   1985     __ Add(pop_reg, pop_reg, pop_count);
   1986     __ Drop(pop_reg);
   1987   }
   1988 
   1989   if (descriptor->UseNativeStack()) {
   1990     __ AssertCspAligned();
   1991   }
   1992   __ Ret();
   1993 }
   1994 
   1995 
   1996 void CodeGenerator::AssembleMove(InstructionOperand* source,
   1997                                  InstructionOperand* destination) {
   1998   Arm64OperandConverter g(this, nullptr);
   1999   // Dispatch on the source and destination operand kinds.  Not all
   2000   // combinations are possible.
   2001   if (source->IsRegister()) {
   2002     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2003     Register src = g.ToRegister(source);
   2004     if (destination->IsRegister()) {
   2005       __ Mov(g.ToRegister(destination), src);
   2006     } else {
   2007       __ Str(src, g.ToMemOperand(destination, masm()));
   2008     }
   2009   } else if (source->IsStackSlot()) {
   2010     MemOperand src = g.ToMemOperand(source, masm());
   2011     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2012     if (destination->IsRegister()) {
   2013       __ Ldr(g.ToRegister(destination), src);
   2014     } else {
   2015       UseScratchRegisterScope scope(masm());
   2016       Register temp = scope.AcquireX();
   2017       __ Ldr(temp, src);
   2018       __ Str(temp, g.ToMemOperand(destination, masm()));
   2019     }
   2020   } else if (source->IsConstant()) {
   2021     Constant src = g.ToConstant(ConstantOperand::cast(source));
   2022     if (destination->IsRegister() || destination->IsStackSlot()) {
   2023       UseScratchRegisterScope scope(masm());
   2024       Register dst = destination->IsRegister() ? g.ToRegister(destination)
   2025                                                : scope.AcquireX();
   2026       if (src.type() == Constant::kHeapObject) {
   2027         Handle<HeapObject> src_object = src.ToHeapObject();
   2028         Heap::RootListIndex index;
   2029         if (IsMaterializableFromRoot(src_object, &index)) {
   2030           __ LoadRoot(dst, index);
   2031         } else {
   2032           __ LoadObject(dst, src_object);
   2033         }
   2034       } else {
   2035         __ Mov(dst, g.ToImmediate(source));
   2036       }
   2037       if (destination->IsStackSlot()) {
   2038         __ Str(dst, g.ToMemOperand(destination, masm()));
   2039       }
   2040     } else if (src.type() == Constant::kFloat32) {
   2041       if (destination->IsFPRegister()) {
   2042         FPRegister dst = g.ToDoubleRegister(destination).S();
   2043         __ Fmov(dst, src.ToFloat32());
   2044       } else {
   2045         DCHECK(destination->IsFPStackSlot());
   2046         if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
   2047           __ Str(wzr, g.ToMemOperand(destination, masm()));
   2048         } else {
   2049           UseScratchRegisterScope scope(masm());
   2050           FPRegister temp = scope.AcquireS();
   2051           __ Fmov(temp, src.ToFloat32());
   2052           __ Str(temp, g.ToMemOperand(destination, masm()));
   2053         }
   2054       }
   2055     } else {
   2056       DCHECK_EQ(Constant::kFloat64, src.type());
   2057       if (destination->IsFPRegister()) {
   2058         FPRegister dst = g.ToDoubleRegister(destination);
   2059         __ Fmov(dst, src.ToFloat64());
   2060       } else {
   2061         DCHECK(destination->IsFPStackSlot());
   2062         if (bit_cast<int64_t>(src.ToFloat64()) == 0) {
   2063           __ Str(xzr, g.ToMemOperand(destination, masm()));
   2064         } else {
   2065           UseScratchRegisterScope scope(masm());
   2066           FPRegister temp = scope.AcquireD();
   2067           __ Fmov(temp, src.ToFloat64());
   2068           __ Str(temp, g.ToMemOperand(destination, masm()));
   2069         }
   2070       }
   2071     }
   2072   } else if (source->IsFPRegister()) {
   2073     FPRegister src = g.ToDoubleRegister(source);
   2074     if (destination->IsFPRegister()) {
   2075       FPRegister dst = g.ToDoubleRegister(destination);
   2076       __ Fmov(dst, src);
   2077     } else {
   2078       DCHECK(destination->IsFPStackSlot());
   2079       __ Str(src, g.ToMemOperand(destination, masm()));
   2080     }
   2081   } else if (source->IsFPStackSlot()) {
   2082     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
   2083     MemOperand src = g.ToMemOperand(source, masm());
   2084     if (destination->IsFPRegister()) {
   2085       __ Ldr(g.ToDoubleRegister(destination), src);
   2086     } else {
   2087       UseScratchRegisterScope scope(masm());
   2088       FPRegister temp = scope.AcquireD();
   2089       __ Ldr(temp, src);
   2090       __ Str(temp, g.ToMemOperand(destination, masm()));
   2091     }
   2092   } else {
   2093     UNREACHABLE();
   2094   }
   2095 }
   2096 
   2097 
   2098 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   2099                                  InstructionOperand* destination) {
   2100   Arm64OperandConverter g(this, nullptr);
   2101   // Dispatch on the source and destination operand kinds.  Not all
   2102   // combinations are possible.
   2103   if (source->IsRegister()) {
   2104     // Register-register.
   2105     UseScratchRegisterScope scope(masm());
   2106     Register temp = scope.AcquireX();
   2107     Register src = g.ToRegister(source);
   2108     if (destination->IsRegister()) {
   2109       Register dst = g.ToRegister(destination);
   2110       __ Mov(temp, src);
   2111       __ Mov(src, dst);
   2112       __ Mov(dst, temp);
   2113     } else {
   2114       DCHECK(destination->IsStackSlot());
   2115       MemOperand dst = g.ToMemOperand(destination, masm());
   2116       __ Mov(temp, src);
   2117       __ Ldr(src, dst);
   2118       __ Str(temp, dst);
   2119     }
   2120   } else if (source->IsStackSlot() || source->IsFPStackSlot()) {
   2121     UseScratchRegisterScope scope(masm());
   2122     DoubleRegister temp_0 = scope.AcquireD();
   2123     DoubleRegister temp_1 = scope.AcquireD();
   2124     MemOperand src = g.ToMemOperand(source, masm());
   2125     MemOperand dst = g.ToMemOperand(destination, masm());
   2126     __ Ldr(temp_0, src);
   2127     __ Ldr(temp_1, dst);
   2128     __ Str(temp_0, dst);
   2129     __ Str(temp_1, src);
   2130   } else if (source->IsFPRegister()) {
   2131     UseScratchRegisterScope scope(masm());
   2132     FPRegister temp = scope.AcquireD();
   2133     FPRegister src = g.ToDoubleRegister(source);
   2134     if (destination->IsFPRegister()) {
   2135       FPRegister dst = g.ToDoubleRegister(destination);
   2136       __ Fmov(temp, src);
   2137       __ Fmov(src, dst);
   2138       __ Fmov(dst, temp);
   2139     } else {
   2140       DCHECK(destination->IsFPStackSlot());
   2141       MemOperand dst = g.ToMemOperand(destination, masm());
   2142       __ Fmov(temp, src);
   2143       __ Ldr(src, dst);
   2144       __ Str(temp, dst);
   2145     }
   2146   } else {
   2147     // No other combinations are possible.
   2148     UNREACHABLE();
   2149   }
   2150 }
   2151 
   2152 
   2153 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   2154   // On 64-bit ARM we emit the jump tables inline.
   2155   UNREACHABLE();
   2156 }
   2157 
   2158 
   2159 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   2160   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   2161     return;
   2162   }
   2163 
   2164   int space_needed = Deoptimizer::patch_size();
   2165   // Ensure that we have enough space after the previous lazy-bailout
   2166   // instruction for patching the code here.
   2167   intptr_t current_pc = masm()->pc_offset();
   2168 
   2169   if (current_pc < (last_lazy_deopt_pc_ + space_needed)) {
   2170     intptr_t padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   2171     DCHECK((padding_size % kInstructionSize) == 0);
   2172     InstructionAccurateScope instruction_accurate(
   2173         masm(), padding_size / kInstructionSize);
   2174 
   2175     while (padding_size > 0) {
   2176       __ nop();
   2177       padding_size -= kInstructionSize;
   2178     }
   2179   }
   2180 }
   2181 
   2182 #undef __
   2183 
   2184 }  // namespace compiler
   2185 }  // namespace internal
   2186 }  // namespace v8
   2187