Home | History | Annotate | Download | only in x64
      1 // Copyright 2013 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 <limits>
      8 
      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 #include "src/heap/heap-inl.h"
     15 #include "src/wasm/wasm-module.h"
     16 #include "src/x64/assembler-x64.h"
     17 #include "src/x64/macro-assembler-x64.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 namespace compiler {
     22 
     23 #define __ masm()->
     24 
     25 // Adds X64 specific methods for decoding operands.
     26 class X64OperandConverter : public InstructionOperandConverter {
     27  public:
     28   X64OperandConverter(CodeGenerator* gen, Instruction* instr)
     29       : InstructionOperandConverter(gen, instr) {}
     30 
     31   Immediate InputImmediate(size_t index) {
     32     return ToImmediate(instr_->InputAt(index));
     33   }
     34 
     35   Operand InputOperand(size_t index, int extra = 0) {
     36     return ToOperand(instr_->InputAt(index), extra);
     37   }
     38 
     39   Operand OutputOperand() { return ToOperand(instr_->Output()); }
     40 
     41   Immediate ToImmediate(InstructionOperand* operand) {
     42     Constant constant = ToConstant(operand);
     43     if (constant.type() == Constant::kFloat64) {
     44       DCHECK_EQ(0, bit_cast<int64_t>(constant.ToFloat64()));
     45       return Immediate(0);
     46     }
     47     if (RelocInfo::IsWasmReference(constant.rmode())) {
     48       return Immediate(constant.ToInt32(), constant.rmode());
     49     }
     50     return Immediate(constant.ToInt32());
     51   }
     52 
     53   Operand ToOperand(InstructionOperand* op, int extra = 0) {
     54     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
     55     return SlotToOperand(AllocatedOperand::cast(op)->index(), extra);
     56   }
     57 
     58   Operand SlotToOperand(int slot_index, int extra = 0) {
     59     FrameOffset offset = frame_access_state()->GetFrameOffset(slot_index);
     60     return Operand(offset.from_stack_pointer() ? rsp : rbp,
     61                    offset.offset() + extra);
     62   }
     63 
     64   static size_t NextOffset(size_t* offset) {
     65     size_t i = *offset;
     66     (*offset)++;
     67     return i;
     68   }
     69 
     70   static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
     71     STATIC_ASSERT(0 == static_cast<int>(times_1));
     72     STATIC_ASSERT(1 == static_cast<int>(times_2));
     73     STATIC_ASSERT(2 == static_cast<int>(times_4));
     74     STATIC_ASSERT(3 == static_cast<int>(times_8));
     75     int scale = static_cast<int>(mode - one);
     76     DCHECK(scale >= 0 && scale < 4);
     77     return static_cast<ScaleFactor>(scale);
     78   }
     79 
     80   Operand MemoryOperand(size_t* offset) {
     81     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
     82     switch (mode) {
     83       case kMode_MR: {
     84         Register base = InputRegister(NextOffset(offset));
     85         int32_t disp = 0;
     86         return Operand(base, disp);
     87       }
     88       case kMode_MRI: {
     89         Register base = InputRegister(NextOffset(offset));
     90         int32_t disp = InputInt32(NextOffset(offset));
     91         return Operand(base, disp);
     92       }
     93       case kMode_MR1:
     94       case kMode_MR2:
     95       case kMode_MR4:
     96       case kMode_MR8: {
     97         Register base = InputRegister(NextOffset(offset));
     98         Register index = InputRegister(NextOffset(offset));
     99         ScaleFactor scale = ScaleFor(kMode_MR1, mode);
    100         int32_t disp = 0;
    101         return Operand(base, index, scale, disp);
    102       }
    103       case kMode_MR1I:
    104       case kMode_MR2I:
    105       case kMode_MR4I:
    106       case kMode_MR8I: {
    107         Register base = InputRegister(NextOffset(offset));
    108         Register index = InputRegister(NextOffset(offset));
    109         ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
    110         int32_t disp = InputInt32(NextOffset(offset));
    111         return Operand(base, index, scale, disp);
    112       }
    113       case kMode_M1: {
    114         Register base = InputRegister(NextOffset(offset));
    115         int32_t disp = 0;
    116         return Operand(base, disp);
    117       }
    118       case kMode_M2:
    119         UNREACHABLE();  // Should use kModeMR with more compact encoding instead
    120         return Operand(no_reg, 0);
    121       case kMode_M4:
    122       case kMode_M8: {
    123         Register index = InputRegister(NextOffset(offset));
    124         ScaleFactor scale = ScaleFor(kMode_M1, mode);
    125         int32_t disp = 0;
    126         return Operand(index, scale, disp);
    127       }
    128       case kMode_M1I:
    129       case kMode_M2I:
    130       case kMode_M4I:
    131       case kMode_M8I: {
    132         Register index = InputRegister(NextOffset(offset));
    133         ScaleFactor scale = ScaleFor(kMode_M1I, mode);
    134         int32_t disp = InputInt32(NextOffset(offset));
    135         return Operand(index, scale, disp);
    136       }
    137       case kMode_Root: {
    138         Register base = kRootRegister;
    139         int32_t disp = InputInt32(NextOffset(offset));
    140         return Operand(base, disp);
    141       }
    142       case kMode_None:
    143         UNREACHABLE();
    144         return Operand(no_reg, 0);
    145     }
    146     UNREACHABLE();
    147     return Operand(no_reg, 0);
    148   }
    149 
    150   Operand MemoryOperand(size_t first_input = 0) {
    151     return MemoryOperand(&first_input);
    152   }
    153 };
    154 
    155 
    156 namespace {
    157 
    158 bool HasImmediateInput(Instruction* instr, size_t index) {
    159   return instr->InputAt(index)->IsImmediate();
    160 }
    161 
    162 
    163 class OutOfLineLoadZero final : public OutOfLineCode {
    164  public:
    165   OutOfLineLoadZero(CodeGenerator* gen, Register result)
    166       : OutOfLineCode(gen), result_(result) {}
    167 
    168   void Generate() final { __ xorl(result_, result_); }
    169 
    170  private:
    171   Register const result_;
    172 };
    173 
    174 class OutOfLineLoadFloat32NaN final : public OutOfLineCode {
    175  public:
    176   OutOfLineLoadFloat32NaN(CodeGenerator* gen, XMMRegister result)
    177       : OutOfLineCode(gen), result_(result) {}
    178 
    179   void Generate() final {
    180     __ Xorps(result_, result_);
    181     __ Divss(result_, result_);
    182   }
    183 
    184  private:
    185   XMMRegister const result_;
    186 };
    187 
    188 class OutOfLineLoadFloat64NaN final : public OutOfLineCode {
    189  public:
    190   OutOfLineLoadFloat64NaN(CodeGenerator* gen, XMMRegister result)
    191       : OutOfLineCode(gen), result_(result) {}
    192 
    193   void Generate() final {
    194     __ Xorpd(result_, result_);
    195     __ Divsd(result_, result_);
    196   }
    197 
    198  private:
    199   XMMRegister const result_;
    200 };
    201 
    202 class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
    203  public:
    204   OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
    205                              XMMRegister input,
    206                              UnwindingInfoWriter* unwinding_info_writer)
    207       : OutOfLineCode(gen),
    208         result_(result),
    209         input_(input),
    210         unwinding_info_writer_(unwinding_info_writer) {}
    211 
    212   void Generate() final {
    213     __ subp(rsp, Immediate(kDoubleSize));
    214     unwinding_info_writer_->MaybeIncreaseBaseOffsetAt(__ pc_offset(),
    215                                                       kDoubleSize);
    216     __ Movsd(MemOperand(rsp, 0), input_);
    217     __ SlowTruncateToI(result_, rsp, 0);
    218     __ addp(rsp, Immediate(kDoubleSize));
    219     unwinding_info_writer_->MaybeIncreaseBaseOffsetAt(__ pc_offset(),
    220                                                       -kDoubleSize);
    221   }
    222 
    223  private:
    224   Register const result_;
    225   XMMRegister const input_;
    226   UnwindingInfoWriter* const unwinding_info_writer_;
    227 };
    228 
    229 
    230 class OutOfLineRecordWrite final : public OutOfLineCode {
    231  public:
    232   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
    233                        Register value, Register scratch0, Register scratch1,
    234                        RecordWriteMode mode)
    235       : OutOfLineCode(gen),
    236         object_(object),
    237         operand_(operand),
    238         value_(value),
    239         scratch0_(scratch0),
    240         scratch1_(scratch1),
    241         mode_(mode) {}
    242 
    243   void Generate() final {
    244     if (mode_ > RecordWriteMode::kValueIsPointer) {
    245       __ JumpIfSmi(value_, exit());
    246     }
    247     __ CheckPageFlag(value_, scratch0_,
    248                      MemoryChunk::kPointersToHereAreInterestingMask, zero,
    249                      exit());
    250     RememberedSetAction const remembered_set_action =
    251         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
    252                                              : OMIT_REMEMBERED_SET;
    253     SaveFPRegsMode const save_fp_mode =
    254         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    255     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    256                          remembered_set_action, save_fp_mode);
    257     __ leap(scratch1_, operand_);
    258     __ CallStub(&stub);
    259   }
    260 
    261  private:
    262   Register const object_;
    263   Operand const operand_;
    264   Register const value_;
    265   Register const scratch0_;
    266   Register const scratch1_;
    267   RecordWriteMode const mode_;
    268 };
    269 
    270 class WasmOutOfLineTrap final : public OutOfLineCode {
    271  public:
    272   WasmOutOfLineTrap(CodeGenerator* gen, int pc, bool frame_elided,
    273                     int32_t position, Instruction* instr)
    274       : OutOfLineCode(gen),
    275         gen_(gen),
    276         pc_(pc),
    277         frame_elided_(frame_elided),
    278         position_(position),
    279         instr_(instr) {}
    280 
    281   // TODO(eholk): Refactor this method to take the code generator as a
    282   // parameter.
    283   void Generate() final {
    284     __ RecordProtectedInstructionLanding(pc_);
    285 
    286     if (frame_elided_) {
    287       __ EnterFrame(StackFrame::WASM_COMPILED);
    288     }
    289 
    290     wasm::TrapReason trap_id = wasm::kTrapMemOutOfBounds;
    291     int trap_reason = wasm::WasmOpcodes::TrapReasonToMessageId(trap_id);
    292     __ Push(Smi::FromInt(trap_reason));
    293     __ Push(Smi::FromInt(position_));
    294     __ Move(rsi, gen_->isolate()->native_context());
    295     __ CallRuntime(Runtime::kThrowWasmError);
    296 
    297     if (instr_->reference_map() != nullptr) {
    298       gen_->RecordSafepoint(instr_->reference_map(), Safepoint::kSimple, 0,
    299                             Safepoint::kNoLazyDeopt);
    300     }
    301   }
    302 
    303  private:
    304   CodeGenerator* gen_;
    305   int pc_;
    306   bool frame_elided_;
    307   int32_t position_;
    308   Instruction* instr_;
    309 };
    310 
    311 void EmitOOLTrapIfNeeded(Zone* zone, CodeGenerator* codegen,
    312                          InstructionCode opcode, size_t input_count,
    313                          X64OperandConverter& i, int pc, Instruction* instr) {
    314   const X64MemoryProtection protection =
    315       static_cast<X64MemoryProtection>(MiscField::decode(opcode));
    316   if (protection == X64MemoryProtection::kProtected) {
    317     const bool frame_elided = !codegen->frame_access_state()->has_frame();
    318     const int32_t position = i.InputInt32(input_count - 1);
    319     new (zone) WasmOutOfLineTrap(codegen, pc, frame_elided, position, instr);
    320   }
    321 }
    322 }  // namespace
    323 
    324 
    325 #define ASSEMBLE_UNOP(asm_instr)         \
    326   do {                                   \
    327     if (instr->Output()->IsRegister()) { \
    328       __ asm_instr(i.OutputRegister());  \
    329     } else {                             \
    330       __ asm_instr(i.OutputOperand());   \
    331     }                                    \
    332   } while (0)
    333 
    334 
    335 #define ASSEMBLE_BINOP(asm_instr)                              \
    336   do {                                                         \
    337     if (HasImmediateInput(instr, 1)) {                         \
    338       if (instr->InputAt(0)->IsRegister()) {                   \
    339         __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
    340       } else {                                                 \
    341         __ asm_instr(i.InputOperand(0), i.InputImmediate(1));  \
    342       }                                                        \
    343     } else {                                                   \
    344       if (instr->InputAt(1)->IsRegister()) {                   \
    345         __ asm_instr(i.InputRegister(0), i.InputRegister(1));  \
    346       } else {                                                 \
    347         __ asm_instr(i.InputRegister(0), i.InputOperand(1));   \
    348       }                                                        \
    349     }                                                          \
    350   } while (0)
    351 
    352 #define ASSEMBLE_COMPARE(asm_instr)                                   \
    353   do {                                                                \
    354     if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
    355       size_t index = 0;                                               \
    356       Operand left = i.MemoryOperand(&index);                         \
    357       if (HasImmediateInput(instr, index)) {                          \
    358         __ asm_instr(left, i.InputImmediate(index));                  \
    359       } else {                                                        \
    360         __ asm_instr(left, i.InputRegister(index));                   \
    361       }                                                               \
    362     } else {                                                          \
    363       if (HasImmediateInput(instr, 1)) {                              \
    364         if (instr->InputAt(0)->IsRegister()) {                        \
    365           __ asm_instr(i.InputRegister(0), i.InputImmediate(1));      \
    366         } else {                                                      \
    367           __ asm_instr(i.InputOperand(0), i.InputImmediate(1));       \
    368         }                                                             \
    369       } else {                                                        \
    370         if (instr->InputAt(1)->IsRegister()) {                        \
    371           __ asm_instr(i.InputRegister(0), i.InputRegister(1));       \
    372         } else {                                                      \
    373           __ asm_instr(i.InputRegister(0), i.InputOperand(1));        \
    374         }                                                             \
    375       }                                                               \
    376     }                                                                 \
    377   } while (0)
    378 
    379 #define ASSEMBLE_MULT(asm_instr)                              \
    380   do {                                                        \
    381     if (HasImmediateInput(instr, 1)) {                        \
    382       if (instr->InputAt(0)->IsRegister()) {                  \
    383         __ asm_instr(i.OutputRegister(), i.InputRegister(0),  \
    384                      i.InputImmediate(1));                    \
    385       } else {                                                \
    386         __ asm_instr(i.OutputRegister(), i.InputOperand(0),   \
    387                      i.InputImmediate(1));                    \
    388       }                                                       \
    389     } else {                                                  \
    390       if (instr->InputAt(1)->IsRegister()) {                  \
    391         __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
    392       } else {                                                \
    393         __ asm_instr(i.OutputRegister(), i.InputOperand(1));  \
    394       }                                                       \
    395     }                                                         \
    396   } while (0)
    397 
    398 
    399 #define ASSEMBLE_SHIFT(asm_instr, width)                                   \
    400   do {                                                                     \
    401     if (HasImmediateInput(instr, 1)) {                                     \
    402       if (instr->Output()->IsRegister()) {                                 \
    403         __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
    404       } else {                                                             \
    405         __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1)));  \
    406       }                                                                    \
    407     } else {                                                               \
    408       if (instr->Output()->IsRegister()) {                                 \
    409         __ asm_instr##_cl(i.OutputRegister());                             \
    410       } else {                                                             \
    411         __ asm_instr##_cl(i.OutputOperand());                              \
    412       }                                                                    \
    413     }                                                                      \
    414   } while (0)
    415 
    416 
    417 #define ASSEMBLE_MOVX(asm_instr)                            \
    418   do {                                                      \
    419     if (instr->addressing_mode() != kMode_None) {           \
    420       __ asm_instr(i.OutputRegister(), i.MemoryOperand());  \
    421     } else if (instr->InputAt(0)->IsRegister()) {           \
    422       __ asm_instr(i.OutputRegister(), i.InputRegister(0)); \
    423     } else {                                                \
    424       __ asm_instr(i.OutputRegister(), i.InputOperand(0));  \
    425     }                                                       \
    426   } while (0)
    427 
    428 #define ASSEMBLE_SSE_BINOP(asm_instr)                                   \
    429   do {                                                                  \
    430     if (instr->InputAt(1)->IsFPRegister()) {                            \
    431       __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
    432     } else {                                                            \
    433       __ asm_instr(i.InputDoubleRegister(0), i.InputOperand(1));        \
    434     }                                                                   \
    435   } while (0)
    436 
    437 #define ASSEMBLE_SSE_UNOP(asm_instr)                                    \
    438   do {                                                                  \
    439     if (instr->InputAt(0)->IsFPRegister()) {                            \
    440       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
    441     } else {                                                            \
    442       __ asm_instr(i.OutputDoubleRegister(), i.InputOperand(0));        \
    443     }                                                                   \
    444   } while (0)
    445 
    446 #define ASSEMBLE_AVX_BINOP(asm_instr)                                  \
    447   do {                                                                 \
    448     CpuFeatureScope avx_scope(masm(), AVX);                            \
    449     if (instr->InputAt(1)->IsFPRegister()) {                           \
    450       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    451                    i.InputDoubleRegister(1));                          \
    452     } else {                                                           \
    453       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    454                    i.InputOperand(1));                                 \
    455     }                                                                  \
    456   } while (0)
    457 
    458 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, OutOfLineLoadNaN)             \
    459   do {                                                                       \
    460     auto result = i.OutputDoubleRegister();                                  \
    461     auto buffer = i.InputRegister(0);                                        \
    462     auto index1 = i.InputRegister(1);                                        \
    463     auto index2 = i.InputUint32(2);                                          \
    464     OutOfLineCode* ool;                                                      \
    465     if (instr->InputAt(3)->IsRegister()) {                                   \
    466       auto length = i.InputRegister(3);                                      \
    467       DCHECK_EQ(0u, index2);                                                 \
    468       __ cmpl(index1, length);                                               \
    469       ool = new (zone()) OutOfLineLoadNaN(this, result);                     \
    470     } else {                                                                 \
    471       auto length = i.InputUint32(3);                                        \
    472       RelocInfo::Mode rmode = i.ToConstant(instr->InputAt(3)).rmode();       \
    473       DCHECK_LE(index2, length);                                             \
    474       __ cmpl(index1, Immediate(length - index2, rmode));                    \
    475       class OutOfLineLoadFloat final : public OutOfLineCode {                \
    476        public:                                                               \
    477         OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result,           \
    478                            Register buffer, Register index1, int32_t index2, \
    479                            int32_t length, RelocInfo::Mode rmode)            \
    480             : OutOfLineCode(gen),                                            \
    481               result_(result),                                               \
    482               buffer_(buffer),                                               \
    483               index1_(index1),                                               \
    484               index2_(index2),                                               \
    485               length_(length),                                               \
    486               rmode_(rmode) {}                                               \
    487                                                                              \
    488         void Generate() final {                                              \
    489           __ leal(kScratchRegister, Operand(index1_, index2_));              \
    490           __ Pcmpeqd(result_, result_);                                      \
    491           __ cmpl(kScratchRegister, Immediate(length_, rmode_));             \
    492           __ j(above_equal, exit());                                         \
    493           __ asm_instr(result_,                                              \
    494                        Operand(buffer_, kScratchRegister, times_1, 0));      \
    495         }                                                                    \
    496                                                                              \
    497        private:                                                              \
    498         XMMRegister const result_;                                           \
    499         Register const buffer_;                                              \
    500         Register const index1_;                                              \
    501         int32_t const index2_;                                               \
    502         int32_t const length_;                                               \
    503         RelocInfo::Mode rmode_;                                              \
    504       };                                                                     \
    505       ool = new (zone()) OutOfLineLoadFloat(this, result, buffer, index1,    \
    506                                             index2, length, rmode);          \
    507     }                                                                        \
    508     __ j(above_equal, ool->entry());                                         \
    509     __ asm_instr(result, Operand(buffer, index1, times_1, index2));          \
    510     __ bind(ool->exit());                                                    \
    511   } while (false)
    512 
    513 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                               \
    514   do {                                                                         \
    515     auto result = i.OutputRegister();                                          \
    516     auto buffer = i.InputRegister(0);                                          \
    517     auto index1 = i.InputRegister(1);                                          \
    518     auto index2 = i.InputUint32(2);                                            \
    519     OutOfLineCode* ool;                                                        \
    520     if (instr->InputAt(3)->IsRegister()) {                                     \
    521       auto length = i.InputRegister(3);                                        \
    522       DCHECK_EQ(0u, index2);                                                   \
    523       __ cmpl(index1, length);                                                 \
    524       ool = new (zone()) OutOfLineLoadZero(this, result);                      \
    525     } else {                                                                   \
    526       auto length = i.InputUint32(3);                                          \
    527       RelocInfo::Mode rmode = i.ToConstant(instr->InputAt(3)).rmode();         \
    528       DCHECK_LE(index2, length);                                               \
    529       __ cmpl(index1, Immediate(length - index2, rmode));                      \
    530       class OutOfLineLoadInteger final : public OutOfLineCode {                \
    531        public:                                                                 \
    532         OutOfLineLoadInteger(CodeGenerator* gen, Register result,              \
    533                              Register buffer, Register index1, int32_t index2, \
    534                              int32_t length, RelocInfo::Mode rmode)            \
    535             : OutOfLineCode(gen),                                              \
    536               result_(result),                                                 \
    537               buffer_(buffer),                                                 \
    538               index1_(index1),                                                 \
    539               index2_(index2),                                                 \
    540               length_(length),                                                 \
    541               rmode_(rmode) {}                                                 \
    542                                                                                \
    543         void Generate() final {                                                \
    544           Label oob;                                                           \
    545           __ leal(kScratchRegister, Operand(index1_, index2_));                \
    546           __ cmpl(kScratchRegister, Immediate(length_, rmode_));               \
    547           __ j(above_equal, &oob, Label::kNear);                               \
    548           __ asm_instr(result_,                                                \
    549                        Operand(buffer_, kScratchRegister, times_1, 0));        \
    550           __ jmp(exit());                                                      \
    551           __ bind(&oob);                                                       \
    552           __ xorl(result_, result_);                                           \
    553         }                                                                      \
    554                                                                                \
    555        private:                                                                \
    556         Register const result_;                                                \
    557         Register const buffer_;                                                \
    558         Register const index1_;                                                \
    559         int32_t const index2_;                                                 \
    560         int32_t const length_;                                                 \
    561         RelocInfo::Mode const rmode_;                                          \
    562       };                                                                       \
    563       ool = new (zone()) OutOfLineLoadInteger(this, result, buffer, index1,    \
    564                                               index2, length, rmode);          \
    565     }                                                                          \
    566     __ j(above_equal, ool->entry());                                           \
    567     __ asm_instr(result, Operand(buffer, index1, times_1, index2));            \
    568     __ bind(ool->exit());                                                      \
    569   } while (false)
    570 
    571 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)                              \
    572   do {                                                                       \
    573     auto buffer = i.InputRegister(0);                                        \
    574     auto index1 = i.InputRegister(1);                                        \
    575     auto index2 = i.InputUint32(2);                                          \
    576     auto value = i.InputDoubleRegister(4);                                   \
    577     if (instr->InputAt(3)->IsRegister()) {                                   \
    578       auto length = i.InputRegister(3);                                      \
    579       DCHECK_EQ(0u, index2);                                                 \
    580       Label done;                                                            \
    581       __ cmpl(index1, length);                                               \
    582       __ j(above_equal, &done, Label::kNear);                                \
    583       __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
    584       __ bind(&done);                                                        \
    585     } else {                                                                 \
    586       auto length = i.InputUint32(3);                                        \
    587       RelocInfo::Mode rmode = i.ToConstant(instr->InputAt(3)).rmode();       \
    588       DCHECK_LE(index2, length);                                             \
    589       __ cmpl(index1, Immediate(length - index2, rmode));                    \
    590       class OutOfLineStoreFloat final : public OutOfLineCode {               \
    591        public:                                                               \
    592         OutOfLineStoreFloat(CodeGenerator* gen, Register buffer,             \
    593                             Register index1, int32_t index2, int32_t length, \
    594                             XMMRegister value, RelocInfo::Mode rmode)        \
    595             : OutOfLineCode(gen),                                            \
    596               buffer_(buffer),                                               \
    597               index1_(index1),                                               \
    598               index2_(index2),                                               \
    599               length_(length),                                               \
    600               value_(value),                                                 \
    601               rmode_(rmode) {}                                               \
    602                                                                              \
    603         void Generate() final {                                              \
    604           __ leal(kScratchRegister, Operand(index1_, index2_));              \
    605           __ cmpl(kScratchRegister, Immediate(length_, rmode_));             \
    606           __ j(above_equal, exit());                                         \
    607           __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),       \
    608                        value_);                                              \
    609         }                                                                    \
    610                                                                              \
    611        private:                                                              \
    612         Register const buffer_;                                              \
    613         Register const index1_;                                              \
    614         int32_t const index2_;                                               \
    615         int32_t const length_;                                               \
    616         XMMRegister const value_;                                            \
    617         RelocInfo::Mode rmode_;                                              \
    618       };                                                                     \
    619       auto ool = new (zone()) OutOfLineStoreFloat(                           \
    620           this, buffer, index1, index2, length, value, rmode);               \
    621       __ j(above_equal, ool->entry());                                       \
    622       __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
    623       __ bind(ool->exit());                                                  \
    624     }                                                                        \
    625   } while (false)
    626 
    627 #define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value)                  \
    628   do {                                                                         \
    629     auto buffer = i.InputRegister(0);                                          \
    630     auto index1 = i.InputRegister(1);                                          \
    631     auto index2 = i.InputUint32(2);                                            \
    632     if (instr->InputAt(3)->IsRegister()) {                                     \
    633       auto length = i.InputRegister(3);                                        \
    634       DCHECK_EQ(0u, index2);                                                   \
    635       Label done;                                                              \
    636       __ cmpl(index1, length);                                                 \
    637       __ j(above_equal, &done, Label::kNear);                                  \
    638       __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
    639       __ bind(&done);                                                          \
    640     } else {                                                                   \
    641       auto length = i.InputUint32(3);                                          \
    642       RelocInfo::Mode rmode = i.ToConstant(instr->InputAt(3)).rmode();         \
    643       DCHECK_LE(index2, length);                                               \
    644       __ cmpl(index1, Immediate(length - index2, rmode));                      \
    645       class OutOfLineStoreInteger final : public OutOfLineCode {               \
    646        public:                                                                 \
    647         OutOfLineStoreInteger(CodeGenerator* gen, Register buffer,             \
    648                               Register index1, int32_t index2, int32_t length, \
    649                               Value value, RelocInfo::Mode rmode)              \
    650             : OutOfLineCode(gen),                                              \
    651               buffer_(buffer),                                                 \
    652               index1_(index1),                                                 \
    653               index2_(index2),                                                 \
    654               length_(length),                                                 \
    655               value_(value),                                                   \
    656               rmode_(rmode) {}                                                 \
    657                                                                                \
    658         void Generate() final {                                                \
    659           __ leal(kScratchRegister, Operand(index1_, index2_));                \
    660           __ cmpl(kScratchRegister, Immediate(length_, rmode_));               \
    661           __ j(above_equal, exit());                                           \
    662           __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),         \
    663                        value_);                                                \
    664         }                                                                      \
    665                                                                                \
    666        private:                                                                \
    667         Register const buffer_;                                                \
    668         Register const index1_;                                                \
    669         int32_t const index2_;                                                 \
    670         int32_t const length_;                                                 \
    671         Value const value_;                                                    \
    672         RelocInfo::Mode rmode_;                                                \
    673       };                                                                       \
    674       auto ool = new (zone()) OutOfLineStoreInteger(                           \
    675           this, buffer, index1, index2, length, value, rmode);                 \
    676       __ j(above_equal, ool->entry());                                         \
    677       __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
    678       __ bind(ool->exit());                                                    \
    679     }                                                                          \
    680   } while (false)
    681 
    682 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                \
    683   do {                                                           \
    684     if (instr->InputAt(4)->IsRegister()) {                       \
    685       Register value = i.InputRegister(4);                       \
    686       ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Register);  \
    687     } else {                                                     \
    688       Immediate value = i.InputImmediate(4);                     \
    689       ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Immediate); \
    690     }                                                            \
    691   } while (false)
    692 
    693 #define ASSEMBLE_IEEE754_BINOP(name)                                          \
    694   do {                                                                        \
    695     __ PrepareCallCFunction(2);                                               \
    696     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    697                      2);                                                      \
    698   } while (false)
    699 
    700 #define ASSEMBLE_IEEE754_UNOP(name)                                           \
    701   do {                                                                        \
    702     __ PrepareCallCFunction(1);                                               \
    703     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    704                      1);                                                      \
    705   } while (false)
    706 
    707 void CodeGenerator::AssembleDeconstructFrame() {
    708   unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
    709   __ movq(rsp, rbp);
    710   __ popq(rbp);
    711 }
    712 
    713 void CodeGenerator::AssemblePrepareTailCall() {
    714   if (frame_access_state()->has_frame()) {
    715     __ movq(rbp, MemOperand(rbp, 0));
    716   }
    717   frame_access_state()->SetFrameAccessToSP();
    718 }
    719 
    720 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
    721                                                      Register scratch1,
    722                                                      Register scratch2,
    723                                                      Register scratch3) {
    724   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
    725   Label done;
    726 
    727   // Check if current frame is an arguments adaptor frame.
    728   __ cmpp(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset),
    729           Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
    730   __ j(not_equal, &done, Label::kNear);
    731 
    732   // Load arguments count from current arguments adaptor frame (note, it
    733   // does not include receiver).
    734   Register caller_args_count_reg = scratch1;
    735   __ SmiToInteger32(
    736       caller_args_count_reg,
    737       Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
    738 
    739   ParameterCount callee_args_count(args_reg);
    740   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
    741                         scratch3, ReturnAddressState::kOnStack);
    742   __ bind(&done);
    743 }
    744 
    745 namespace {
    746 
    747 void AdjustStackPointerForTailCall(MacroAssembler* masm,
    748                                    FrameAccessState* state,
    749                                    int new_slot_above_sp,
    750                                    bool allow_shrinkage = true) {
    751   int current_sp_offset = state->GetSPToFPSlotCount() +
    752                           StandardFrameConstants::kFixedSlotCountAboveFp;
    753   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
    754   if (stack_slot_delta > 0) {
    755     masm->subq(rsp, Immediate(stack_slot_delta * kPointerSize));
    756     state->IncreaseSPDelta(stack_slot_delta);
    757   } else if (allow_shrinkage && stack_slot_delta < 0) {
    758     masm->addq(rsp, Immediate(-stack_slot_delta * kPointerSize));
    759     state->IncreaseSPDelta(stack_slot_delta);
    760   }
    761 }
    762 
    763 }  // namespace
    764 
    765 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
    766                                               int first_unused_stack_slot) {
    767   CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
    768   ZoneVector<MoveOperands*> pushes(zone());
    769   GetPushCompatibleMoves(instr, flags, &pushes);
    770 
    771   if (!pushes.empty() &&
    772       (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
    773        first_unused_stack_slot)) {
    774     X64OperandConverter g(this, instr);
    775     for (auto move : pushes) {
    776       LocationOperand destination_location(
    777           LocationOperand::cast(move->destination()));
    778       InstructionOperand source(move->source());
    779       AdjustStackPointerForTailCall(masm(), frame_access_state(),
    780                                     destination_location.index());
    781       if (source.IsStackSlot()) {
    782         LocationOperand source_location(LocationOperand::cast(source));
    783         __ Push(g.SlotToOperand(source_location.index()));
    784       } else if (source.IsRegister()) {
    785         LocationOperand source_location(LocationOperand::cast(source));
    786         __ Push(source_location.GetRegister());
    787       } else if (source.IsImmediate()) {
    788         __ Push(Immediate(ImmediateOperand::cast(source).inline_value()));
    789       } else {
    790         // Pushes of non-scalar data types is not supported.
    791         UNIMPLEMENTED();
    792       }
    793       frame_access_state()->IncreaseSPDelta(1);
    794       move->Eliminate();
    795     }
    796   }
    797   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    798                                 first_unused_stack_slot, false);
    799 }
    800 
    801 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
    802                                              int first_unused_stack_slot) {
    803   AdjustStackPointerForTailCall(masm(), frame_access_state(),
    804                                 first_unused_stack_slot);
    805 }
    806 
    807 // Assembles an instruction after register allocation, producing machine code.
    808 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    809     Instruction* instr) {
    810   X64OperandConverter i(this, instr);
    811   InstructionCode opcode = instr->opcode();
    812   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
    813   switch (arch_opcode) {
    814     case kArchCallCodeObject: {
    815       EnsureSpaceForLazyDeopt();
    816       if (HasImmediateInput(instr, 0)) {
    817         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
    818         __ Call(code, RelocInfo::CODE_TARGET);
    819       } else {
    820         Register reg = i.InputRegister(0);
    821         __ addp(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
    822         __ call(reg);
    823       }
    824       RecordCallPosition(instr);
    825       frame_access_state()->ClearSPDelta();
    826       break;
    827     }
    828     case kArchTailCallCodeObjectFromJSFunction:
    829     case kArchTailCallCodeObject: {
    830       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
    831         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    832                                          i.TempRegister(0), i.TempRegister(1),
    833                                          i.TempRegister(2));
    834       }
    835       if (HasImmediateInput(instr, 0)) {
    836         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
    837         __ jmp(code, RelocInfo::CODE_TARGET);
    838       } else {
    839         Register reg = i.InputRegister(0);
    840         __ addp(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
    841         __ jmp(reg);
    842       }
    843       unwinding_info_writer_.MarkBlockWillExit();
    844       frame_access_state()->ClearSPDelta();
    845       frame_access_state()->SetFrameAccessToDefault();
    846       break;
    847     }
    848     case kArchTailCallAddress: {
    849       CHECK(!HasImmediateInput(instr, 0));
    850       Register reg = i.InputRegister(0);
    851       __ jmp(reg);
    852       unwinding_info_writer_.MarkBlockWillExit();
    853       frame_access_state()->ClearSPDelta();
    854       frame_access_state()->SetFrameAccessToDefault();
    855       break;
    856     }
    857     case kArchCallJSFunction: {
    858       EnsureSpaceForLazyDeopt();
    859       Register func = i.InputRegister(0);
    860       if (FLAG_debug_code) {
    861         // Check the function's context matches the context argument.
    862         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
    863         __ Assert(equal, kWrongFunctionContext);
    864       }
    865       __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
    866       frame_access_state()->ClearSPDelta();
    867       RecordCallPosition(instr);
    868       break;
    869     }
    870     case kArchTailCallJSFunctionFromJSFunction: {
    871       Register func = i.InputRegister(0);
    872       if (FLAG_debug_code) {
    873         // Check the function's context matches the context argument.
    874         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
    875         __ Assert(equal, kWrongFunctionContext);
    876       }
    877       AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    878                                        i.TempRegister(0), i.TempRegister(1),
    879                                        i.TempRegister(2));
    880       __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
    881       frame_access_state()->ClearSPDelta();
    882       frame_access_state()->SetFrameAccessToDefault();
    883       break;
    884     }
    885     case kArchPrepareCallCFunction: {
    886       // Frame alignment requires using FP-relative frame addressing.
    887       frame_access_state()->SetFrameAccessToFP();
    888       int const num_parameters = MiscField::decode(instr->opcode());
    889       __ PrepareCallCFunction(num_parameters);
    890       break;
    891     }
    892     case kArchPrepareTailCall:
    893       AssemblePrepareTailCall();
    894       break;
    895     case kArchCallCFunction: {
    896       int const num_parameters = MiscField::decode(instr->opcode());
    897       if (HasImmediateInput(instr, 0)) {
    898         ExternalReference ref = i.InputExternalReference(0);
    899         __ CallCFunction(ref, num_parameters);
    900       } else {
    901         Register func = i.InputRegister(0);
    902         __ CallCFunction(func, num_parameters);
    903       }
    904       frame_access_state()->SetFrameAccessToDefault();
    905       frame_access_state()->ClearSPDelta();
    906       break;
    907     }
    908     case kArchJmp:
    909       AssembleArchJump(i.InputRpo(0));
    910       break;
    911     case kArchLookupSwitch:
    912       AssembleArchLookupSwitch(instr);
    913       break;
    914     case kArchTableSwitch:
    915       AssembleArchTableSwitch(instr);
    916       break;
    917     case kArchComment: {
    918       Address comment_string = i.InputExternalReference(0).address();
    919       __ RecordComment(reinterpret_cast<const char*>(comment_string));
    920       break;
    921     }
    922     case kArchDebugBreak:
    923       __ int3();
    924       break;
    925     case kArchNop:
    926     case kArchThrowTerminator:
    927       // don't emit code for nops.
    928       break;
    929     case kArchDeoptimize: {
    930       int deopt_state_id =
    931           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    932       CodeGenResult result =
    933           AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
    934       if (result != kSuccess) return result;
    935       break;
    936     }
    937     case kArchRet:
    938       AssembleReturn(instr->InputAt(0));
    939       break;
    940     case kArchStackPointer:
    941       __ movq(i.OutputRegister(), rsp);
    942       break;
    943     case kArchFramePointer:
    944       __ movq(i.OutputRegister(), rbp);
    945       break;
    946     case kArchParentFramePointer:
    947       if (frame_access_state()->has_frame()) {
    948         __ movq(i.OutputRegister(), Operand(rbp, 0));
    949       } else {
    950         __ movq(i.OutputRegister(), rbp);
    951       }
    952       break;
    953     case kArchTruncateDoubleToI: {
    954       auto result = i.OutputRegister();
    955       auto input = i.InputDoubleRegister(0);
    956       auto ool = new (zone()) OutOfLineTruncateDoubleToI(
    957           this, result, input, &unwinding_info_writer_);
    958       // We use Cvttsd2siq instead of Cvttsd2si due to performance reasons. The
    959       // use of Cvttsd2siq requires the movl below to avoid sign extension.
    960       __ Cvttsd2siq(result, input);
    961       __ cmpq(result, Immediate(1));
    962       __ j(overflow, ool->entry());
    963       __ bind(ool->exit());
    964       __ movl(result, result);
    965       break;
    966     }
    967     case kArchStoreWithWriteBarrier: {
    968       RecordWriteMode mode =
    969           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    970       Register object = i.InputRegister(0);
    971       size_t index = 0;
    972       Operand operand = i.MemoryOperand(&index);
    973       Register value = i.InputRegister(index);
    974       Register scratch0 = i.TempRegister(0);
    975       Register scratch1 = i.TempRegister(1);
    976       auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
    977                                                    scratch0, scratch1, mode);
    978       __ movp(operand, value);
    979       __ CheckPageFlag(object, scratch0,
    980                        MemoryChunk::kPointersFromHereAreInterestingMask,
    981                        not_zero, ool->entry());
    982       __ bind(ool->exit());
    983       break;
    984     }
    985     case kArchStackSlot: {
    986       FrameOffset offset =
    987           frame_access_state()->GetFrameOffset(i.InputInt32(0));
    988       Register base;
    989       if (offset.from_stack_pointer()) {
    990         base = rsp;
    991       } else {
    992         base = rbp;
    993       }
    994       __ leaq(i.OutputRegister(), Operand(base, offset.offset()));
    995       break;
    996     }
    997     case kIeee754Float64Acos:
    998       ASSEMBLE_IEEE754_UNOP(acos);
    999       break;
   1000     case kIeee754Float64Acosh:
   1001       ASSEMBLE_IEEE754_UNOP(acosh);
   1002       break;
   1003     case kIeee754Float64Asin:
   1004       ASSEMBLE_IEEE754_UNOP(asin);
   1005       break;
   1006     case kIeee754Float64Asinh:
   1007       ASSEMBLE_IEEE754_UNOP(asinh);
   1008       break;
   1009     case kIeee754Float64Atan:
   1010       ASSEMBLE_IEEE754_UNOP(atan);
   1011       break;
   1012     case kIeee754Float64Atanh:
   1013       ASSEMBLE_IEEE754_UNOP(atanh);
   1014       break;
   1015     case kIeee754Float64Atan2:
   1016       ASSEMBLE_IEEE754_BINOP(atan2);
   1017       break;
   1018     case kIeee754Float64Cbrt:
   1019       ASSEMBLE_IEEE754_UNOP(cbrt);
   1020       break;
   1021     case kIeee754Float64Cos:
   1022       ASSEMBLE_IEEE754_UNOP(cos);
   1023       break;
   1024     case kIeee754Float64Cosh:
   1025       ASSEMBLE_IEEE754_UNOP(cosh);
   1026       break;
   1027     case kIeee754Float64Exp:
   1028       ASSEMBLE_IEEE754_UNOP(exp);
   1029       break;
   1030     case kIeee754Float64Expm1:
   1031       ASSEMBLE_IEEE754_UNOP(expm1);
   1032       break;
   1033     case kIeee754Float64Log:
   1034       ASSEMBLE_IEEE754_UNOP(log);
   1035       break;
   1036     case kIeee754Float64Log1p:
   1037       ASSEMBLE_IEEE754_UNOP(log1p);
   1038       break;
   1039     case kIeee754Float64Log2:
   1040       ASSEMBLE_IEEE754_UNOP(log2);
   1041       break;
   1042     case kIeee754Float64Log10:
   1043       ASSEMBLE_IEEE754_UNOP(log10);
   1044       break;
   1045     case kIeee754Float64Pow: {
   1046       // TODO(bmeurer): Improve integration of the stub.
   1047       __ Movsd(xmm2, xmm0);
   1048       MathPowStub stub(isolate(), MathPowStub::DOUBLE);
   1049       __ CallStub(&stub);
   1050       __ Movsd(xmm0, xmm3);
   1051       break;
   1052     }
   1053     case kIeee754Float64Sin:
   1054       ASSEMBLE_IEEE754_UNOP(sin);
   1055       break;
   1056     case kIeee754Float64Sinh:
   1057       ASSEMBLE_IEEE754_UNOP(sinh);
   1058       break;
   1059     case kIeee754Float64Tan:
   1060       ASSEMBLE_IEEE754_UNOP(tan);
   1061       break;
   1062     case kIeee754Float64Tanh:
   1063       ASSEMBLE_IEEE754_UNOP(tanh);
   1064       break;
   1065     case kX64Add32:
   1066       ASSEMBLE_BINOP(addl);
   1067       break;
   1068     case kX64Add:
   1069       ASSEMBLE_BINOP(addq);
   1070       break;
   1071     case kX64Sub32:
   1072       ASSEMBLE_BINOP(subl);
   1073       break;
   1074     case kX64Sub:
   1075       ASSEMBLE_BINOP(subq);
   1076       break;
   1077     case kX64And32:
   1078       ASSEMBLE_BINOP(andl);
   1079       break;
   1080     case kX64And:
   1081       ASSEMBLE_BINOP(andq);
   1082       break;
   1083     case kX64Cmp8:
   1084       ASSEMBLE_COMPARE(cmpb);
   1085       break;
   1086     case kX64Cmp16:
   1087       ASSEMBLE_COMPARE(cmpw);
   1088       break;
   1089     case kX64Cmp32:
   1090       ASSEMBLE_COMPARE(cmpl);
   1091       break;
   1092     case kX64Cmp:
   1093       ASSEMBLE_COMPARE(cmpq);
   1094       break;
   1095     case kX64Test8:
   1096       ASSEMBLE_COMPARE(testb);
   1097       break;
   1098     case kX64Test16:
   1099       ASSEMBLE_COMPARE(testw);
   1100       break;
   1101     case kX64Test32:
   1102       ASSEMBLE_COMPARE(testl);
   1103       break;
   1104     case kX64Test:
   1105       ASSEMBLE_COMPARE(testq);
   1106       break;
   1107     case kX64Imul32:
   1108       ASSEMBLE_MULT(imull);
   1109       break;
   1110     case kX64Imul:
   1111       ASSEMBLE_MULT(imulq);
   1112       break;
   1113     case kX64ImulHigh32:
   1114       if (instr->InputAt(1)->IsRegister()) {
   1115         __ imull(i.InputRegister(1));
   1116       } else {
   1117         __ imull(i.InputOperand(1));
   1118       }
   1119       break;
   1120     case kX64UmulHigh32:
   1121       if (instr->InputAt(1)->IsRegister()) {
   1122         __ mull(i.InputRegister(1));
   1123       } else {
   1124         __ mull(i.InputOperand(1));
   1125       }
   1126       break;
   1127     case kX64Idiv32:
   1128       __ cdq();
   1129       __ idivl(i.InputRegister(1));
   1130       break;
   1131     case kX64Idiv:
   1132       __ cqo();
   1133       __ idivq(i.InputRegister(1));
   1134       break;
   1135     case kX64Udiv32:
   1136       __ xorl(rdx, rdx);
   1137       __ divl(i.InputRegister(1));
   1138       break;
   1139     case kX64Udiv:
   1140       __ xorq(rdx, rdx);
   1141       __ divq(i.InputRegister(1));
   1142       break;
   1143     case kX64Not:
   1144       ASSEMBLE_UNOP(notq);
   1145       break;
   1146     case kX64Not32:
   1147       ASSEMBLE_UNOP(notl);
   1148       break;
   1149     case kX64Neg:
   1150       ASSEMBLE_UNOP(negq);
   1151       break;
   1152     case kX64Neg32:
   1153       ASSEMBLE_UNOP(negl);
   1154       break;
   1155     case kX64Or32:
   1156       ASSEMBLE_BINOP(orl);
   1157       break;
   1158     case kX64Or:
   1159       ASSEMBLE_BINOP(orq);
   1160       break;
   1161     case kX64Xor32:
   1162       ASSEMBLE_BINOP(xorl);
   1163       break;
   1164     case kX64Xor:
   1165       ASSEMBLE_BINOP(xorq);
   1166       break;
   1167     case kX64Shl32:
   1168       ASSEMBLE_SHIFT(shll, 5);
   1169       break;
   1170     case kX64Shl:
   1171       ASSEMBLE_SHIFT(shlq, 6);
   1172       break;
   1173     case kX64Shr32:
   1174       ASSEMBLE_SHIFT(shrl, 5);
   1175       break;
   1176     case kX64Shr:
   1177       ASSEMBLE_SHIFT(shrq, 6);
   1178       break;
   1179     case kX64Sar32:
   1180       ASSEMBLE_SHIFT(sarl, 5);
   1181       break;
   1182     case kX64Sar:
   1183       ASSEMBLE_SHIFT(sarq, 6);
   1184       break;
   1185     case kX64Ror32:
   1186       ASSEMBLE_SHIFT(rorl, 5);
   1187       break;
   1188     case kX64Ror:
   1189       ASSEMBLE_SHIFT(rorq, 6);
   1190       break;
   1191     case kX64Lzcnt:
   1192       if (instr->InputAt(0)->IsRegister()) {
   1193         __ Lzcntq(i.OutputRegister(), i.InputRegister(0));
   1194       } else {
   1195         __ Lzcntq(i.OutputRegister(), i.InputOperand(0));
   1196       }
   1197       break;
   1198     case kX64Lzcnt32:
   1199       if (instr->InputAt(0)->IsRegister()) {
   1200         __ Lzcntl(i.OutputRegister(), i.InputRegister(0));
   1201       } else {
   1202         __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
   1203       }
   1204       break;
   1205     case kX64Tzcnt:
   1206       if (instr->InputAt(0)->IsRegister()) {
   1207         __ Tzcntq(i.OutputRegister(), i.InputRegister(0));
   1208       } else {
   1209         __ Tzcntq(i.OutputRegister(), i.InputOperand(0));
   1210       }
   1211       break;
   1212     case kX64Tzcnt32:
   1213       if (instr->InputAt(0)->IsRegister()) {
   1214         __ Tzcntl(i.OutputRegister(), i.InputRegister(0));
   1215       } else {
   1216         __ Tzcntl(i.OutputRegister(), i.InputOperand(0));
   1217       }
   1218       break;
   1219     case kX64Popcnt:
   1220       if (instr->InputAt(0)->IsRegister()) {
   1221         __ Popcntq(i.OutputRegister(), i.InputRegister(0));
   1222       } else {
   1223         __ Popcntq(i.OutputRegister(), i.InputOperand(0));
   1224       }
   1225       break;
   1226     case kX64Popcnt32:
   1227       if (instr->InputAt(0)->IsRegister()) {
   1228         __ Popcntl(i.OutputRegister(), i.InputRegister(0));
   1229       } else {
   1230         __ Popcntl(i.OutputRegister(), i.InputOperand(0));
   1231       }
   1232       break;
   1233     case kSSEFloat32Cmp:
   1234       ASSEMBLE_SSE_BINOP(Ucomiss);
   1235       break;
   1236     case kSSEFloat32Add:
   1237       ASSEMBLE_SSE_BINOP(addss);
   1238       break;
   1239     case kSSEFloat32Sub:
   1240       ASSEMBLE_SSE_BINOP(subss);
   1241       break;
   1242     case kSSEFloat32Mul:
   1243       ASSEMBLE_SSE_BINOP(mulss);
   1244       break;
   1245     case kSSEFloat32Div:
   1246       ASSEMBLE_SSE_BINOP(divss);
   1247       // Don't delete this mov. It may improve performance on some CPUs,
   1248       // when there is a (v)mulss depending on the result.
   1249       __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1250       break;
   1251     case kSSEFloat32Abs: {
   1252       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1253       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1254       __ psrlq(kScratchDoubleReg, 33);
   1255       __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
   1256       break;
   1257     }
   1258     case kSSEFloat32Neg: {
   1259       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1260       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1261       __ psllq(kScratchDoubleReg, 31);
   1262       __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
   1263       break;
   1264     }
   1265     case kSSEFloat32Sqrt:
   1266       ASSEMBLE_SSE_UNOP(sqrtss);
   1267       break;
   1268     case kSSEFloat32ToFloat64:
   1269       ASSEMBLE_SSE_UNOP(Cvtss2sd);
   1270       break;
   1271     case kSSEFloat32Round: {
   1272       CpuFeatureScope sse_scope(masm(), SSE4_1);
   1273       RoundingMode const mode =
   1274           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
   1275       __ Roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
   1276       break;
   1277     }
   1278     case kSSEFloat32ToInt32:
   1279       if (instr->InputAt(0)->IsFPRegister()) {
   1280         __ Cvttss2si(i.OutputRegister(), i.InputDoubleRegister(0));
   1281       } else {
   1282         __ Cvttss2si(i.OutputRegister(), i.InputOperand(0));
   1283       }
   1284       break;
   1285     case kSSEFloat32ToUint32: {
   1286       if (instr->InputAt(0)->IsFPRegister()) {
   1287         __ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1288       } else {
   1289         __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
   1290       }
   1291       break;
   1292     }
   1293     case kSSEFloat64Cmp:
   1294       ASSEMBLE_SSE_BINOP(Ucomisd);
   1295       break;
   1296     case kSSEFloat64Add:
   1297       ASSEMBLE_SSE_BINOP(addsd);
   1298       break;
   1299     case kSSEFloat64Sub:
   1300       ASSEMBLE_SSE_BINOP(subsd);
   1301       break;
   1302     case kSSEFloat64Mul:
   1303       ASSEMBLE_SSE_BINOP(mulsd);
   1304       break;
   1305     case kSSEFloat64Div:
   1306       ASSEMBLE_SSE_BINOP(divsd);
   1307       // Don't delete this mov. It may improve performance on some CPUs,
   1308       // when there is a (v)mulsd depending on the result.
   1309       __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1310       break;
   1311     case kSSEFloat64Mod: {
   1312       __ subq(rsp, Immediate(kDoubleSize));
   1313       unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   1314                                                        kDoubleSize);
   1315       // Move values to st(0) and st(1).
   1316       __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
   1317       __ fld_d(Operand(rsp, 0));
   1318       __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
   1319       __ fld_d(Operand(rsp, 0));
   1320       // Loop while fprem isn't done.
   1321       Label mod_loop;
   1322       __ bind(&mod_loop);
   1323       // This instructions traps on all kinds inputs, but we are assuming the
   1324       // floating point control word is set to ignore them all.
   1325       __ fprem();
   1326       // The following 2 instruction implicitly use rax.
   1327       __ fnstsw_ax();
   1328       if (CpuFeatures::IsSupported(SAHF)) {
   1329         CpuFeatureScope sahf_scope(masm(), SAHF);
   1330         __ sahf();
   1331       } else {
   1332         __ shrl(rax, Immediate(8));
   1333         __ andl(rax, Immediate(0xFF));
   1334         __ pushq(rax);
   1335         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   1336                                                          kPointerSize);
   1337         __ popfq();
   1338         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   1339                                                          -kPointerSize);
   1340       }
   1341       __ j(parity_even, &mod_loop);
   1342       // Move output to stack and clean up.
   1343       __ fstp(1);
   1344       __ fstp_d(Operand(rsp, 0));
   1345       __ Movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
   1346       __ addq(rsp, Immediate(kDoubleSize));
   1347       unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   1348                                                        -kDoubleSize);
   1349       break;
   1350     }
   1351     case kSSEFloat32Max: {
   1352       Label compare_nan, compare_swap, done_compare;
   1353       if (instr->InputAt(1)->IsFPRegister()) {
   1354         __ Ucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1355       } else {
   1356         __ Ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
   1357       }
   1358       auto ool =
   1359           new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister());
   1360       __ j(parity_even, ool->entry());
   1361       __ j(above, &done_compare, Label::kNear);
   1362       __ j(below, &compare_swap, Label::kNear);
   1363       __ Movmskps(kScratchRegister, i.InputDoubleRegister(0));
   1364       __ testl(kScratchRegister, Immediate(1));
   1365       __ j(zero, &done_compare, Label::kNear);
   1366       __ bind(&compare_swap);
   1367       if (instr->InputAt(1)->IsFPRegister()) {
   1368         __ Movss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1369       } else {
   1370         __ Movss(i.InputDoubleRegister(0), i.InputOperand(1));
   1371       }
   1372       __ bind(&done_compare);
   1373       __ bind(ool->exit());
   1374       break;
   1375     }
   1376     case kSSEFloat32Min: {
   1377       Label compare_swap, done_compare;
   1378       if (instr->InputAt(1)->IsFPRegister()) {
   1379         __ Ucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1380       } else {
   1381         __ Ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
   1382       }
   1383       auto ool =
   1384           new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister());
   1385       __ j(parity_even, ool->entry());
   1386       __ j(below, &done_compare, Label::kNear);
   1387       __ j(above, &compare_swap, Label::kNear);
   1388       if (instr->InputAt(1)->IsFPRegister()) {
   1389         __ Movmskps(kScratchRegister, i.InputDoubleRegister(1));
   1390       } else {
   1391         __ Movss(kScratchDoubleReg, i.InputOperand(1));
   1392         __ Movmskps(kScratchRegister, kScratchDoubleReg);
   1393       }
   1394       __ testl(kScratchRegister, Immediate(1));
   1395       __ j(zero, &done_compare, Label::kNear);
   1396       __ bind(&compare_swap);
   1397       if (instr->InputAt(1)->IsFPRegister()) {
   1398         __ Movss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1399       } else {
   1400         __ Movss(i.InputDoubleRegister(0), i.InputOperand(1));
   1401       }
   1402       __ bind(&done_compare);
   1403       __ bind(ool->exit());
   1404       break;
   1405     }
   1406     case kSSEFloat64Max: {
   1407       Label compare_nan, compare_swap, done_compare;
   1408       if (instr->InputAt(1)->IsFPRegister()) {
   1409         __ Ucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1410       } else {
   1411         __ Ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
   1412       }
   1413       auto ool =
   1414           new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister());
   1415       __ j(parity_even, ool->entry());
   1416       __ j(above, &done_compare, Label::kNear);
   1417       __ j(below, &compare_swap, Label::kNear);
   1418       __ Movmskpd(kScratchRegister, i.InputDoubleRegister(0));
   1419       __ testl(kScratchRegister, Immediate(1));
   1420       __ j(zero, &done_compare, Label::kNear);
   1421       __ bind(&compare_swap);
   1422       if (instr->InputAt(1)->IsFPRegister()) {
   1423         __ Movsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1424       } else {
   1425         __ Movsd(i.InputDoubleRegister(0), i.InputOperand(1));
   1426       }
   1427       __ bind(&done_compare);
   1428       __ bind(ool->exit());
   1429       break;
   1430     }
   1431     case kSSEFloat64Min: {
   1432       Label compare_swap, done_compare;
   1433       if (instr->InputAt(1)->IsFPRegister()) {
   1434         __ Ucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1435       } else {
   1436         __ Ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
   1437       }
   1438       auto ool =
   1439           new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister());
   1440       __ j(parity_even, ool->entry());
   1441       __ j(below, &done_compare, Label::kNear);
   1442       __ j(above, &compare_swap, Label::kNear);
   1443       if (instr->InputAt(1)->IsFPRegister()) {
   1444         __ Movmskpd(kScratchRegister, i.InputDoubleRegister(1));
   1445       } else {
   1446         __ Movsd(kScratchDoubleReg, i.InputOperand(1));
   1447         __ Movmskpd(kScratchRegister, kScratchDoubleReg);
   1448       }
   1449       __ testl(kScratchRegister, Immediate(1));
   1450       __ j(zero, &done_compare, Label::kNear);
   1451       __ bind(&compare_swap);
   1452       if (instr->InputAt(1)->IsFPRegister()) {
   1453         __ Movsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1454       } else {
   1455         __ Movsd(i.InputDoubleRegister(0), i.InputOperand(1));
   1456       }
   1457       __ bind(&done_compare);
   1458       __ bind(ool->exit());
   1459       break;
   1460     }
   1461     case kSSEFloat64Abs: {
   1462       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1463       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1464       __ psrlq(kScratchDoubleReg, 1);
   1465       __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
   1466       break;
   1467     }
   1468     case kSSEFloat64Neg: {
   1469       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1470       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1471       __ psllq(kScratchDoubleReg, 63);
   1472       __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
   1473       break;
   1474     }
   1475     case kSSEFloat64Sqrt:
   1476       ASSEMBLE_SSE_UNOP(Sqrtsd);
   1477       break;
   1478     case kSSEFloat64Round: {
   1479       CpuFeatureScope sse_scope(masm(), SSE4_1);
   1480       RoundingMode const mode =
   1481           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
   1482       __ Roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
   1483       break;
   1484     }
   1485     case kSSEFloat64ToFloat32:
   1486       ASSEMBLE_SSE_UNOP(Cvtsd2ss);
   1487       break;
   1488     case kSSEFloat64ToInt32:
   1489       if (instr->InputAt(0)->IsFPRegister()) {
   1490         __ Cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
   1491       } else {
   1492         __ Cvttsd2si(i.OutputRegister(), i.InputOperand(0));
   1493       }
   1494       break;
   1495     case kSSEFloat64ToUint32: {
   1496       if (instr->InputAt(0)->IsFPRegister()) {
   1497         __ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1498       } else {
   1499         __ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
   1500       }
   1501       if (MiscField::decode(instr->opcode())) {
   1502         __ AssertZeroExtended(i.OutputRegister());
   1503       }
   1504       break;
   1505     }
   1506     case kSSEFloat32ToInt64:
   1507       if (instr->InputAt(0)->IsFPRegister()) {
   1508         __ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1509       } else {
   1510         __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
   1511       }
   1512       if (instr->OutputCount() > 1) {
   1513         __ Set(i.OutputRegister(1), 1);
   1514         Label done;
   1515         Label fail;
   1516         __ Move(kScratchDoubleReg, static_cast<float>(INT64_MIN));
   1517         if (instr->InputAt(0)->IsFPRegister()) {
   1518           __ Ucomiss(kScratchDoubleReg, i.InputDoubleRegister(0));
   1519         } else {
   1520           __ Ucomiss(kScratchDoubleReg, i.InputOperand(0));
   1521         }
   1522         // If the input is NaN, then the conversion fails.
   1523         __ j(parity_even, &fail);
   1524         // If the input is INT64_MIN, then the conversion succeeds.
   1525         __ j(equal, &done);
   1526         __ cmpq(i.OutputRegister(0), Immediate(1));
   1527         // If the conversion results in INT64_MIN, but the input was not
   1528         // INT64_MIN, then the conversion fails.
   1529         __ j(no_overflow, &done);
   1530         __ bind(&fail);
   1531         __ Set(i.OutputRegister(1), 0);
   1532         __ bind(&done);
   1533       }
   1534       break;
   1535     case kSSEFloat64ToInt64:
   1536       if (instr->InputAt(0)->IsFPRegister()) {
   1537         __ Cvttsd2siq(i.OutputRegister(0), i.InputDoubleRegister(0));
   1538       } else {
   1539         __ Cvttsd2siq(i.OutputRegister(0), i.InputOperand(0));
   1540       }
   1541       if (instr->OutputCount() > 1) {
   1542         __ Set(i.OutputRegister(1), 1);
   1543         Label done;
   1544         Label fail;
   1545         __ Move(kScratchDoubleReg, static_cast<double>(INT64_MIN));
   1546         if (instr->InputAt(0)->IsFPRegister()) {
   1547           __ Ucomisd(kScratchDoubleReg, i.InputDoubleRegister(0));
   1548         } else {
   1549           __ Ucomisd(kScratchDoubleReg, i.InputOperand(0));
   1550         }
   1551         // If the input is NaN, then the conversion fails.
   1552         __ j(parity_even, &fail);
   1553         // If the input is INT64_MIN, then the conversion succeeds.
   1554         __ j(equal, &done);
   1555         __ cmpq(i.OutputRegister(0), Immediate(1));
   1556         // If the conversion results in INT64_MIN, but the input was not
   1557         // INT64_MIN, then the conversion fails.
   1558         __ j(no_overflow, &done);
   1559         __ bind(&fail);
   1560         __ Set(i.OutputRegister(1), 0);
   1561         __ bind(&done);
   1562       }
   1563       break;
   1564     case kSSEFloat32ToUint64: {
   1565       Label done;
   1566       Label success;
   1567       if (instr->OutputCount() > 1) {
   1568         __ Set(i.OutputRegister(1), 0);
   1569       }
   1570       // There does not exist a Float32ToUint64 instruction, so we have to use
   1571       // the Float32ToInt64 instruction.
   1572       if (instr->InputAt(0)->IsFPRegister()) {
   1573         __ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1574       } else {
   1575         __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
   1576       }
   1577       // Check if the result of the Float32ToInt64 conversion is positive, we
   1578       // are already done.
   1579       __ testq(i.OutputRegister(), i.OutputRegister());
   1580       __ j(positive, &success);
   1581       // The result of the first conversion was negative, which means that the
   1582       // input value was not within the positive int64 range. We subtract 2^64
   1583       // and convert it again to see if it is within the uint64 range.
   1584       __ Move(kScratchDoubleReg, -9223372036854775808.0f);
   1585       if (instr->InputAt(0)->IsFPRegister()) {
   1586         __ addss(kScratchDoubleReg, i.InputDoubleRegister(0));
   1587       } else {
   1588         __ addss(kScratchDoubleReg, i.InputOperand(0));
   1589       }
   1590       __ Cvttss2siq(i.OutputRegister(), kScratchDoubleReg);
   1591       __ testq(i.OutputRegister(), i.OutputRegister());
   1592       // The only possible negative value here is 0x80000000000000000, which is
   1593       // used on x64 to indicate an integer overflow.
   1594       __ j(negative, &done);
   1595       // The input value is within uint64 range and the second conversion worked
   1596       // successfully, but we still have to undo the subtraction we did
   1597       // earlier.
   1598       __ Set(kScratchRegister, 0x8000000000000000);
   1599       __ orq(i.OutputRegister(), kScratchRegister);
   1600       __ bind(&success);
   1601       if (instr->OutputCount() > 1) {
   1602         __ Set(i.OutputRegister(1), 1);
   1603       }
   1604       __ bind(&done);
   1605       break;
   1606     }
   1607     case kSSEFloat64ToUint64: {
   1608       Label done;
   1609       Label success;
   1610       if (instr->OutputCount() > 1) {
   1611         __ Set(i.OutputRegister(1), 0);
   1612       }
   1613       // There does not exist a Float64ToUint64 instruction, so we have to use
   1614       // the Float64ToInt64 instruction.
   1615       if (instr->InputAt(0)->IsFPRegister()) {
   1616         __ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1617       } else {
   1618         __ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
   1619       }
   1620       // Check if the result of the Float64ToInt64 conversion is positive, we
   1621       // are already done.
   1622       __ testq(i.OutputRegister(), i.OutputRegister());
   1623       __ j(positive, &success);
   1624       // The result of the first conversion was negative, which means that the
   1625       // input value was not within the positive int64 range. We subtract 2^64
   1626       // and convert it again to see if it is within the uint64 range.
   1627       __ Move(kScratchDoubleReg, -9223372036854775808.0);
   1628       if (instr->InputAt(0)->IsFPRegister()) {
   1629         __ addsd(kScratchDoubleReg, i.InputDoubleRegister(0));
   1630       } else {
   1631         __ addsd(kScratchDoubleReg, i.InputOperand(0));
   1632       }
   1633       __ Cvttsd2siq(i.OutputRegister(), kScratchDoubleReg);
   1634       __ testq(i.OutputRegister(), i.OutputRegister());
   1635       // The only possible negative value here is 0x80000000000000000, which is
   1636       // used on x64 to indicate an integer overflow.
   1637       __ j(negative, &done);
   1638       // The input value is within uint64 range and the second conversion worked
   1639       // successfully, but we still have to undo the subtraction we did
   1640       // earlier.
   1641       __ Set(kScratchRegister, 0x8000000000000000);
   1642       __ orq(i.OutputRegister(), kScratchRegister);
   1643       __ bind(&success);
   1644       if (instr->OutputCount() > 1) {
   1645         __ Set(i.OutputRegister(1), 1);
   1646       }
   1647       __ bind(&done);
   1648       break;
   1649     }
   1650     case kSSEInt32ToFloat64:
   1651       if (instr->InputAt(0)->IsRegister()) {
   1652         __ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
   1653       } else {
   1654         __ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
   1655       }
   1656       break;
   1657     case kSSEInt32ToFloat32:
   1658       if (instr->InputAt(0)->IsRegister()) {
   1659         __ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
   1660       } else {
   1661         __ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
   1662       }
   1663       break;
   1664     case kSSEInt64ToFloat32:
   1665       if (instr->InputAt(0)->IsRegister()) {
   1666         __ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
   1667       } else {
   1668         __ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
   1669       }
   1670       break;
   1671     case kSSEInt64ToFloat64:
   1672       if (instr->InputAt(0)->IsRegister()) {
   1673         __ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
   1674       } else {
   1675         __ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
   1676       }
   1677       break;
   1678     case kSSEUint64ToFloat32:
   1679       if (instr->InputAt(0)->IsRegister()) {
   1680         __ movq(kScratchRegister, i.InputRegister(0));
   1681       } else {
   1682         __ movq(kScratchRegister, i.InputOperand(0));
   1683       }
   1684       __ Cvtqui2ss(i.OutputDoubleRegister(), kScratchRegister,
   1685                    i.TempRegister(0));
   1686       break;
   1687     case kSSEUint64ToFloat64:
   1688       if (instr->InputAt(0)->IsRegister()) {
   1689         __ movq(kScratchRegister, i.InputRegister(0));
   1690       } else {
   1691         __ movq(kScratchRegister, i.InputOperand(0));
   1692       }
   1693       __ Cvtqui2sd(i.OutputDoubleRegister(), kScratchRegister,
   1694                    i.TempRegister(0));
   1695       break;
   1696     case kSSEUint32ToFloat64:
   1697       if (instr->InputAt(0)->IsRegister()) {
   1698         __ movl(kScratchRegister, i.InputRegister(0));
   1699       } else {
   1700         __ movl(kScratchRegister, i.InputOperand(0));
   1701       }
   1702       __ Cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
   1703       break;
   1704     case kSSEUint32ToFloat32:
   1705       if (instr->InputAt(0)->IsRegister()) {
   1706         __ movl(kScratchRegister, i.InputRegister(0));
   1707       } else {
   1708         __ movl(kScratchRegister, i.InputOperand(0));
   1709       }
   1710       __ Cvtqsi2ss(i.OutputDoubleRegister(), kScratchRegister);
   1711       break;
   1712     case kSSEFloat64ExtractLowWord32:
   1713       if (instr->InputAt(0)->IsFPStackSlot()) {
   1714         __ movl(i.OutputRegister(), i.InputOperand(0));
   1715       } else {
   1716         __ Movd(i.OutputRegister(), i.InputDoubleRegister(0));
   1717       }
   1718       break;
   1719     case kSSEFloat64ExtractHighWord32:
   1720       if (instr->InputAt(0)->IsFPStackSlot()) {
   1721         __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
   1722       } else {
   1723         __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
   1724       }
   1725       break;
   1726     case kSSEFloat64InsertLowWord32:
   1727       if (instr->InputAt(1)->IsRegister()) {
   1728         __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
   1729       } else {
   1730         __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
   1731       }
   1732       break;
   1733     case kSSEFloat64InsertHighWord32:
   1734       if (instr->InputAt(1)->IsRegister()) {
   1735         __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
   1736       } else {
   1737         __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
   1738       }
   1739       break;
   1740     case kSSEFloat64LoadLowWord32:
   1741       if (instr->InputAt(0)->IsRegister()) {
   1742         __ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
   1743       } else {
   1744         __ Movd(i.OutputDoubleRegister(), i.InputOperand(0));
   1745       }
   1746       break;
   1747     case kAVXFloat32Cmp: {
   1748       CpuFeatureScope avx_scope(masm(), AVX);
   1749       if (instr->InputAt(1)->IsFPRegister()) {
   1750         __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1751       } else {
   1752         __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
   1753       }
   1754       break;
   1755     }
   1756     case kAVXFloat32Add:
   1757       ASSEMBLE_AVX_BINOP(vaddss);
   1758       break;
   1759     case kAVXFloat32Sub:
   1760       ASSEMBLE_AVX_BINOP(vsubss);
   1761       break;
   1762     case kAVXFloat32Mul:
   1763       ASSEMBLE_AVX_BINOP(vmulss);
   1764       break;
   1765     case kAVXFloat32Div:
   1766       ASSEMBLE_AVX_BINOP(vdivss);
   1767       // Don't delete this mov. It may improve performance on some CPUs,
   1768       // when there is a (v)mulss depending on the result.
   1769       __ Movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1770       break;
   1771     case kAVXFloat64Cmp: {
   1772       CpuFeatureScope avx_scope(masm(), AVX);
   1773       if (instr->InputAt(1)->IsFPRegister()) {
   1774         __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1775       } else {
   1776         __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
   1777       }
   1778       break;
   1779     }
   1780     case kAVXFloat64Add:
   1781       ASSEMBLE_AVX_BINOP(vaddsd);
   1782       break;
   1783     case kAVXFloat64Sub:
   1784       ASSEMBLE_AVX_BINOP(vsubsd);
   1785       break;
   1786     case kAVXFloat64Mul:
   1787       ASSEMBLE_AVX_BINOP(vmulsd);
   1788       break;
   1789     case kAVXFloat64Div:
   1790       ASSEMBLE_AVX_BINOP(vdivsd);
   1791       // Don't delete this mov. It may improve performance on some CPUs,
   1792       // when there is a (v)mulsd depending on the result.
   1793       __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1794       break;
   1795     case kAVXFloat32Abs: {
   1796       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1797       CpuFeatureScope avx_scope(masm(), AVX);
   1798       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1799       __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 33);
   1800       if (instr->InputAt(0)->IsFPRegister()) {
   1801         __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1802                   i.InputDoubleRegister(0));
   1803       } else {
   1804         __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1805                   i.InputOperand(0));
   1806       }
   1807       break;
   1808     }
   1809     case kAVXFloat32Neg: {
   1810       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1811       CpuFeatureScope avx_scope(masm(), AVX);
   1812       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1813       __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 31);
   1814       if (instr->InputAt(0)->IsFPRegister()) {
   1815         __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1816                   i.InputDoubleRegister(0));
   1817       } else {
   1818         __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1819                   i.InputOperand(0));
   1820       }
   1821       break;
   1822     }
   1823     case kAVXFloat64Abs: {
   1824       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1825       CpuFeatureScope avx_scope(masm(), AVX);
   1826       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1827       __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 1);
   1828       if (instr->InputAt(0)->IsFPRegister()) {
   1829         __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1830                   i.InputDoubleRegister(0));
   1831       } else {
   1832         __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1833                   i.InputOperand(0));
   1834       }
   1835       break;
   1836     }
   1837     case kAVXFloat64Neg: {
   1838       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1839       CpuFeatureScope avx_scope(masm(), AVX);
   1840       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1841       __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 63);
   1842       if (instr->InputAt(0)->IsFPRegister()) {
   1843         __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1844                   i.InputDoubleRegister(0));
   1845       } else {
   1846         __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1847                   i.InputOperand(0));
   1848       }
   1849       break;
   1850     }
   1851     case kSSEFloat64SilenceNaN:
   1852       __ Xorpd(kScratchDoubleReg, kScratchDoubleReg);
   1853       __ Subsd(i.InputDoubleRegister(0), kScratchDoubleReg);
   1854       break;
   1855     case kX64Movsxbl:
   1856       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1857                           __ pc_offset(), instr);
   1858       ASSEMBLE_MOVX(movsxbl);
   1859       __ AssertZeroExtended(i.OutputRegister());
   1860       break;
   1861     case kX64Movzxbl:
   1862       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1863                           __ pc_offset(), instr);
   1864       ASSEMBLE_MOVX(movzxbl);
   1865       __ AssertZeroExtended(i.OutputRegister());
   1866       break;
   1867     case kX64Movsxbq:
   1868       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1869                           __ pc_offset(), instr);
   1870       ASSEMBLE_MOVX(movsxbq);
   1871       break;
   1872     case kX64Movzxbq:
   1873       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1874                           __ pc_offset(), instr);
   1875       ASSEMBLE_MOVX(movzxbq);
   1876       __ AssertZeroExtended(i.OutputRegister());
   1877       break;
   1878     case kX64Movb: {
   1879       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1880                           __ pc_offset(), instr);
   1881       size_t index = 0;
   1882       Operand operand = i.MemoryOperand(&index);
   1883       if (HasImmediateInput(instr, index)) {
   1884         __ movb(operand, Immediate(i.InputInt8(index)));
   1885       } else {
   1886         __ movb(operand, i.InputRegister(index));
   1887       }
   1888       break;
   1889     }
   1890     case kX64Movsxwl:
   1891       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1892                           __ pc_offset(), instr);
   1893       ASSEMBLE_MOVX(movsxwl);
   1894       __ AssertZeroExtended(i.OutputRegister());
   1895       break;
   1896     case kX64Movzxwl:
   1897       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1898                           __ pc_offset(), instr);
   1899       ASSEMBLE_MOVX(movzxwl);
   1900       __ AssertZeroExtended(i.OutputRegister());
   1901       break;
   1902     case kX64Movsxwq:
   1903       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1904                           __ pc_offset(), instr);
   1905       ASSEMBLE_MOVX(movsxwq);
   1906       break;
   1907     case kX64Movzxwq:
   1908       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1909                           __ pc_offset(), instr);
   1910       ASSEMBLE_MOVX(movzxwq);
   1911       __ AssertZeroExtended(i.OutputRegister());
   1912       break;
   1913     case kX64Movw: {
   1914       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1915                           __ pc_offset(), instr);
   1916       size_t index = 0;
   1917       Operand operand = i.MemoryOperand(&index);
   1918       if (HasImmediateInput(instr, index)) {
   1919         __ movw(operand, Immediate(i.InputInt16(index)));
   1920       } else {
   1921         __ movw(operand, i.InputRegister(index));
   1922       }
   1923       break;
   1924     }
   1925     case kX64Movl:
   1926       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1927                           __ pc_offset(), instr);
   1928       if (instr->HasOutput()) {
   1929         if (instr->addressing_mode() == kMode_None) {
   1930           if (instr->InputAt(0)->IsRegister()) {
   1931             __ movl(i.OutputRegister(), i.InputRegister(0));
   1932           } else {
   1933             __ movl(i.OutputRegister(), i.InputOperand(0));
   1934           }
   1935         } else {
   1936           __ movl(i.OutputRegister(), i.MemoryOperand());
   1937         }
   1938         __ AssertZeroExtended(i.OutputRegister());
   1939       } else {
   1940         size_t index = 0;
   1941         Operand operand = i.MemoryOperand(&index);
   1942         if (HasImmediateInput(instr, index)) {
   1943           __ movl(operand, i.InputImmediate(index));
   1944         } else {
   1945           __ movl(operand, i.InputRegister(index));
   1946         }
   1947       }
   1948       break;
   1949     case kX64Movsxlq:
   1950       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1951                           __ pc_offset(), instr);
   1952       ASSEMBLE_MOVX(movsxlq);
   1953       break;
   1954     case kX64Movq:
   1955       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1956                           __ pc_offset(), instr);
   1957       if (instr->HasOutput()) {
   1958         __ movq(i.OutputRegister(), i.MemoryOperand());
   1959       } else {
   1960         size_t index = 0;
   1961         Operand operand = i.MemoryOperand(&index);
   1962         if (HasImmediateInput(instr, index)) {
   1963           __ movq(operand, i.InputImmediate(index));
   1964         } else {
   1965           __ movq(operand, i.InputRegister(index));
   1966         }
   1967       }
   1968       break;
   1969     case kX64Movss:
   1970       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1971                           __ pc_offset(), instr);
   1972       if (instr->HasOutput()) {
   1973         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
   1974       } else {
   1975         size_t index = 0;
   1976         Operand operand = i.MemoryOperand(&index);
   1977         __ movss(operand, i.InputDoubleRegister(index));
   1978       }
   1979       break;
   1980     case kX64Movsd:
   1981       EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
   1982                           __ pc_offset(), instr);
   1983       if (instr->HasOutput()) {
   1984         __ Movsd(i.OutputDoubleRegister(), i.MemoryOperand());
   1985       } else {
   1986         size_t index = 0;
   1987         Operand operand = i.MemoryOperand(&index);
   1988         __ Movsd(operand, i.InputDoubleRegister(index));
   1989       }
   1990       break;
   1991     case kX64BitcastFI:
   1992       if (instr->InputAt(0)->IsFPStackSlot()) {
   1993         __ movl(i.OutputRegister(), i.InputOperand(0));
   1994       } else {
   1995         __ Movd(i.OutputRegister(), i.InputDoubleRegister(0));
   1996       }
   1997       break;
   1998     case kX64BitcastDL:
   1999       if (instr->InputAt(0)->IsFPStackSlot()) {
   2000         __ movq(i.OutputRegister(), i.InputOperand(0));
   2001       } else {
   2002         __ Movq(i.OutputRegister(), i.InputDoubleRegister(0));
   2003       }
   2004       break;
   2005     case kX64BitcastIF:
   2006       if (instr->InputAt(0)->IsRegister()) {
   2007         __ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
   2008       } else {
   2009         __ movss(i.OutputDoubleRegister(), i.InputOperand(0));
   2010       }
   2011       break;
   2012     case kX64BitcastLD:
   2013       if (instr->InputAt(0)->IsRegister()) {
   2014         __ Movq(i.OutputDoubleRegister(), i.InputRegister(0));
   2015       } else {
   2016         __ Movsd(i.OutputDoubleRegister(), i.InputOperand(0));
   2017       }
   2018       break;
   2019     case kX64Lea32: {
   2020       AddressingMode mode = AddressingModeField::decode(instr->opcode());
   2021       // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
   2022       // and addressing mode just happens to work out. The "addl"/"subl" forms
   2023       // in these cases are faster based on measurements.
   2024       if (i.InputRegister(0).is(i.OutputRegister())) {
   2025         if (mode == kMode_MRI) {
   2026           int32_t constant_summand = i.InputInt32(1);
   2027           if (constant_summand > 0) {
   2028             __ addl(i.OutputRegister(), Immediate(constant_summand));
   2029           } else if (constant_summand < 0) {
   2030             __ subl(i.OutputRegister(), Immediate(-constant_summand));
   2031           }
   2032         } else if (mode == kMode_MR1) {
   2033           if (i.InputRegister(1).is(i.OutputRegister())) {
   2034             __ shll(i.OutputRegister(), Immediate(1));
   2035           } else {
   2036             __ addl(i.OutputRegister(), i.InputRegister(1));
   2037           }
   2038         } else if (mode == kMode_M2) {
   2039           __ shll(i.OutputRegister(), Immediate(1));
   2040         } else if (mode == kMode_M4) {
   2041           __ shll(i.OutputRegister(), Immediate(2));
   2042         } else if (mode == kMode_M8) {
   2043           __ shll(i.OutputRegister(), Immediate(3));
   2044         } else {
   2045           __ leal(i.OutputRegister(), i.MemoryOperand());
   2046         }
   2047       } else if (mode == kMode_MR1 &&
   2048                  i.InputRegister(1).is(i.OutputRegister())) {
   2049         __ addl(i.OutputRegister(), i.InputRegister(0));
   2050       } else {
   2051         __ leal(i.OutputRegister(), i.MemoryOperand());
   2052       }
   2053       __ AssertZeroExtended(i.OutputRegister());
   2054       break;
   2055     }
   2056     case kX64Lea: {
   2057       AddressingMode mode = AddressingModeField::decode(instr->opcode());
   2058       // Shorten "leaq" to "addq", "subq" or "shlq" if the register allocation
   2059       // and addressing mode just happens to work out. The "addq"/"subq" forms
   2060       // in these cases are faster based on measurements.
   2061       if (i.InputRegister(0).is(i.OutputRegister())) {
   2062         if (mode == kMode_MRI) {
   2063           int32_t constant_summand = i.InputInt32(1);
   2064           if (constant_summand > 0) {
   2065             __ addq(i.OutputRegister(), Immediate(constant_summand));
   2066           } else if (constant_summand < 0) {
   2067             __ subq(i.OutputRegister(), Immediate(-constant_summand));
   2068           }
   2069         } else if (mode == kMode_MR1) {
   2070           if (i.InputRegister(1).is(i.OutputRegister())) {
   2071             __ shlq(i.OutputRegister(), Immediate(1));
   2072           } else {
   2073             __ addq(i.OutputRegister(), i.InputRegister(1));
   2074           }
   2075         } else if (mode == kMode_M2) {
   2076           __ shlq(i.OutputRegister(), Immediate(1));
   2077         } else if (mode == kMode_M4) {
   2078           __ shlq(i.OutputRegister(), Immediate(2));
   2079         } else if (mode == kMode_M8) {
   2080           __ shlq(i.OutputRegister(), Immediate(3));
   2081         } else {
   2082           __ leaq(i.OutputRegister(), i.MemoryOperand());
   2083         }
   2084       } else if (mode == kMode_MR1 &&
   2085                  i.InputRegister(1).is(i.OutputRegister())) {
   2086         __ addq(i.OutputRegister(), i.InputRegister(0));
   2087       } else {
   2088         __ leaq(i.OutputRegister(), i.MemoryOperand());
   2089       }
   2090       break;
   2091     }
   2092     case kX64Dec32:
   2093       __ decl(i.OutputRegister());
   2094       break;
   2095     case kX64Inc32:
   2096       __ incl(i.OutputRegister());
   2097       break;
   2098     case kX64Push:
   2099       if (AddressingModeField::decode(instr->opcode()) != kMode_None) {
   2100         size_t index = 0;
   2101         Operand operand = i.MemoryOperand(&index);
   2102         __ pushq(operand);
   2103         frame_access_state()->IncreaseSPDelta(1);
   2104         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2105                                                          kPointerSize);
   2106       } else if (HasImmediateInput(instr, 0)) {
   2107         __ pushq(i.InputImmediate(0));
   2108         frame_access_state()->IncreaseSPDelta(1);
   2109         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2110                                                          kPointerSize);
   2111       } else if (instr->InputAt(0)->IsRegister()) {
   2112         __ pushq(i.InputRegister(0));
   2113         frame_access_state()->IncreaseSPDelta(1);
   2114         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2115                                                          kPointerSize);
   2116       } else if (instr->InputAt(0)->IsFPRegister()) {
   2117         // TODO(titzer): use another machine instruction?
   2118         __ subq(rsp, Immediate(kDoubleSize));
   2119         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   2120         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2121                                                          kDoubleSize);
   2122         __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
   2123       } else {
   2124         __ pushq(i.InputOperand(0));
   2125         frame_access_state()->IncreaseSPDelta(1);
   2126         unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2127                                                          kPointerSize);
   2128       }
   2129       break;
   2130     case kX64Poke: {
   2131       int const slot = MiscField::decode(instr->opcode());
   2132       if (HasImmediateInput(instr, 0)) {
   2133         __ movq(Operand(rsp, slot * kPointerSize), i.InputImmediate(0));
   2134       } else {
   2135         __ movq(Operand(rsp, slot * kPointerSize), i.InputRegister(0));
   2136       }
   2137       break;
   2138     }
   2139     case kX64Xchgb: {
   2140       size_t index = 0;
   2141       Operand operand = i.MemoryOperand(&index);
   2142       __ xchgb(i.InputRegister(index), operand);
   2143       break;
   2144     }
   2145     case kX64Xchgw: {
   2146       size_t index = 0;
   2147       Operand operand = i.MemoryOperand(&index);
   2148       __ xchgw(i.InputRegister(index), operand);
   2149       break;
   2150     }
   2151     case kX64Xchgl: {
   2152       size_t index = 0;
   2153       Operand operand = i.MemoryOperand(&index);
   2154       __ xchgl(i.InputRegister(index), operand);
   2155       break;
   2156     }
   2157     case kX64Int32x4Create: {
   2158       CpuFeatureScope sse_scope(masm(), SSE4_1);
   2159       XMMRegister dst = i.OutputSimd128Register();
   2160       __ Movd(dst, i.InputRegister(0));
   2161       __ shufps(dst, dst, 0x0);
   2162       break;
   2163     }
   2164     case kX64Int32x4ExtractLane: {
   2165       CpuFeatureScope sse_scope(masm(), SSE4_1);
   2166       __ Pextrd(i.OutputRegister(), i.InputSimd128Register(0), i.InputInt8(1));
   2167       break;
   2168     }
   2169     case kX64Int32x4ReplaceLane: {
   2170       CpuFeatureScope sse_scope(masm(), SSE4_1);
   2171       if (instr->InputAt(2)->IsRegister()) {
   2172         __ Pinsrd(i.OutputSimd128Register(), i.InputRegister(2),
   2173                   i.InputInt8(1));
   2174       } else {
   2175         __ Pinsrd(i.OutputSimd128Register(), i.InputOperand(2), i.InputInt8(1));
   2176       }
   2177       break;
   2178     }
   2179     case kX64Int32x4Add: {
   2180       CpuFeatureScope sse_scope(masm(), SSE4_1);
   2181       __ paddd(i.OutputSimd128Register(), i.InputSimd128Register(1));
   2182       break;
   2183     }
   2184     case kX64Int32x4Sub: {
   2185       CpuFeatureScope sse_scope(masm(), SSE4_1);
   2186       __ psubd(i.OutputSimd128Register(), i.InputSimd128Register(1));
   2187       break;
   2188     }
   2189     case kCheckedLoadInt8:
   2190       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
   2191       break;
   2192     case kCheckedLoadUint8:
   2193       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
   2194       break;
   2195     case kCheckedLoadInt16:
   2196       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
   2197       break;
   2198     case kCheckedLoadUint16:
   2199       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
   2200       break;
   2201     case kCheckedLoadWord32:
   2202       ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
   2203       break;
   2204     case kCheckedLoadWord64:
   2205       ASSEMBLE_CHECKED_LOAD_INTEGER(movq);
   2206       break;
   2207     case kCheckedLoadFloat32:
   2208       ASSEMBLE_CHECKED_LOAD_FLOAT(Movss, OutOfLineLoadFloat32NaN);
   2209       break;
   2210     case kCheckedLoadFloat64:
   2211       ASSEMBLE_CHECKED_LOAD_FLOAT(Movsd, OutOfLineLoadFloat64NaN);
   2212       break;
   2213     case kCheckedStoreWord8:
   2214       ASSEMBLE_CHECKED_STORE_INTEGER(movb);
   2215       break;
   2216     case kCheckedStoreWord16:
   2217       ASSEMBLE_CHECKED_STORE_INTEGER(movw);
   2218       break;
   2219     case kCheckedStoreWord32:
   2220       ASSEMBLE_CHECKED_STORE_INTEGER(movl);
   2221       break;
   2222     case kCheckedStoreWord64:
   2223       ASSEMBLE_CHECKED_STORE_INTEGER(movq);
   2224       break;
   2225     case kCheckedStoreFloat32:
   2226       ASSEMBLE_CHECKED_STORE_FLOAT(Movss);
   2227       break;
   2228     case kCheckedStoreFloat64:
   2229       ASSEMBLE_CHECKED_STORE_FLOAT(Movsd);
   2230       break;
   2231     case kX64StackCheck:
   2232       __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
   2233       break;
   2234     case kAtomicLoadInt8:
   2235     case kAtomicLoadUint8:
   2236     case kAtomicLoadInt16:
   2237     case kAtomicLoadUint16:
   2238     case kAtomicLoadWord32:
   2239     case kAtomicStoreWord8:
   2240     case kAtomicStoreWord16:
   2241     case kAtomicStoreWord32:
   2242       UNREACHABLE();  // Won't be generated by instruction selector.
   2243       break;
   2244   }
   2245   return kSuccess;
   2246 }  // NOLINT(readability/fn_size)
   2247 
   2248 namespace {
   2249 
   2250 Condition FlagsConditionToCondition(FlagsCondition condition) {
   2251   switch (condition) {
   2252     case kUnorderedEqual:
   2253     case kEqual:
   2254       return equal;
   2255     case kUnorderedNotEqual:
   2256     case kNotEqual:
   2257       return not_equal;
   2258     case kSignedLessThan:
   2259       return less;
   2260     case kSignedGreaterThanOrEqual:
   2261       return greater_equal;
   2262     case kSignedLessThanOrEqual:
   2263       return less_equal;
   2264     case kSignedGreaterThan:
   2265       return greater;
   2266     case kUnsignedLessThan:
   2267       return below;
   2268     case kUnsignedGreaterThanOrEqual:
   2269       return above_equal;
   2270     case kUnsignedLessThanOrEqual:
   2271       return below_equal;
   2272     case kUnsignedGreaterThan:
   2273       return above;
   2274     case kOverflow:
   2275       return overflow;
   2276     case kNotOverflow:
   2277       return no_overflow;
   2278     default:
   2279       break;
   2280   }
   2281   UNREACHABLE();
   2282   return no_condition;
   2283 }
   2284 
   2285 }  // namespace
   2286 
   2287 // Assembles branches after this instruction.
   2288 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   2289   Label::Distance flabel_distance =
   2290       branch->fallthru ? Label::kNear : Label::kFar;
   2291   Label* tlabel = branch->true_label;
   2292   Label* flabel = branch->false_label;
   2293   if (branch->condition == kUnorderedEqual) {
   2294     __ j(parity_even, flabel, flabel_distance);
   2295   } else if (branch->condition == kUnorderedNotEqual) {
   2296     __ j(parity_even, tlabel);
   2297   }
   2298   __ j(FlagsConditionToCondition(branch->condition), tlabel);
   2299 
   2300   if (!branch->fallthru) __ jmp(flabel, flabel_distance);
   2301 }
   2302 
   2303 
   2304 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   2305   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
   2306 }
   2307 
   2308 void CodeGenerator::AssembleArchTrap(Instruction* instr,
   2309                                      FlagsCondition condition) {
   2310   class OutOfLineTrap final : public OutOfLineCode {
   2311    public:
   2312     OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
   2313         : OutOfLineCode(gen),
   2314           frame_elided_(frame_elided),
   2315           instr_(instr),
   2316           gen_(gen) {}
   2317 
   2318     void Generate() final {
   2319       X64OperandConverter i(gen_, instr_);
   2320 
   2321       Builtins::Name trap_id =
   2322           static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
   2323       bool old_has_frame = __ has_frame();
   2324       if (frame_elided_) {
   2325         __ set_has_frame(true);
   2326         __ EnterFrame(StackFrame::WASM_COMPILED);
   2327       }
   2328       GenerateCallToTrap(trap_id);
   2329       if (frame_elided_) {
   2330         __ set_has_frame(old_has_frame);
   2331       }
   2332     }
   2333 
   2334    private:
   2335     void GenerateCallToTrap(Builtins::Name trap_id) {
   2336       if (trap_id == Builtins::builtin_count) {
   2337         // We cannot test calls to the runtime in cctest/test-run-wasm.
   2338         // Therefore we emit a call to C here instead of a call to the runtime.
   2339         __ PrepareCallCFunction(0);
   2340         __ CallCFunction(
   2341             ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
   2342             0);
   2343         __ LeaveFrame(StackFrame::WASM_COMPILED);
   2344         __ Ret();
   2345       } else {
   2346         gen_->AssembleSourcePosition(instr_);
   2347         __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()),
   2348                 RelocInfo::CODE_TARGET);
   2349         ReferenceMap* reference_map =
   2350             new (gen_->zone()) ReferenceMap(gen_->zone());
   2351         gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
   2352                               Safepoint::kNoLazyDeopt);
   2353         if (FLAG_debug_code) {
   2354           __ ud2();
   2355         }
   2356       }
   2357     }
   2358 
   2359     bool frame_elided_;
   2360     Instruction* instr_;
   2361     CodeGenerator* gen_;
   2362   };
   2363   bool frame_elided = !frame_access_state()->has_frame();
   2364   auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
   2365   Label* tlabel = ool->entry();
   2366   Label end;
   2367   if (condition == kUnorderedEqual) {
   2368     __ j(parity_even, &end);
   2369   } else if (condition == kUnorderedNotEqual) {
   2370     __ j(parity_even, tlabel);
   2371   }
   2372   __ j(FlagsConditionToCondition(condition), tlabel);
   2373   __ bind(&end);
   2374 }
   2375 
   2376 // Assembles boolean materializations after this instruction.
   2377 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   2378                                         FlagsCondition condition) {
   2379   X64OperandConverter i(this, instr);
   2380   Label done;
   2381 
   2382   // Materialize a full 64-bit 1 or 0 value. The result register is always the
   2383   // last output of the instruction.
   2384   Label check;
   2385   DCHECK_NE(0u, instr->OutputCount());
   2386   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   2387   if (condition == kUnorderedEqual) {
   2388     __ j(parity_odd, &check, Label::kNear);
   2389     __ movl(reg, Immediate(0));
   2390     __ jmp(&done, Label::kNear);
   2391   } else if (condition == kUnorderedNotEqual) {
   2392     __ j(parity_odd, &check, Label::kNear);
   2393     __ movl(reg, Immediate(1));
   2394     __ jmp(&done, Label::kNear);
   2395   }
   2396   __ bind(&check);
   2397   __ setcc(FlagsConditionToCondition(condition), reg);
   2398   __ movzxbl(reg, reg);
   2399   __ bind(&done);
   2400 }
   2401 
   2402 
   2403 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   2404   X64OperandConverter i(this, instr);
   2405   Register input = i.InputRegister(0);
   2406   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   2407     __ cmpl(input, Immediate(i.InputInt32(index + 0)));
   2408     __ j(equal, GetLabel(i.InputRpo(index + 1)));
   2409   }
   2410   AssembleArchJump(i.InputRpo(1));
   2411 }
   2412 
   2413 
   2414 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   2415   X64OperandConverter i(this, instr);
   2416   Register input = i.InputRegister(0);
   2417   int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
   2418   Label** cases = zone()->NewArray<Label*>(case_count);
   2419   for (int32_t index = 0; index < case_count; ++index) {
   2420     cases[index] = GetLabel(i.InputRpo(index + 2));
   2421   }
   2422   Label* const table = AddJumpTable(cases, case_count);
   2423   __ cmpl(input, Immediate(case_count));
   2424   __ j(above_equal, GetLabel(i.InputRpo(1)));
   2425   __ leaq(kScratchRegister, Operand(table));
   2426   __ jmp(Operand(kScratchRegister, input, times_8, 0));
   2427 }
   2428 
   2429 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
   2430     int deoptimization_id, SourcePosition pos) {
   2431   DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
   2432   DeoptimizeReason deoptimization_reason =
   2433       GetDeoptimizationReason(deoptimization_id);
   2434   Deoptimizer::BailoutType bailout_type =
   2435       deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
   2436                                                    : Deoptimizer::EAGER;
   2437   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   2438       isolate(), deoptimization_id, bailout_type);
   2439   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
   2440   __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
   2441   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   2442   return kSuccess;
   2443 }
   2444 
   2445 
   2446 namespace {
   2447 
   2448 static const int kQuadWordSize = 16;
   2449 
   2450 }  // namespace
   2451 
   2452 void CodeGenerator::FinishFrame(Frame* frame) {
   2453   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2454 
   2455   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2456   if (saves_fp != 0) {
   2457     frame->AlignSavedCalleeRegisterSlots();
   2458     if (saves_fp != 0) {  // Save callee-saved XMM registers.
   2459       const uint32_t saves_fp_count = base::bits::CountPopulation32(saves_fp);
   2460       frame->AllocateSavedCalleeRegisterSlots(saves_fp_count *
   2461                                               (kQuadWordSize / kPointerSize));
   2462     }
   2463   }
   2464   const RegList saves = descriptor->CalleeSavedRegisters();
   2465   if (saves != 0) {  // Save callee-saved registers.
   2466     int count = 0;
   2467     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
   2468       if (((1 << i) & saves)) {
   2469         ++count;
   2470       }
   2471     }
   2472     frame->AllocateSavedCalleeRegisterSlots(count);
   2473   }
   2474 }
   2475 
   2476 void CodeGenerator::AssembleConstructFrame() {
   2477   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2478   if (frame_access_state()->has_frame()) {
   2479     int pc_base = __ pc_offset();
   2480 
   2481     if (descriptor->IsCFunctionCall()) {
   2482       __ pushq(rbp);
   2483       __ movq(rbp, rsp);
   2484     } else if (descriptor->IsJSFunctionCall()) {
   2485       __ Prologue(this->info()->GeneratePreagedPrologue());
   2486       if (descriptor->PushArgumentCount()) {
   2487         __ pushq(kJavaScriptCallArgCountRegister);
   2488       }
   2489     } else {
   2490       __ StubPrologue(info()->GetOutputStackFrameType());
   2491     }
   2492 
   2493     if (!descriptor->IsJSFunctionCall() || !info()->GeneratePreagedPrologue()) {
   2494       unwinding_info_writer_.MarkFrameConstructed(pc_base);
   2495     }
   2496   }
   2497   int shrink_slots =
   2498       frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
   2499 
   2500   if (info()->is_osr()) {
   2501     // TurboFan OSR-compiled functions cannot be entered directly.
   2502     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   2503 
   2504     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   2505     // frame is still on the stack. Optimized code uses OSR values directly from
   2506     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   2507     // remaining stack slots.
   2508     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   2509     osr_pc_offset_ = __ pc_offset();
   2510     shrink_slots -= static_cast<int>(OsrHelper(info()).UnoptimizedFrameSlots());
   2511   }
   2512 
   2513   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2514   if (shrink_slots > 0) {
   2515     __ subq(rsp, Immediate(shrink_slots * kPointerSize));
   2516   }
   2517 
   2518   if (saves_fp != 0) {  // Save callee-saved XMM registers.
   2519     const uint32_t saves_fp_count = base::bits::CountPopulation32(saves_fp);
   2520     const int stack_size = saves_fp_count * kQuadWordSize;
   2521     // Adjust the stack pointer.
   2522     __ subp(rsp, Immediate(stack_size));
   2523     // Store the registers on the stack.
   2524     int slot_idx = 0;
   2525     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   2526       if (!((1 << i) & saves_fp)) continue;
   2527       __ movdqu(Operand(rsp, kQuadWordSize * slot_idx),
   2528                 XMMRegister::from_code(i));
   2529       slot_idx++;
   2530     }
   2531   }
   2532 
   2533   const RegList saves = descriptor->CalleeSavedRegisters();
   2534   if (saves != 0) {  // Save callee-saved registers.
   2535     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
   2536       if (!((1 << i) & saves)) continue;
   2537       __ pushq(Register::from_code(i));
   2538     }
   2539   }
   2540 }
   2541 
   2542 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
   2543   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2544 
   2545   // Restore registers.
   2546   const RegList saves = descriptor->CalleeSavedRegisters();
   2547   if (saves != 0) {
   2548     for (int i = 0; i < Register::kNumRegisters; i++) {
   2549       if (!((1 << i) & saves)) continue;
   2550       __ popq(Register::from_code(i));
   2551     }
   2552   }
   2553   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   2554   if (saves_fp != 0) {
   2555     const uint32_t saves_fp_count = base::bits::CountPopulation32(saves_fp);
   2556     const int stack_size = saves_fp_count * kQuadWordSize;
   2557     // Load the registers from the stack.
   2558     int slot_idx = 0;
   2559     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   2560       if (!((1 << i) & saves_fp)) continue;
   2561       __ movdqu(XMMRegister::from_code(i),
   2562                 Operand(rsp, kQuadWordSize * slot_idx));
   2563       slot_idx++;
   2564     }
   2565     // Adjust the stack pointer.
   2566     __ addp(rsp, Immediate(stack_size));
   2567   }
   2568 
   2569   unwinding_info_writer_.MarkBlockWillExit();
   2570 
   2571   // Might need rcx for scratch if pop_size is too big or if there is a variable
   2572   // pop count.
   2573   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & rcx.bit());
   2574   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & rdx.bit());
   2575   size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
   2576   X64OperandConverter g(this, nullptr);
   2577   if (descriptor->IsCFunctionCall()) {
   2578     AssembleDeconstructFrame();
   2579   } else if (frame_access_state()->has_frame()) {
   2580     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
   2581       // Canonicalize JSFunction return sites for now.
   2582       if (return_label_.is_bound()) {
   2583         __ jmp(&return_label_);
   2584         return;
   2585       } else {
   2586         __ bind(&return_label_);
   2587         AssembleDeconstructFrame();
   2588       }
   2589     } else {
   2590       AssembleDeconstructFrame();
   2591     }
   2592   }
   2593 
   2594   if (pop->IsImmediate()) {
   2595     DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
   2596     pop_size += g.ToConstant(pop).ToInt32() * kPointerSize;
   2597     CHECK_LT(pop_size, static_cast<size_t>(std::numeric_limits<int>::max()));
   2598     __ Ret(static_cast<int>(pop_size), rcx);
   2599   } else {
   2600     Register pop_reg = g.ToRegister(pop);
   2601     Register scratch_reg = pop_reg.is(rcx) ? rdx : rcx;
   2602     __ popq(scratch_reg);
   2603     __ leaq(rsp, Operand(rsp, pop_reg, times_8, static_cast<int>(pop_size)));
   2604     __ jmp(scratch_reg);
   2605   }
   2606 }
   2607 
   2608 
   2609 void CodeGenerator::AssembleMove(InstructionOperand* source,
   2610                                  InstructionOperand* destination) {
   2611   X64OperandConverter g(this, nullptr);
   2612   // Dispatch on the source and destination operand kinds.  Not all
   2613   // combinations are possible.
   2614   if (source->IsRegister()) {
   2615     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2616     Register src = g.ToRegister(source);
   2617     if (destination->IsRegister()) {
   2618       __ movq(g.ToRegister(destination), src);
   2619     } else {
   2620       __ movq(g.ToOperand(destination), src);
   2621     }
   2622   } else if (source->IsStackSlot()) {
   2623     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2624     Operand src = g.ToOperand(source);
   2625     if (destination->IsRegister()) {
   2626       Register dst = g.ToRegister(destination);
   2627       __ movq(dst, src);
   2628     } else {
   2629       // Spill on demand to use a temporary register for memory-to-memory
   2630       // moves.
   2631       Register tmp = kScratchRegister;
   2632       Operand dst = g.ToOperand(destination);
   2633       __ movq(tmp, src);
   2634       __ movq(dst, tmp);
   2635     }
   2636   } else if (source->IsConstant()) {
   2637     ConstantOperand* constant_source = ConstantOperand::cast(source);
   2638     Constant src = g.ToConstant(constant_source);
   2639     if (destination->IsRegister() || destination->IsStackSlot()) {
   2640       Register dst = destination->IsRegister() ? g.ToRegister(destination)
   2641                                                : kScratchRegister;
   2642       switch (src.type()) {
   2643         case Constant::kInt32: {
   2644           if (RelocInfo::IsWasmPtrReference(src.rmode())) {
   2645             __ movq(dst, src.ToInt64(), src.rmode());
   2646           } else {
   2647             // TODO(dcarney): don't need scratch in this case.
   2648             int32_t value = src.ToInt32();
   2649             if (value == 0) {
   2650               __ xorl(dst, dst);
   2651             } else {
   2652               if (RelocInfo::IsWasmSizeReference(src.rmode())) {
   2653                 __ movl(dst, Immediate(value, src.rmode()));
   2654               } else {
   2655                 __ movl(dst, Immediate(value));
   2656               }
   2657             }
   2658           }
   2659           break;
   2660         }
   2661         case Constant::kInt64:
   2662           if (RelocInfo::IsWasmPtrReference(src.rmode())) {
   2663             __ movq(dst, src.ToInt64(), src.rmode());
   2664           } else {
   2665             DCHECK(!RelocInfo::IsWasmSizeReference(src.rmode()));
   2666             __ Set(dst, src.ToInt64());
   2667           }
   2668           break;
   2669         case Constant::kFloat32:
   2670           __ Move(dst,
   2671                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   2672           break;
   2673         case Constant::kFloat64:
   2674           __ Move(dst,
   2675                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   2676           break;
   2677         case Constant::kExternalReference:
   2678           __ Move(dst, src.ToExternalReference());
   2679           break;
   2680         case Constant::kHeapObject: {
   2681           Handle<HeapObject> src_object = src.ToHeapObject();
   2682           Heap::RootListIndex index;
   2683           if (IsMaterializableFromRoot(src_object, &index)) {
   2684             __ LoadRoot(dst, index);
   2685           } else {
   2686             __ Move(dst, src_object);
   2687           }
   2688           break;
   2689         }
   2690         case Constant::kRpoNumber:
   2691           UNREACHABLE();  // TODO(dcarney): load of labels on x64.
   2692           break;
   2693       }
   2694       if (destination->IsStackSlot()) {
   2695         __ movq(g.ToOperand(destination), kScratchRegister);
   2696       }
   2697     } else if (src.type() == Constant::kFloat32) {
   2698       // TODO(turbofan): Can we do better here?
   2699       uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
   2700       if (destination->IsFPRegister()) {
   2701         __ Move(g.ToDoubleRegister(destination), src_const);
   2702       } else {
   2703         DCHECK(destination->IsFPStackSlot());
   2704         Operand dst = g.ToOperand(destination);
   2705         __ movl(dst, Immediate(src_const));
   2706       }
   2707     } else {
   2708       DCHECK_EQ(Constant::kFloat64, src.type());
   2709       uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
   2710       if (destination->IsFPRegister()) {
   2711         __ Move(g.ToDoubleRegister(destination), src_const);
   2712       } else {
   2713         DCHECK(destination->IsFPStackSlot());
   2714         __ movq(kScratchRegister, src_const);
   2715         __ movq(g.ToOperand(destination), kScratchRegister);
   2716       }
   2717     }
   2718   } else if (source->IsFPRegister()) {
   2719     XMMRegister src = g.ToDoubleRegister(source);
   2720     if (destination->IsFPRegister()) {
   2721       XMMRegister dst = g.ToDoubleRegister(destination);
   2722       __ Movapd(dst, src);
   2723     } else {
   2724       DCHECK(destination->IsFPStackSlot());
   2725       Operand dst = g.ToOperand(destination);
   2726       MachineRepresentation rep =
   2727           LocationOperand::cast(source)->representation();
   2728       if (rep != MachineRepresentation::kSimd128) {
   2729         __ Movsd(dst, src);
   2730       } else {
   2731         __ Movups(dst, src);
   2732       }
   2733     }
   2734   } else if (source->IsFPStackSlot()) {
   2735     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
   2736     Operand src = g.ToOperand(source);
   2737     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2738     if (destination->IsFPRegister()) {
   2739       XMMRegister dst = g.ToDoubleRegister(destination);
   2740       if (rep != MachineRepresentation::kSimd128) {
   2741         __ Movsd(dst, src);
   2742       } else {
   2743         __ Movups(dst, src);
   2744       }
   2745     } else {
   2746       Operand dst = g.ToOperand(destination);
   2747       if (rep != MachineRepresentation::kSimd128) {
   2748         __ Movsd(kScratchDoubleReg, src);
   2749         __ Movsd(dst, kScratchDoubleReg);
   2750       } else {
   2751         __ Movups(kScratchDoubleReg, src);
   2752         __ Movups(dst, kScratchDoubleReg);
   2753       }
   2754     }
   2755   } else {
   2756     UNREACHABLE();
   2757   }
   2758 }
   2759 
   2760 
   2761 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   2762                                  InstructionOperand* destination) {
   2763   X64OperandConverter g(this, nullptr);
   2764   // Dispatch on the source and destination operand kinds.  Not all
   2765   // combinations are possible.
   2766   if (source->IsRegister() && destination->IsRegister()) {
   2767     // Register-register.
   2768     Register src = g.ToRegister(source);
   2769     Register dst = g.ToRegister(destination);
   2770     __ movq(kScratchRegister, src);
   2771     __ movq(src, dst);
   2772     __ movq(dst, kScratchRegister);
   2773   } else if (source->IsRegister() && destination->IsStackSlot()) {
   2774     Register src = g.ToRegister(source);
   2775     __ pushq(src);
   2776     frame_access_state()->IncreaseSPDelta(1);
   2777     unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2778                                                      kPointerSize);
   2779     Operand dst = g.ToOperand(destination);
   2780     __ movq(src, dst);
   2781     frame_access_state()->IncreaseSPDelta(-1);
   2782     dst = g.ToOperand(destination);
   2783     __ popq(dst);
   2784     unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2785                                                      -kPointerSize);
   2786   } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
   2787              (source->IsFPStackSlot() && destination->IsFPStackSlot())) {
   2788     // Memory-memory.
   2789     Operand src = g.ToOperand(source);
   2790     Operand dst = g.ToOperand(destination);
   2791     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2792     if (rep != MachineRepresentation::kSimd128) {
   2793       Register tmp = kScratchRegister;
   2794       __ movq(tmp, dst);
   2795       __ pushq(src);
   2796       unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2797                                                        kPointerSize);
   2798       frame_access_state()->IncreaseSPDelta(1);
   2799       src = g.ToOperand(source);
   2800       __ movq(src, tmp);
   2801       frame_access_state()->IncreaseSPDelta(-1);
   2802       dst = g.ToOperand(destination);
   2803       __ popq(dst);
   2804       unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
   2805                                                        -kPointerSize);
   2806     } else {
   2807       // Use the XOR trick to swap without a temporary.
   2808       __ Movups(kScratchDoubleReg, src);
   2809       __ Xorps(kScratchDoubleReg, dst);  // scratch contains src ^ dst.
   2810       __ Movups(src, kScratchDoubleReg);
   2811       __ Xorps(kScratchDoubleReg, dst);  // scratch contains src.
   2812       __ Movups(dst, kScratchDoubleReg);
   2813       __ Xorps(kScratchDoubleReg, src);  // scratch contains dst.
   2814       __ Movups(src, kScratchDoubleReg);
   2815     }
   2816   } else if (source->IsFPRegister() && destination->IsFPRegister()) {
   2817     // XMM register-register swap.
   2818     XMMRegister src = g.ToDoubleRegister(source);
   2819     XMMRegister dst = g.ToDoubleRegister(destination);
   2820     __ Movapd(kScratchDoubleReg, src);
   2821     __ Movapd(src, dst);
   2822     __ Movapd(dst, kScratchDoubleReg);
   2823   } else if (source->IsFPRegister() && destination->IsFPStackSlot()) {
   2824     // XMM register-memory swap.
   2825     XMMRegister src = g.ToDoubleRegister(source);
   2826     Operand dst = g.ToOperand(destination);
   2827     MachineRepresentation rep = LocationOperand::cast(source)->representation();
   2828     if (rep != MachineRepresentation::kSimd128) {
   2829       __ Movsd(kScratchDoubleReg, src);
   2830       __ Movsd(src, dst);
   2831       __ Movsd(dst, kScratchDoubleReg);
   2832     } else {
   2833       __ Movups(kScratchDoubleReg, src);
   2834       __ Movups(src, dst);
   2835       __ Movups(dst, kScratchDoubleReg);
   2836     }
   2837   } else {
   2838     // No other combinations are possible.
   2839     UNREACHABLE();
   2840   }
   2841 }
   2842 
   2843 
   2844 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   2845   for (size_t index = 0; index < target_count; ++index) {
   2846     __ dq(targets[index]);
   2847   }
   2848 }
   2849 
   2850 
   2851 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   2852   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   2853     return;
   2854   }
   2855 
   2856   int space_needed = Deoptimizer::patch_size();
   2857   // Ensure that we have enough space after the previous lazy-bailout
   2858   // instruction for patching the code here.
   2859   int current_pc = __ pc_offset();
   2860   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   2861     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   2862     __ Nop(padding_size);
   2863   }
   2864 }
   2865 
   2866 #undef __
   2867 
   2868 }  // namespace compiler
   2869 }  // namespace internal
   2870 }  // namespace v8
   2871