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 "src/ast/scopes.h"
      8 #include "src/compiler/code-generator-impl.h"
      9 #include "src/compiler/gap-resolver.h"
     10 #include "src/compiler/node-matchers.h"
     11 #include "src/compiler/osr.h"
     12 #include "src/x64/assembler-x64.h"
     13 #include "src/x64/macro-assembler-x64.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 #define __ masm()->
     20 
     21 
     22 #define kScratchDoubleReg xmm0
     23 
     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     return Immediate(constant.ToInt32());
     48   }
     49 
     50   Operand ToOperand(InstructionOperand* op, int extra = 0) {
     51     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
     52     FrameOffset offset = frame_access_state()->GetFrameOffset(
     53         AllocatedOperand::cast(op)->index());
     54     return Operand(offset.from_stack_pointer() ? rsp : rbp,
     55                    offset.offset() + extra);
     56   }
     57 
     58   static size_t NextOffset(size_t* offset) {
     59     size_t i = *offset;
     60     (*offset)++;
     61     return i;
     62   }
     63 
     64   static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
     65     STATIC_ASSERT(0 == static_cast<int>(times_1));
     66     STATIC_ASSERT(1 == static_cast<int>(times_2));
     67     STATIC_ASSERT(2 == static_cast<int>(times_4));
     68     STATIC_ASSERT(3 == static_cast<int>(times_8));
     69     int scale = static_cast<int>(mode - one);
     70     DCHECK(scale >= 0 && scale < 4);
     71     return static_cast<ScaleFactor>(scale);
     72   }
     73 
     74   Operand MemoryOperand(size_t* offset) {
     75     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
     76     switch (mode) {
     77       case kMode_MR: {
     78         Register base = InputRegister(NextOffset(offset));
     79         int32_t disp = 0;
     80         return Operand(base, disp);
     81       }
     82       case kMode_MRI: {
     83         Register base = InputRegister(NextOffset(offset));
     84         int32_t disp = InputInt32(NextOffset(offset));
     85         return Operand(base, disp);
     86       }
     87       case kMode_MR1:
     88       case kMode_MR2:
     89       case kMode_MR4:
     90       case kMode_MR8: {
     91         Register base = InputRegister(NextOffset(offset));
     92         Register index = InputRegister(NextOffset(offset));
     93         ScaleFactor scale = ScaleFor(kMode_MR1, mode);
     94         int32_t disp = 0;
     95         return Operand(base, index, scale, disp);
     96       }
     97       case kMode_MR1I:
     98       case kMode_MR2I:
     99       case kMode_MR4I:
    100       case kMode_MR8I: {
    101         Register base = InputRegister(NextOffset(offset));
    102         Register index = InputRegister(NextOffset(offset));
    103         ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
    104         int32_t disp = InputInt32(NextOffset(offset));
    105         return Operand(base, index, scale, disp);
    106       }
    107       case kMode_M1: {
    108         Register base = InputRegister(NextOffset(offset));
    109         int32_t disp = 0;
    110         return Operand(base, disp);
    111       }
    112       case kMode_M2:
    113         UNREACHABLE();  // Should use kModeMR with more compact encoding instead
    114         return Operand(no_reg, 0);
    115       case kMode_M4:
    116       case kMode_M8: {
    117         Register index = InputRegister(NextOffset(offset));
    118         ScaleFactor scale = ScaleFor(kMode_M1, mode);
    119         int32_t disp = 0;
    120         return Operand(index, scale, disp);
    121       }
    122       case kMode_M1I:
    123       case kMode_M2I:
    124       case kMode_M4I:
    125       case kMode_M8I: {
    126         Register index = InputRegister(NextOffset(offset));
    127         ScaleFactor scale = ScaleFor(kMode_M1I, mode);
    128         int32_t disp = InputInt32(NextOffset(offset));
    129         return Operand(index, scale, disp);
    130       }
    131       case kMode_None:
    132         UNREACHABLE();
    133         return Operand(no_reg, 0);
    134     }
    135     UNREACHABLE();
    136     return Operand(no_reg, 0);
    137   }
    138 
    139   Operand MemoryOperand(size_t first_input = 0) {
    140     return MemoryOperand(&first_input);
    141   }
    142 };
    143 
    144 
    145 namespace {
    146 
    147 bool HasImmediateInput(Instruction* instr, size_t index) {
    148   return instr->InputAt(index)->IsImmediate();
    149 }
    150 
    151 
    152 class OutOfLineLoadZero final : public OutOfLineCode {
    153  public:
    154   OutOfLineLoadZero(CodeGenerator* gen, Register result)
    155       : OutOfLineCode(gen), result_(result) {}
    156 
    157   void Generate() final { __ xorl(result_, result_); }
    158 
    159  private:
    160   Register const result_;
    161 };
    162 
    163 
    164 class OutOfLineLoadNaN final : public OutOfLineCode {
    165  public:
    166   OutOfLineLoadNaN(CodeGenerator* gen, XMMRegister result)
    167       : OutOfLineCode(gen), result_(result) {}
    168 
    169   void Generate() final { __ Pcmpeqd(result_, result_); }
    170 
    171  private:
    172   XMMRegister const result_;
    173 };
    174 
    175 
    176 class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
    177  public:
    178   OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
    179                              XMMRegister input)
    180       : OutOfLineCode(gen), result_(result), input_(input) {}
    181 
    182   void Generate() final {
    183     __ subp(rsp, Immediate(kDoubleSize));
    184     __ Movsd(MemOperand(rsp, 0), input_);
    185     __ SlowTruncateToI(result_, rsp, 0);
    186     __ addp(rsp, Immediate(kDoubleSize));
    187   }
    188 
    189  private:
    190   Register const result_;
    191   XMMRegister const input_;
    192 };
    193 
    194 
    195 class OutOfLineRecordWrite final : public OutOfLineCode {
    196  public:
    197   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
    198                        Register value, Register scratch0, Register scratch1,
    199                        RecordWriteMode mode)
    200       : OutOfLineCode(gen),
    201         object_(object),
    202         operand_(operand),
    203         value_(value),
    204         scratch0_(scratch0),
    205         scratch1_(scratch1),
    206         mode_(mode) {}
    207 
    208   void Generate() final {
    209     if (mode_ > RecordWriteMode::kValueIsPointer) {
    210       __ JumpIfSmi(value_, exit());
    211     }
    212     if (mode_ > RecordWriteMode::kValueIsMap) {
    213       __ CheckPageFlag(value_, scratch0_,
    214                        MemoryChunk::kPointersToHereAreInterestingMask, zero,
    215                        exit());
    216     }
    217     SaveFPRegsMode const save_fp_mode =
    218         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    219     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    220                          EMIT_REMEMBERED_SET, save_fp_mode);
    221     __ leap(scratch1_, operand_);
    222     __ CallStub(&stub);
    223   }
    224 
    225  private:
    226   Register const object_;
    227   Operand const operand_;
    228   Register const value_;
    229   Register const scratch0_;
    230   Register const scratch1_;
    231   RecordWriteMode const mode_;
    232 };
    233 
    234 }  // namespace
    235 
    236 
    237 #define ASSEMBLE_UNOP(asm_instr)         \
    238   do {                                   \
    239     if (instr->Output()->IsRegister()) { \
    240       __ asm_instr(i.OutputRegister());  \
    241     } else {                             \
    242       __ asm_instr(i.OutputOperand());   \
    243     }                                    \
    244   } while (0)
    245 
    246 
    247 #define ASSEMBLE_BINOP(asm_instr)                              \
    248   do {                                                         \
    249     if (HasImmediateInput(instr, 1)) {                         \
    250       if (instr->InputAt(0)->IsRegister()) {                   \
    251         __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
    252       } else {                                                 \
    253         __ asm_instr(i.InputOperand(0), i.InputImmediate(1));  \
    254       }                                                        \
    255     } else {                                                   \
    256       if (instr->InputAt(1)->IsRegister()) {                   \
    257         __ asm_instr(i.InputRegister(0), i.InputRegister(1));  \
    258       } else {                                                 \
    259         __ asm_instr(i.InputRegister(0), i.InputOperand(1));   \
    260       }                                                        \
    261     }                                                          \
    262   } while (0)
    263 
    264 
    265 #define ASSEMBLE_MULT(asm_instr)                              \
    266   do {                                                        \
    267     if (HasImmediateInput(instr, 1)) {                        \
    268       if (instr->InputAt(0)->IsRegister()) {                  \
    269         __ asm_instr(i.OutputRegister(), i.InputRegister(0),  \
    270                      i.InputImmediate(1));                    \
    271       } else {                                                \
    272         __ asm_instr(i.OutputRegister(), i.InputOperand(0),   \
    273                      i.InputImmediate(1));                    \
    274       }                                                       \
    275     } else {                                                  \
    276       if (instr->InputAt(1)->IsRegister()) {                  \
    277         __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
    278       } else {                                                \
    279         __ asm_instr(i.OutputRegister(), i.InputOperand(1));  \
    280       }                                                       \
    281     }                                                         \
    282   } while (0)
    283 
    284 
    285 #define ASSEMBLE_SHIFT(asm_instr, width)                                   \
    286   do {                                                                     \
    287     if (HasImmediateInput(instr, 1)) {                                     \
    288       if (instr->Output()->IsRegister()) {                                 \
    289         __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
    290       } else {                                                             \
    291         __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1)));  \
    292       }                                                                    \
    293     } else {                                                               \
    294       if (instr->Output()->IsRegister()) {                                 \
    295         __ asm_instr##_cl(i.OutputRegister());                             \
    296       } else {                                                             \
    297         __ asm_instr##_cl(i.OutputOperand());                              \
    298       }                                                                    \
    299     }                                                                      \
    300   } while (0)
    301 
    302 
    303 #define ASSEMBLE_MOVX(asm_instr)                            \
    304   do {                                                      \
    305     if (instr->addressing_mode() != kMode_None) {           \
    306       __ asm_instr(i.OutputRegister(), i.MemoryOperand());  \
    307     } else if (instr->InputAt(0)->IsRegister()) {           \
    308       __ asm_instr(i.OutputRegister(), i.InputRegister(0)); \
    309     } else {                                                \
    310       __ asm_instr(i.OutputRegister(), i.InputOperand(0));  \
    311     }                                                       \
    312   } while (0)
    313 
    314 
    315 #define ASSEMBLE_SSE_BINOP(asm_instr)                                   \
    316   do {                                                                  \
    317     if (instr->InputAt(1)->IsDoubleRegister()) {                        \
    318       __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
    319     } else {                                                            \
    320       __ asm_instr(i.InputDoubleRegister(0), i.InputOperand(1));        \
    321     }                                                                   \
    322   } while (0)
    323 
    324 
    325 #define ASSEMBLE_SSE_UNOP(asm_instr)                                    \
    326   do {                                                                  \
    327     if (instr->InputAt(0)->IsDoubleRegister()) {                        \
    328       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
    329     } else {                                                            \
    330       __ asm_instr(i.OutputDoubleRegister(), i.InputOperand(0));        \
    331     }                                                                   \
    332   } while (0)
    333 
    334 
    335 #define ASSEMBLE_AVX_BINOP(asm_instr)                                  \
    336   do {                                                                 \
    337     CpuFeatureScope avx_scope(masm(), AVX);                            \
    338     if (instr->InputAt(1)->IsDoubleRegister()) {                       \
    339       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    340                    i.InputDoubleRegister(1));                          \
    341     } else {                                                           \
    342       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    343                    i.InputOperand(1));                                 \
    344     }                                                                  \
    345   } while (0)
    346 
    347 
    348 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr)                               \
    349   do {                                                                       \
    350     auto result = i.OutputDoubleRegister();                                  \
    351     auto buffer = i.InputRegister(0);                                        \
    352     auto index1 = i.InputRegister(1);                                        \
    353     auto index2 = i.InputInt32(2);                                           \
    354     OutOfLineCode* ool;                                                      \
    355     if (instr->InputAt(3)->IsRegister()) {                                   \
    356       auto length = i.InputRegister(3);                                      \
    357       DCHECK_EQ(0, index2);                                                  \
    358       __ cmpl(index1, length);                                               \
    359       ool = new (zone()) OutOfLineLoadNaN(this, result);                     \
    360     } else {                                                                 \
    361       auto length = i.InputInt32(3);                                         \
    362       DCHECK_LE(index2, length);                                             \
    363       __ cmpq(index1, Immediate(length - index2));                           \
    364       class OutOfLineLoadFloat final : public OutOfLineCode {                \
    365        public:                                                               \
    366         OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result,           \
    367                            Register buffer, Register index1, int32_t index2, \
    368                            int32_t length)                                   \
    369             : OutOfLineCode(gen),                                            \
    370               result_(result),                                               \
    371               buffer_(buffer),                                               \
    372               index1_(index1),                                               \
    373               index2_(index2),                                               \
    374               length_(length) {}                                             \
    375                                                                              \
    376         void Generate() final {                                              \
    377           __ leal(kScratchRegister, Operand(index1_, index2_));              \
    378           __ Pcmpeqd(result_, result_);                                      \
    379           __ cmpl(kScratchRegister, Immediate(length_));                     \
    380           __ j(above_equal, exit());                                         \
    381           __ asm_instr(result_,                                              \
    382                        Operand(buffer_, kScratchRegister, times_1, 0));      \
    383         }                                                                    \
    384                                                                              \
    385        private:                                                              \
    386         XMMRegister const result_;                                           \
    387         Register const buffer_;                                              \
    388         Register const index1_;                                              \
    389         int32_t const index2_;                                               \
    390         int32_t const length_;                                               \
    391       };                                                                     \
    392       ool = new (zone())                                                     \
    393           OutOfLineLoadFloat(this, result, buffer, index1, index2, length);  \
    394     }                                                                        \
    395     __ j(above_equal, ool->entry());                                         \
    396     __ asm_instr(result, Operand(buffer, index1, times_1, index2));          \
    397     __ bind(ool->exit());                                                    \
    398   } while (false)
    399 
    400 
    401 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                               \
    402   do {                                                                         \
    403     auto result = i.OutputRegister();                                          \
    404     auto buffer = i.InputRegister(0);                                          \
    405     auto index1 = i.InputRegister(1);                                          \
    406     auto index2 = i.InputInt32(2);                                             \
    407     OutOfLineCode* ool;                                                        \
    408     if (instr->InputAt(3)->IsRegister()) {                                     \
    409       auto length = i.InputRegister(3);                                        \
    410       DCHECK_EQ(0, index2);                                                    \
    411       __ cmpl(index1, length);                                                 \
    412       ool = new (zone()) OutOfLineLoadZero(this, result);                      \
    413     } else {                                                                   \
    414       auto length = i.InputInt32(3);                                           \
    415       DCHECK_LE(index2, length);                                               \
    416       __ cmpq(index1, Immediate(length - index2));                             \
    417       class OutOfLineLoadInteger final : public OutOfLineCode {                \
    418        public:                                                                 \
    419         OutOfLineLoadInteger(CodeGenerator* gen, Register result,              \
    420                              Register buffer, Register index1, int32_t index2, \
    421                              int32_t length)                                   \
    422             : OutOfLineCode(gen),                                              \
    423               result_(result),                                                 \
    424               buffer_(buffer),                                                 \
    425               index1_(index1),                                                 \
    426               index2_(index2),                                                 \
    427               length_(length) {}                                               \
    428                                                                                \
    429         void Generate() final {                                                \
    430           Label oob;                                                           \
    431           __ leal(kScratchRegister, Operand(index1_, index2_));                \
    432           __ cmpl(kScratchRegister, Immediate(length_));                       \
    433           __ j(above_equal, &oob, Label::kNear);                               \
    434           __ asm_instr(result_,                                                \
    435                        Operand(buffer_, kScratchRegister, times_1, 0));        \
    436           __ jmp(exit());                                                      \
    437           __ bind(&oob);                                                       \
    438           __ xorl(result_, result_);                                           \
    439         }                                                                      \
    440                                                                                \
    441        private:                                                                \
    442         Register const result_;                                                \
    443         Register const buffer_;                                                \
    444         Register const index1_;                                                \
    445         int32_t const index2_;                                                 \
    446         int32_t const length_;                                                 \
    447       };                                                                       \
    448       ool = new (zone())                                                       \
    449           OutOfLineLoadInteger(this, result, buffer, index1, index2, length);  \
    450     }                                                                          \
    451     __ j(above_equal, ool->entry());                                           \
    452     __ asm_instr(result, Operand(buffer, index1, times_1, index2));            \
    453     __ bind(ool->exit());                                                      \
    454   } while (false)
    455 
    456 
    457 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)                              \
    458   do {                                                                       \
    459     auto buffer = i.InputRegister(0);                                        \
    460     auto index1 = i.InputRegister(1);                                        \
    461     auto index2 = i.InputInt32(2);                                           \
    462     auto value = i.InputDoubleRegister(4);                                   \
    463     if (instr->InputAt(3)->IsRegister()) {                                   \
    464       auto length = i.InputRegister(3);                                      \
    465       DCHECK_EQ(0, index2);                                                  \
    466       Label done;                                                            \
    467       __ cmpl(index1, length);                                               \
    468       __ j(above_equal, &done, Label::kNear);                                \
    469       __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
    470       __ bind(&done);                                                        \
    471     } else {                                                                 \
    472       auto length = i.InputInt32(3);                                         \
    473       DCHECK_LE(index2, length);                                             \
    474       __ cmpq(index1, Immediate(length - index2));                           \
    475       class OutOfLineStoreFloat final : public OutOfLineCode {               \
    476        public:                                                               \
    477         OutOfLineStoreFloat(CodeGenerator* gen, Register buffer,             \
    478                             Register index1, int32_t index2, int32_t length, \
    479                             XMMRegister value)                               \
    480             : OutOfLineCode(gen),                                            \
    481               buffer_(buffer),                                               \
    482               index1_(index1),                                               \
    483               index2_(index2),                                               \
    484               length_(length),                                               \
    485               value_(value) {}                                               \
    486                                                                              \
    487         void Generate() final {                                              \
    488           __ leal(kScratchRegister, Operand(index1_, index2_));              \
    489           __ cmpl(kScratchRegister, Immediate(length_));                     \
    490           __ j(above_equal, exit());                                         \
    491           __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),       \
    492                        value_);                                              \
    493         }                                                                    \
    494                                                                              \
    495        private:                                                              \
    496         Register const buffer_;                                              \
    497         Register const index1_;                                              \
    498         int32_t const index2_;                                               \
    499         int32_t const length_;                                               \
    500         XMMRegister const value_;                                            \
    501       };                                                                     \
    502       auto ool = new (zone())                                                \
    503           OutOfLineStoreFloat(this, buffer, index1, index2, length, value);  \
    504       __ j(above_equal, ool->entry());                                       \
    505       __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
    506       __ bind(ool->exit());                                                  \
    507     }                                                                        \
    508   } while (false)
    509 
    510 
    511 #define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value)                  \
    512   do {                                                                         \
    513     auto buffer = i.InputRegister(0);                                          \
    514     auto index1 = i.InputRegister(1);                                          \
    515     auto index2 = i.InputInt32(2);                                             \
    516     if (instr->InputAt(3)->IsRegister()) {                                     \
    517       auto length = i.InputRegister(3);                                        \
    518       DCHECK_EQ(0, index2);                                                    \
    519       Label done;                                                              \
    520       __ cmpl(index1, length);                                                 \
    521       __ j(above_equal, &done, Label::kNear);                                  \
    522       __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
    523       __ bind(&done);                                                          \
    524     } else {                                                                   \
    525       auto length = i.InputInt32(3);                                           \
    526       DCHECK_LE(index2, length);                                               \
    527       __ cmpq(index1, Immediate(length - index2));                             \
    528       class OutOfLineStoreInteger final : public OutOfLineCode {               \
    529        public:                                                                 \
    530         OutOfLineStoreInteger(CodeGenerator* gen, Register buffer,             \
    531                               Register index1, int32_t index2, int32_t length, \
    532                               Value value)                                     \
    533             : OutOfLineCode(gen),                                              \
    534               buffer_(buffer),                                                 \
    535               index1_(index1),                                                 \
    536               index2_(index2),                                                 \
    537               length_(length),                                                 \
    538               value_(value) {}                                                 \
    539                                                                                \
    540         void Generate() final {                                                \
    541           __ leal(kScratchRegister, Operand(index1_, index2_));                \
    542           __ cmpl(kScratchRegister, Immediate(length_));                       \
    543           __ j(above_equal, exit());                                           \
    544           __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),         \
    545                        value_);                                                \
    546         }                                                                      \
    547                                                                                \
    548        private:                                                                \
    549         Register const buffer_;                                                \
    550         Register const index1_;                                                \
    551         int32_t const index2_;                                                 \
    552         int32_t const length_;                                                 \
    553         Value const value_;                                                    \
    554       };                                                                       \
    555       auto ool = new (zone())                                                  \
    556           OutOfLineStoreInteger(this, buffer, index1, index2, length, value);  \
    557       __ j(above_equal, ool->entry());                                         \
    558       __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
    559       __ bind(ool->exit());                                                    \
    560     }                                                                          \
    561   } while (false)
    562 
    563 
    564 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                \
    565   do {                                                           \
    566     if (instr->InputAt(4)->IsRegister()) {                       \
    567       Register value = i.InputRegister(4);                       \
    568       ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Register);  \
    569     } else {                                                     \
    570       Immediate value = i.InputImmediate(4);                     \
    571       ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Immediate); \
    572     }                                                            \
    573   } while (false)
    574 
    575 
    576 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
    577   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    578   if (sp_slot_delta > 0) {
    579     __ addq(rsp, Immediate(sp_slot_delta * kPointerSize));
    580   }
    581   frame_access_state()->SetFrameAccessToDefault();
    582 }
    583 
    584 
    585 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
    586   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    587   if (sp_slot_delta < 0) {
    588     __ subq(rsp, Immediate(-sp_slot_delta * kPointerSize));
    589     frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
    590   }
    591   if (frame()->needs_frame()) {
    592     __ movq(rbp, MemOperand(rbp, 0));
    593   }
    594   frame_access_state()->SetFrameAccessToSP();
    595 }
    596 
    597 
    598 // Assembles an instruction after register allocation, producing machine code.
    599 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
    600   X64OperandConverter i(this, instr);
    601 
    602   switch (ArchOpcodeField::decode(instr->opcode())) {
    603     case kArchCallCodeObject: {
    604       EnsureSpaceForLazyDeopt();
    605       if (HasImmediateInput(instr, 0)) {
    606         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
    607         __ Call(code, RelocInfo::CODE_TARGET);
    608       } else {
    609         Register reg = i.InputRegister(0);
    610         __ addp(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
    611         __ call(reg);
    612       }
    613       RecordCallPosition(instr);
    614       frame_access_state()->ClearSPDelta();
    615       break;
    616     }
    617     case kArchTailCallCodeObject: {
    618       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    619       AssembleDeconstructActivationRecord(stack_param_delta);
    620       if (HasImmediateInput(instr, 0)) {
    621         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
    622         __ jmp(code, RelocInfo::CODE_TARGET);
    623       } else {
    624         Register reg = i.InputRegister(0);
    625         __ addp(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
    626         __ jmp(reg);
    627       }
    628       frame_access_state()->ClearSPDelta();
    629       break;
    630     }
    631     case kArchCallJSFunction: {
    632       EnsureSpaceForLazyDeopt();
    633       Register func = i.InputRegister(0);
    634       if (FLAG_debug_code) {
    635         // Check the function's context matches the context argument.
    636         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
    637         __ Assert(equal, kWrongFunctionContext);
    638       }
    639       __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
    640       frame_access_state()->ClearSPDelta();
    641       RecordCallPosition(instr);
    642       break;
    643     }
    644     case kArchTailCallJSFunction: {
    645       Register func = i.InputRegister(0);
    646       if (FLAG_debug_code) {
    647         // Check the function's context matches the context argument.
    648         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
    649         __ Assert(equal, kWrongFunctionContext);
    650       }
    651       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    652       AssembleDeconstructActivationRecord(stack_param_delta);
    653       __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
    654       frame_access_state()->ClearSPDelta();
    655       break;
    656     }
    657     case kArchLazyBailout: {
    658       EnsureSpaceForLazyDeopt();
    659       RecordCallPosition(instr);
    660       break;
    661     }
    662     case kArchPrepareCallCFunction: {
    663       // Frame alignment requires using FP-relative frame addressing.
    664       frame_access_state()->SetFrameAccessToFP();
    665       int const num_parameters = MiscField::decode(instr->opcode());
    666       __ PrepareCallCFunction(num_parameters);
    667       break;
    668     }
    669     case kArchPrepareTailCall:
    670       AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
    671       break;
    672     case kArchCallCFunction: {
    673       int const num_parameters = MiscField::decode(instr->opcode());
    674       if (HasImmediateInput(instr, 0)) {
    675         ExternalReference ref = i.InputExternalReference(0);
    676         __ CallCFunction(ref, num_parameters);
    677       } else {
    678         Register func = i.InputRegister(0);
    679         __ CallCFunction(func, num_parameters);
    680       }
    681       frame_access_state()->SetFrameAccessToDefault();
    682       frame_access_state()->ClearSPDelta();
    683       break;
    684     }
    685     case kArchJmp:
    686       AssembleArchJump(i.InputRpo(0));
    687       break;
    688     case kArchLookupSwitch:
    689       AssembleArchLookupSwitch(instr);
    690       break;
    691     case kArchTableSwitch:
    692       AssembleArchTableSwitch(instr);
    693       break;
    694     case kArchNop:
    695     case kArchThrowTerminator:
    696       // don't emit code for nops.
    697       break;
    698     case kArchDeoptimize: {
    699       int deopt_state_id =
    700           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    701       Deoptimizer::BailoutType bailout_type =
    702           Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
    703       AssembleDeoptimizerCall(deopt_state_id, bailout_type);
    704       break;
    705     }
    706     case kArchRet:
    707       AssembleReturn();
    708       break;
    709     case kArchStackPointer:
    710       __ movq(i.OutputRegister(), rsp);
    711       break;
    712     case kArchFramePointer:
    713       __ movq(i.OutputRegister(), rbp);
    714       break;
    715     case kArchTruncateDoubleToI: {
    716       auto result = i.OutputRegister();
    717       auto input = i.InputDoubleRegister(0);
    718       auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
    719       __ Cvttsd2siq(result, input);
    720       __ cmpq(result, Immediate(1));
    721       __ j(overflow, ool->entry());
    722       __ bind(ool->exit());
    723       break;
    724     }
    725     case kArchStoreWithWriteBarrier: {
    726       RecordWriteMode mode =
    727           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    728       Register object = i.InputRegister(0);
    729       size_t index = 0;
    730       Operand operand = i.MemoryOperand(&index);
    731       Register value = i.InputRegister(index);
    732       Register scratch0 = i.TempRegister(0);
    733       Register scratch1 = i.TempRegister(1);
    734       auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
    735                                                    scratch0, scratch1, mode);
    736       __ movp(operand, value);
    737       __ CheckPageFlag(object, scratch0,
    738                        MemoryChunk::kPointersFromHereAreInterestingMask,
    739                        not_zero, ool->entry());
    740       __ bind(ool->exit());
    741       break;
    742     }
    743     case kX64Add32:
    744       ASSEMBLE_BINOP(addl);
    745       break;
    746     case kX64Add:
    747       ASSEMBLE_BINOP(addq);
    748       break;
    749     case kX64Sub32:
    750       ASSEMBLE_BINOP(subl);
    751       break;
    752     case kX64Sub:
    753       ASSEMBLE_BINOP(subq);
    754       break;
    755     case kX64And32:
    756       ASSEMBLE_BINOP(andl);
    757       break;
    758     case kX64And:
    759       ASSEMBLE_BINOP(andq);
    760       break;
    761     case kX64Cmp32:
    762       ASSEMBLE_BINOP(cmpl);
    763       break;
    764     case kX64Cmp:
    765       ASSEMBLE_BINOP(cmpq);
    766       break;
    767     case kX64Test32:
    768       ASSEMBLE_BINOP(testl);
    769       break;
    770     case kX64Test:
    771       ASSEMBLE_BINOP(testq);
    772       break;
    773     case kX64Imul32:
    774       ASSEMBLE_MULT(imull);
    775       break;
    776     case kX64Imul:
    777       ASSEMBLE_MULT(imulq);
    778       break;
    779     case kX64ImulHigh32:
    780       if (instr->InputAt(1)->IsRegister()) {
    781         __ imull(i.InputRegister(1));
    782       } else {
    783         __ imull(i.InputOperand(1));
    784       }
    785       break;
    786     case kX64UmulHigh32:
    787       if (instr->InputAt(1)->IsRegister()) {
    788         __ mull(i.InputRegister(1));
    789       } else {
    790         __ mull(i.InputOperand(1));
    791       }
    792       break;
    793     case kX64Idiv32:
    794       __ cdq();
    795       __ idivl(i.InputRegister(1));
    796       break;
    797     case kX64Idiv:
    798       __ cqo();
    799       __ idivq(i.InputRegister(1));
    800       break;
    801     case kX64Udiv32:
    802       __ xorl(rdx, rdx);
    803       __ divl(i.InputRegister(1));
    804       break;
    805     case kX64Udiv:
    806       __ xorq(rdx, rdx);
    807       __ divq(i.InputRegister(1));
    808       break;
    809     case kX64Not:
    810       ASSEMBLE_UNOP(notq);
    811       break;
    812     case kX64Not32:
    813       ASSEMBLE_UNOP(notl);
    814       break;
    815     case kX64Neg:
    816       ASSEMBLE_UNOP(negq);
    817       break;
    818     case kX64Neg32:
    819       ASSEMBLE_UNOP(negl);
    820       break;
    821     case kX64Or32:
    822       ASSEMBLE_BINOP(orl);
    823       break;
    824     case kX64Or:
    825       ASSEMBLE_BINOP(orq);
    826       break;
    827     case kX64Xor32:
    828       ASSEMBLE_BINOP(xorl);
    829       break;
    830     case kX64Xor:
    831       ASSEMBLE_BINOP(xorq);
    832       break;
    833     case kX64Shl32:
    834       ASSEMBLE_SHIFT(shll, 5);
    835       break;
    836     case kX64Shl:
    837       ASSEMBLE_SHIFT(shlq, 6);
    838       break;
    839     case kX64Shr32:
    840       ASSEMBLE_SHIFT(shrl, 5);
    841       break;
    842     case kX64Shr:
    843       ASSEMBLE_SHIFT(shrq, 6);
    844       break;
    845     case kX64Sar32:
    846       ASSEMBLE_SHIFT(sarl, 5);
    847       break;
    848     case kX64Sar:
    849       ASSEMBLE_SHIFT(sarq, 6);
    850       break;
    851     case kX64Ror32:
    852       ASSEMBLE_SHIFT(rorl, 5);
    853       break;
    854     case kX64Ror:
    855       ASSEMBLE_SHIFT(rorq, 6);
    856       break;
    857     case kX64Lzcnt:
    858       if (instr->InputAt(0)->IsRegister()) {
    859         __ Lzcntq(i.OutputRegister(), i.InputRegister(0));
    860       } else {
    861         __ Lzcntq(i.OutputRegister(), i.InputOperand(0));
    862       }
    863       break;
    864     case kX64Lzcnt32:
    865       if (instr->InputAt(0)->IsRegister()) {
    866         __ Lzcntl(i.OutputRegister(), i.InputRegister(0));
    867       } else {
    868         __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
    869       }
    870       break;
    871     case kX64Tzcnt:
    872       if (instr->InputAt(0)->IsRegister()) {
    873         __ Tzcntq(i.OutputRegister(), i.InputRegister(0));
    874       } else {
    875         __ Tzcntq(i.OutputRegister(), i.InputOperand(0));
    876       }
    877       break;
    878     case kX64Tzcnt32:
    879       if (instr->InputAt(0)->IsRegister()) {
    880         __ Tzcntl(i.OutputRegister(), i.InputRegister(0));
    881       } else {
    882         __ Tzcntl(i.OutputRegister(), i.InputOperand(0));
    883       }
    884       break;
    885     case kX64Popcnt:
    886       if (instr->InputAt(0)->IsRegister()) {
    887         __ Popcntq(i.OutputRegister(), i.InputRegister(0));
    888       } else {
    889         __ Popcntq(i.OutputRegister(), i.InputOperand(0));
    890       }
    891       break;
    892     case kX64Popcnt32:
    893       if (instr->InputAt(0)->IsRegister()) {
    894         __ Popcntl(i.OutputRegister(), i.InputRegister(0));
    895       } else {
    896         __ Popcntl(i.OutputRegister(), i.InputOperand(0));
    897       }
    898       break;
    899     case kSSEFloat32Cmp:
    900       ASSEMBLE_SSE_BINOP(Ucomiss);
    901       break;
    902     case kSSEFloat32Add:
    903       ASSEMBLE_SSE_BINOP(addss);
    904       break;
    905     case kSSEFloat32Sub:
    906       ASSEMBLE_SSE_BINOP(subss);
    907       break;
    908     case kSSEFloat32Mul:
    909       ASSEMBLE_SSE_BINOP(mulss);
    910       break;
    911     case kSSEFloat32Div:
    912       ASSEMBLE_SSE_BINOP(divss);
    913       // Don't delete this mov. It may improve performance on some CPUs,
    914       // when there is a (v)mulss depending on the result.
    915       __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
    916       break;
    917     case kSSEFloat32Abs: {
    918       // TODO(bmeurer): Use RIP relative 128-bit constants.
    919       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
    920       __ psrlq(kScratchDoubleReg, 33);
    921       __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
    922       break;
    923     }
    924     case kSSEFloat32Neg: {
    925       // TODO(bmeurer): Use RIP relative 128-bit constants.
    926       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
    927       __ psllq(kScratchDoubleReg, 31);
    928       __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
    929       break;
    930     }
    931     case kSSEFloat32Sqrt:
    932       ASSEMBLE_SSE_UNOP(sqrtss);
    933       break;
    934     case kSSEFloat32Max:
    935       ASSEMBLE_SSE_BINOP(maxss);
    936       break;
    937     case kSSEFloat32Min:
    938       ASSEMBLE_SSE_BINOP(minss);
    939       break;
    940     case kSSEFloat32ToFloat64:
    941       ASSEMBLE_SSE_UNOP(Cvtss2sd);
    942       break;
    943     case kSSEFloat32Round: {
    944       CpuFeatureScope sse_scope(masm(), SSE4_1);
    945       RoundingMode const mode =
    946           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
    947       __ Roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
    948       break;
    949     }
    950     case kSSEFloat64Cmp:
    951       ASSEMBLE_SSE_BINOP(Ucomisd);
    952       break;
    953     case kSSEFloat64Add:
    954       ASSEMBLE_SSE_BINOP(addsd);
    955       break;
    956     case kSSEFloat64Sub:
    957       ASSEMBLE_SSE_BINOP(subsd);
    958       break;
    959     case kSSEFloat64Mul:
    960       ASSEMBLE_SSE_BINOP(mulsd);
    961       break;
    962     case kSSEFloat64Div:
    963       ASSEMBLE_SSE_BINOP(divsd);
    964       // Don't delete this mov. It may improve performance on some CPUs,
    965       // when there is a (v)mulsd depending on the result.
    966       __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
    967       break;
    968     case kSSEFloat64Mod: {
    969       __ subq(rsp, Immediate(kDoubleSize));
    970       // Move values to st(0) and st(1).
    971       __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
    972       __ fld_d(Operand(rsp, 0));
    973       __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
    974       __ fld_d(Operand(rsp, 0));
    975       // Loop while fprem isn't done.
    976       Label mod_loop;
    977       __ bind(&mod_loop);
    978       // This instructions traps on all kinds inputs, but we are assuming the
    979       // floating point control word is set to ignore them all.
    980       __ fprem();
    981       // The following 2 instruction implicitly use rax.
    982       __ fnstsw_ax();
    983       if (CpuFeatures::IsSupported(SAHF)) {
    984         CpuFeatureScope sahf_scope(masm(), SAHF);
    985         __ sahf();
    986       } else {
    987         __ shrl(rax, Immediate(8));
    988         __ andl(rax, Immediate(0xFF));
    989         __ pushq(rax);
    990         __ popfq();
    991       }
    992       __ j(parity_even, &mod_loop);
    993       // Move output to stack and clean up.
    994       __ fstp(1);
    995       __ fstp_d(Operand(rsp, 0));
    996       __ Movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
    997       __ addq(rsp, Immediate(kDoubleSize));
    998       break;
    999     }
   1000     case kSSEFloat64Max:
   1001       ASSEMBLE_SSE_BINOP(maxsd);
   1002       break;
   1003     case kSSEFloat64Min:
   1004       ASSEMBLE_SSE_BINOP(minsd);
   1005       break;
   1006     case kSSEFloat64Abs: {
   1007       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1008       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1009       __ psrlq(kScratchDoubleReg, 1);
   1010       __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
   1011       break;
   1012     }
   1013     case kSSEFloat64Neg: {
   1014       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1015       __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
   1016       __ psllq(kScratchDoubleReg, 63);
   1017       __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
   1018       break;
   1019     }
   1020     case kSSEFloat64Sqrt:
   1021       ASSEMBLE_SSE_UNOP(sqrtsd);
   1022       break;
   1023     case kSSEFloat64Round: {
   1024       CpuFeatureScope sse_scope(masm(), SSE4_1);
   1025       RoundingMode const mode =
   1026           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
   1027       __ Roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
   1028       break;
   1029     }
   1030     case kSSEFloat64ToFloat32:
   1031       ASSEMBLE_SSE_UNOP(Cvtsd2ss);
   1032       break;
   1033     case kSSEFloat64ToInt32:
   1034       if (instr->InputAt(0)->IsDoubleRegister()) {
   1035         __ Cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
   1036       } else {
   1037         __ Cvttsd2si(i.OutputRegister(), i.InputOperand(0));
   1038       }
   1039       break;
   1040     case kSSEFloat64ToUint32: {
   1041       if (instr->InputAt(0)->IsDoubleRegister()) {
   1042         __ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1043       } else {
   1044         __ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
   1045       }
   1046       __ AssertZeroExtended(i.OutputRegister());
   1047       break;
   1048     }
   1049     case kSSEFloat32ToInt64:
   1050       if (instr->InputAt(0)->IsDoubleRegister()) {
   1051         __ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1052       } else {
   1053         __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
   1054       }
   1055       if (instr->OutputCount() > 1) {
   1056         __ Set(i.OutputRegister(1), 1);
   1057         Label done;
   1058         Label fail;
   1059         __ Move(kScratchDoubleReg, static_cast<float>(INT64_MIN));
   1060         if (instr->InputAt(0)->IsDoubleRegister()) {
   1061           __ Ucomiss(kScratchDoubleReg, i.InputDoubleRegister(0));
   1062         } else {
   1063           __ Ucomiss(kScratchDoubleReg, i.InputOperand(0));
   1064         }
   1065         // If the input is NaN, then the conversion fails.
   1066         __ j(parity_even, &fail);
   1067         // If the input is INT64_MIN, then the conversion succeeds.
   1068         __ j(equal, &done);
   1069         __ cmpq(i.OutputRegister(0), Immediate(1));
   1070         // If the conversion results in INT64_MIN, but the input was not
   1071         // INT64_MIN, then the conversion fails.
   1072         __ j(no_overflow, &done);
   1073         __ bind(&fail);
   1074         __ Set(i.OutputRegister(1), 0);
   1075         __ bind(&done);
   1076       }
   1077       break;
   1078     case kSSEFloat64ToInt64:
   1079       if (instr->InputAt(0)->IsDoubleRegister()) {
   1080         __ Cvttsd2siq(i.OutputRegister(0), i.InputDoubleRegister(0));
   1081       } else {
   1082         __ Cvttsd2siq(i.OutputRegister(0), i.InputOperand(0));
   1083       }
   1084       if (instr->OutputCount() > 1) {
   1085         __ Set(i.OutputRegister(1), 1);
   1086         Label done;
   1087         Label fail;
   1088         __ Move(kScratchDoubleReg, static_cast<double>(INT64_MIN));
   1089         if (instr->InputAt(0)->IsDoubleRegister()) {
   1090           __ Ucomisd(kScratchDoubleReg, i.InputDoubleRegister(0));
   1091         } else {
   1092           __ Ucomisd(kScratchDoubleReg, i.InputOperand(0));
   1093         }
   1094         // If the input is NaN, then the conversion fails.
   1095         __ j(parity_even, &fail);
   1096         // If the input is INT64_MIN, then the conversion succeeds.
   1097         __ j(equal, &done);
   1098         __ cmpq(i.OutputRegister(0), Immediate(1));
   1099         // If the conversion results in INT64_MIN, but the input was not
   1100         // INT64_MIN, then the conversion fails.
   1101         __ j(no_overflow, &done);
   1102         __ bind(&fail);
   1103         __ Set(i.OutputRegister(1), 0);
   1104         __ bind(&done);
   1105       }
   1106       break;
   1107     case kSSEFloat32ToUint64: {
   1108       Label done;
   1109       Label success;
   1110       if (instr->OutputCount() > 1) {
   1111         __ Set(i.OutputRegister(1), 0);
   1112       }
   1113       // There does not exist a Float32ToUint64 instruction, so we have to use
   1114       // the Float32ToInt64 instruction.
   1115       if (instr->InputAt(0)->IsDoubleRegister()) {
   1116         __ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1117       } else {
   1118         __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
   1119       }
   1120       // Check if the result of the Float32ToInt64 conversion is positive, we
   1121       // are already done.
   1122       __ testq(i.OutputRegister(), i.OutputRegister());
   1123       __ j(positive, &success);
   1124       // The result of the first conversion was negative, which means that the
   1125       // input value was not within the positive int64 range. We subtract 2^64
   1126       // and convert it again to see if it is within the uint64 range.
   1127       __ Move(kScratchDoubleReg, -9223372036854775808.0f);
   1128       if (instr->InputAt(0)->IsDoubleRegister()) {
   1129         __ addss(kScratchDoubleReg, i.InputDoubleRegister(0));
   1130       } else {
   1131         __ addss(kScratchDoubleReg, i.InputOperand(0));
   1132       }
   1133       __ Cvttss2siq(i.OutputRegister(), kScratchDoubleReg);
   1134       __ testq(i.OutputRegister(), i.OutputRegister());
   1135       // The only possible negative value here is 0x80000000000000000, which is
   1136       // used on x64 to indicate an integer overflow.
   1137       __ j(negative, &done);
   1138       // The input value is within uint64 range and the second conversion worked
   1139       // successfully, but we still have to undo the subtraction we did
   1140       // earlier.
   1141       __ Set(kScratchRegister, 0x8000000000000000);
   1142       __ orq(i.OutputRegister(), kScratchRegister);
   1143       __ bind(&success);
   1144       if (instr->OutputCount() > 1) {
   1145         __ Set(i.OutputRegister(1), 1);
   1146       }
   1147       __ bind(&done);
   1148       break;
   1149     }
   1150     case kSSEFloat64ToUint64: {
   1151       Label done;
   1152       Label success;
   1153       if (instr->OutputCount() > 1) {
   1154         __ Set(i.OutputRegister(1), 0);
   1155       }
   1156       // There does not exist a Float64ToUint64 instruction, so we have to use
   1157       // the Float64ToInt64 instruction.
   1158       if (instr->InputAt(0)->IsDoubleRegister()) {
   1159         __ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
   1160       } else {
   1161         __ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
   1162       }
   1163       // Check if the result of the Float64ToInt64 conversion is positive, we
   1164       // are already done.
   1165       __ testq(i.OutputRegister(), i.OutputRegister());
   1166       __ j(positive, &success);
   1167       // The result of the first conversion was negative, which means that the
   1168       // input value was not within the positive int64 range. We subtract 2^64
   1169       // and convert it again to see if it is within the uint64 range.
   1170       __ Move(kScratchDoubleReg, -9223372036854775808.0);
   1171       if (instr->InputAt(0)->IsDoubleRegister()) {
   1172         __ addsd(kScratchDoubleReg, i.InputDoubleRegister(0));
   1173       } else {
   1174         __ addsd(kScratchDoubleReg, i.InputOperand(0));
   1175       }
   1176       __ Cvttsd2siq(i.OutputRegister(), kScratchDoubleReg);
   1177       __ testq(i.OutputRegister(), i.OutputRegister());
   1178       // The only possible negative value here is 0x80000000000000000, which is
   1179       // used on x64 to indicate an integer overflow.
   1180       __ j(negative, &done);
   1181       // The input value is within uint64 range and the second conversion worked
   1182       // successfully, but we still have to undo the subtraction we did
   1183       // earlier.
   1184       __ Set(kScratchRegister, 0x8000000000000000);
   1185       __ orq(i.OutputRegister(), kScratchRegister);
   1186       __ bind(&success);
   1187       if (instr->OutputCount() > 1) {
   1188         __ Set(i.OutputRegister(1), 1);
   1189       }
   1190       __ bind(&done);
   1191       break;
   1192     }
   1193     case kSSEInt32ToFloat64:
   1194       if (instr->InputAt(0)->IsRegister()) {
   1195         __ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
   1196       } else {
   1197         __ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
   1198       }
   1199       break;
   1200     case kSSEInt64ToFloat32:
   1201       if (instr->InputAt(0)->IsRegister()) {
   1202         __ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
   1203       } else {
   1204         __ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
   1205       }
   1206       break;
   1207     case kSSEInt64ToFloat64:
   1208       if (instr->InputAt(0)->IsRegister()) {
   1209         __ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
   1210       } else {
   1211         __ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
   1212       }
   1213       break;
   1214     case kSSEUint64ToFloat32:
   1215       if (instr->InputAt(0)->IsRegister()) {
   1216         __ movq(kScratchRegister, i.InputRegister(0));
   1217       } else {
   1218         __ movq(kScratchRegister, i.InputOperand(0));
   1219       }
   1220       __ Cvtqui2ss(i.OutputDoubleRegister(), kScratchRegister,
   1221                    i.TempRegister(0));
   1222       break;
   1223     case kSSEUint64ToFloat64:
   1224       if (instr->InputAt(0)->IsRegister()) {
   1225         __ movq(kScratchRegister, i.InputRegister(0));
   1226       } else {
   1227         __ movq(kScratchRegister, i.InputOperand(0));
   1228       }
   1229       __ Cvtqui2sd(i.OutputDoubleRegister(), kScratchRegister,
   1230                    i.TempRegister(0));
   1231       break;
   1232     case kSSEUint32ToFloat64:
   1233       if (instr->InputAt(0)->IsRegister()) {
   1234         __ movl(kScratchRegister, i.InputRegister(0));
   1235       } else {
   1236         __ movl(kScratchRegister, i.InputOperand(0));
   1237       }
   1238       __ Cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
   1239       break;
   1240     case kSSEFloat64ExtractLowWord32:
   1241       if (instr->InputAt(0)->IsDoubleStackSlot()) {
   1242         __ movl(i.OutputRegister(), i.InputOperand(0));
   1243       } else {
   1244         __ Movd(i.OutputRegister(), i.InputDoubleRegister(0));
   1245       }
   1246       break;
   1247     case kSSEFloat64ExtractHighWord32:
   1248       if (instr->InputAt(0)->IsDoubleStackSlot()) {
   1249         __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
   1250       } else {
   1251         __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
   1252       }
   1253       break;
   1254     case kSSEFloat64InsertLowWord32:
   1255       if (instr->InputAt(1)->IsRegister()) {
   1256         __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
   1257       } else {
   1258         __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
   1259       }
   1260       break;
   1261     case kSSEFloat64InsertHighWord32:
   1262       if (instr->InputAt(1)->IsRegister()) {
   1263         __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
   1264       } else {
   1265         __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
   1266       }
   1267       break;
   1268     case kSSEFloat64LoadLowWord32:
   1269       if (instr->InputAt(0)->IsRegister()) {
   1270         __ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
   1271       } else {
   1272         __ Movd(i.OutputDoubleRegister(), i.InputOperand(0));
   1273       }
   1274       break;
   1275     case kAVXFloat32Cmp: {
   1276       CpuFeatureScope avx_scope(masm(), AVX);
   1277       if (instr->InputAt(1)->IsDoubleRegister()) {
   1278         __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1279       } else {
   1280         __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
   1281       }
   1282       break;
   1283     }
   1284     case kAVXFloat32Add:
   1285       ASSEMBLE_AVX_BINOP(vaddss);
   1286       break;
   1287     case kAVXFloat32Sub:
   1288       ASSEMBLE_AVX_BINOP(vsubss);
   1289       break;
   1290     case kAVXFloat32Mul:
   1291       ASSEMBLE_AVX_BINOP(vmulss);
   1292       break;
   1293     case kAVXFloat32Div:
   1294       ASSEMBLE_AVX_BINOP(vdivss);
   1295       // Don't delete this mov. It may improve performance on some CPUs,
   1296       // when there is a (v)mulss depending on the result.
   1297       __ Movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1298       break;
   1299     case kAVXFloat32Max:
   1300       ASSEMBLE_AVX_BINOP(vmaxss);
   1301       break;
   1302     case kAVXFloat32Min:
   1303       ASSEMBLE_AVX_BINOP(vminss);
   1304       break;
   1305     case kAVXFloat64Cmp: {
   1306       CpuFeatureScope avx_scope(masm(), AVX);
   1307       if (instr->InputAt(1)->IsDoubleRegister()) {
   1308         __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1309       } else {
   1310         __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
   1311       }
   1312       break;
   1313     }
   1314     case kAVXFloat64Add:
   1315       ASSEMBLE_AVX_BINOP(vaddsd);
   1316       break;
   1317     case kAVXFloat64Sub:
   1318       ASSEMBLE_AVX_BINOP(vsubsd);
   1319       break;
   1320     case kAVXFloat64Mul:
   1321       ASSEMBLE_AVX_BINOP(vmulsd);
   1322       break;
   1323     case kAVXFloat64Div:
   1324       ASSEMBLE_AVX_BINOP(vdivsd);
   1325       // Don't delete this mov. It may improve performance on some CPUs,
   1326       // when there is a (v)mulsd depending on the result.
   1327       __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
   1328       break;
   1329     case kAVXFloat64Max:
   1330       ASSEMBLE_AVX_BINOP(vmaxsd);
   1331       break;
   1332     case kAVXFloat64Min:
   1333       ASSEMBLE_AVX_BINOP(vminsd);
   1334       break;
   1335     case kAVXFloat32Abs: {
   1336       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1337       CpuFeatureScope avx_scope(masm(), AVX);
   1338       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1339       __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 33);
   1340       if (instr->InputAt(0)->IsDoubleRegister()) {
   1341         __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1342                   i.InputDoubleRegister(0));
   1343       } else {
   1344         __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1345                   i.InputOperand(0));
   1346       }
   1347       break;
   1348     }
   1349     case kAVXFloat32Neg: {
   1350       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1351       CpuFeatureScope avx_scope(masm(), AVX);
   1352       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1353       __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 31);
   1354       if (instr->InputAt(0)->IsDoubleRegister()) {
   1355         __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1356                   i.InputDoubleRegister(0));
   1357       } else {
   1358         __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
   1359                   i.InputOperand(0));
   1360       }
   1361       break;
   1362     }
   1363     case kAVXFloat64Abs: {
   1364       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1365       CpuFeatureScope avx_scope(masm(), AVX);
   1366       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1367       __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 1);
   1368       if (instr->InputAt(0)->IsDoubleRegister()) {
   1369         __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1370                   i.InputDoubleRegister(0));
   1371       } else {
   1372         __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1373                   i.InputOperand(0));
   1374       }
   1375       break;
   1376     }
   1377     case kAVXFloat64Neg: {
   1378       // TODO(bmeurer): Use RIP relative 128-bit constants.
   1379       CpuFeatureScope avx_scope(masm(), AVX);
   1380       __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
   1381       __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 63);
   1382       if (instr->InputAt(0)->IsDoubleRegister()) {
   1383         __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1384                   i.InputDoubleRegister(0));
   1385       } else {
   1386         __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
   1387                   i.InputOperand(0));
   1388       }
   1389       break;
   1390     }
   1391     case kX64Movsxbl:
   1392       ASSEMBLE_MOVX(movsxbl);
   1393       __ AssertZeroExtended(i.OutputRegister());
   1394       break;
   1395     case kX64Movzxbl:
   1396       ASSEMBLE_MOVX(movzxbl);
   1397       __ AssertZeroExtended(i.OutputRegister());
   1398       break;
   1399     case kX64Movb: {
   1400       size_t index = 0;
   1401       Operand operand = i.MemoryOperand(&index);
   1402       if (HasImmediateInput(instr, index)) {
   1403         __ movb(operand, Immediate(i.InputInt8(index)));
   1404       } else {
   1405         __ movb(operand, i.InputRegister(index));
   1406       }
   1407       break;
   1408     }
   1409     case kX64Movsxwl:
   1410       ASSEMBLE_MOVX(movsxwl);
   1411       __ AssertZeroExtended(i.OutputRegister());
   1412       break;
   1413     case kX64Movzxwl:
   1414       ASSEMBLE_MOVX(movzxwl);
   1415       __ AssertZeroExtended(i.OutputRegister());
   1416       break;
   1417     case kX64Movw: {
   1418       size_t index = 0;
   1419       Operand operand = i.MemoryOperand(&index);
   1420       if (HasImmediateInput(instr, index)) {
   1421         __ movw(operand, Immediate(i.InputInt16(index)));
   1422       } else {
   1423         __ movw(operand, i.InputRegister(index));
   1424       }
   1425       break;
   1426     }
   1427     case kX64Movl:
   1428       if (instr->HasOutput()) {
   1429         if (instr->addressing_mode() == kMode_None) {
   1430           if (instr->InputAt(0)->IsRegister()) {
   1431             __ movl(i.OutputRegister(), i.InputRegister(0));
   1432           } else {
   1433             __ movl(i.OutputRegister(), i.InputOperand(0));
   1434           }
   1435         } else {
   1436           __ movl(i.OutputRegister(), i.MemoryOperand());
   1437         }
   1438         __ AssertZeroExtended(i.OutputRegister());
   1439       } else {
   1440         size_t index = 0;
   1441         Operand operand = i.MemoryOperand(&index);
   1442         if (HasImmediateInput(instr, index)) {
   1443           __ movl(operand, i.InputImmediate(index));
   1444         } else {
   1445           __ movl(operand, i.InputRegister(index));
   1446         }
   1447       }
   1448       break;
   1449     case kX64Movsxlq:
   1450       ASSEMBLE_MOVX(movsxlq);
   1451       break;
   1452     case kX64Movq:
   1453       if (instr->HasOutput()) {
   1454         __ movq(i.OutputRegister(), i.MemoryOperand());
   1455       } else {
   1456         size_t index = 0;
   1457         Operand operand = i.MemoryOperand(&index);
   1458         if (HasImmediateInput(instr, index)) {
   1459           __ movq(operand, i.InputImmediate(index));
   1460         } else {
   1461           __ movq(operand, i.InputRegister(index));
   1462         }
   1463       }
   1464       break;
   1465     case kX64Movss:
   1466       if (instr->HasOutput()) {
   1467         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
   1468       } else {
   1469         size_t index = 0;
   1470         Operand operand = i.MemoryOperand(&index);
   1471         __ movss(operand, i.InputDoubleRegister(index));
   1472       }
   1473       break;
   1474     case kX64Movsd:
   1475       if (instr->HasOutput()) {
   1476         __ Movsd(i.OutputDoubleRegister(), i.MemoryOperand());
   1477       } else {
   1478         size_t index = 0;
   1479         Operand operand = i.MemoryOperand(&index);
   1480         __ Movsd(operand, i.InputDoubleRegister(index));
   1481       }
   1482       break;
   1483     case kX64BitcastFI:
   1484       if (instr->InputAt(0)->IsDoubleStackSlot()) {
   1485         __ movl(i.OutputRegister(), i.InputOperand(0));
   1486       } else {
   1487         __ Movd(i.OutputRegister(), i.InputDoubleRegister(0));
   1488       }
   1489       break;
   1490     case kX64BitcastDL:
   1491       if (instr->InputAt(0)->IsDoubleStackSlot()) {
   1492         __ movq(i.OutputRegister(), i.InputOperand(0));
   1493       } else {
   1494         __ Movq(i.OutputRegister(), i.InputDoubleRegister(0));
   1495       }
   1496       break;
   1497     case kX64BitcastIF:
   1498       if (instr->InputAt(0)->IsRegister()) {
   1499         __ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
   1500       } else {
   1501         __ movss(i.OutputDoubleRegister(), i.InputOperand(0));
   1502       }
   1503       break;
   1504     case kX64BitcastLD:
   1505       if (instr->InputAt(0)->IsRegister()) {
   1506         __ Movq(i.OutputDoubleRegister(), i.InputRegister(0));
   1507       } else {
   1508         __ Movsd(i.OutputDoubleRegister(), i.InputOperand(0));
   1509       }
   1510       break;
   1511     case kX64Lea32: {
   1512       AddressingMode mode = AddressingModeField::decode(instr->opcode());
   1513       // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
   1514       // and addressing mode just happens to work out. The "addl"/"subl" forms
   1515       // in these cases are faster based on measurements.
   1516       if (i.InputRegister(0).is(i.OutputRegister())) {
   1517         if (mode == kMode_MRI) {
   1518           int32_t constant_summand = i.InputInt32(1);
   1519           if (constant_summand > 0) {
   1520             __ addl(i.OutputRegister(), Immediate(constant_summand));
   1521           } else if (constant_summand < 0) {
   1522             __ subl(i.OutputRegister(), Immediate(-constant_summand));
   1523           }
   1524         } else if (mode == kMode_MR1) {
   1525           if (i.InputRegister(1).is(i.OutputRegister())) {
   1526             __ shll(i.OutputRegister(), Immediate(1));
   1527           } else {
   1528             __ leal(i.OutputRegister(), i.MemoryOperand());
   1529           }
   1530         } else if (mode == kMode_M2) {
   1531           __ shll(i.OutputRegister(), Immediate(1));
   1532         } else if (mode == kMode_M4) {
   1533           __ shll(i.OutputRegister(), Immediate(2));
   1534         } else if (mode == kMode_M8) {
   1535           __ shll(i.OutputRegister(), Immediate(3));
   1536         } else {
   1537           __ leal(i.OutputRegister(), i.MemoryOperand());
   1538         }
   1539       } else {
   1540         __ leal(i.OutputRegister(), i.MemoryOperand());
   1541       }
   1542       __ AssertZeroExtended(i.OutputRegister());
   1543       break;
   1544     }
   1545     case kX64Lea:
   1546       __ leaq(i.OutputRegister(), i.MemoryOperand());
   1547       break;
   1548     case kX64Dec32:
   1549       __ decl(i.OutputRegister());
   1550       break;
   1551     case kX64Inc32:
   1552       __ incl(i.OutputRegister());
   1553       break;
   1554     case kX64Push:
   1555       if (HasImmediateInput(instr, 0)) {
   1556         __ pushq(i.InputImmediate(0));
   1557         frame_access_state()->IncreaseSPDelta(1);
   1558       } else {
   1559         if (instr->InputAt(0)->IsRegister()) {
   1560           __ pushq(i.InputRegister(0));
   1561           frame_access_state()->IncreaseSPDelta(1);
   1562         } else if (instr->InputAt(0)->IsDoubleRegister()) {
   1563           // TODO(titzer): use another machine instruction?
   1564           __ subq(rsp, Immediate(kDoubleSize));
   1565           frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   1566           __ Movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
   1567         } else {
   1568           __ pushq(i.InputOperand(0));
   1569           frame_access_state()->IncreaseSPDelta(1);
   1570         }
   1571       }
   1572       break;
   1573     case kX64Poke: {
   1574       int const slot = MiscField::decode(instr->opcode());
   1575       if (HasImmediateInput(instr, 0)) {
   1576         __ movq(Operand(rsp, slot * kPointerSize), i.InputImmediate(0));
   1577       } else {
   1578         __ movq(Operand(rsp, slot * kPointerSize), i.InputRegister(0));
   1579       }
   1580       break;
   1581     }
   1582     case kCheckedLoadInt8:
   1583       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
   1584       break;
   1585     case kCheckedLoadUint8:
   1586       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
   1587       break;
   1588     case kCheckedLoadInt16:
   1589       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
   1590       break;
   1591     case kCheckedLoadUint16:
   1592       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
   1593       break;
   1594     case kCheckedLoadWord32:
   1595       ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
   1596       break;
   1597     case kCheckedLoadWord64:
   1598       ASSEMBLE_CHECKED_LOAD_INTEGER(movq);
   1599       break;
   1600     case kCheckedLoadFloat32:
   1601       ASSEMBLE_CHECKED_LOAD_FLOAT(Movss);
   1602       break;
   1603     case kCheckedLoadFloat64:
   1604       ASSEMBLE_CHECKED_LOAD_FLOAT(Movsd);
   1605       break;
   1606     case kCheckedStoreWord8:
   1607       ASSEMBLE_CHECKED_STORE_INTEGER(movb);
   1608       break;
   1609     case kCheckedStoreWord16:
   1610       ASSEMBLE_CHECKED_STORE_INTEGER(movw);
   1611       break;
   1612     case kCheckedStoreWord32:
   1613       ASSEMBLE_CHECKED_STORE_INTEGER(movl);
   1614       break;
   1615     case kCheckedStoreWord64:
   1616       ASSEMBLE_CHECKED_STORE_INTEGER(movq);
   1617       break;
   1618     case kCheckedStoreFloat32:
   1619       ASSEMBLE_CHECKED_STORE_FLOAT(Movss);
   1620       break;
   1621     case kCheckedStoreFloat64:
   1622       ASSEMBLE_CHECKED_STORE_FLOAT(Movsd);
   1623       break;
   1624     case kX64StackCheck:
   1625       __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
   1626       break;
   1627   }
   1628 }  // NOLINT(readability/fn_size)
   1629 
   1630 
   1631 // Assembles branches after this instruction.
   1632 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   1633   X64OperandConverter i(this, instr);
   1634   Label::Distance flabel_distance =
   1635       branch->fallthru ? Label::kNear : Label::kFar;
   1636   Label* tlabel = branch->true_label;
   1637   Label* flabel = branch->false_label;
   1638   switch (branch->condition) {
   1639     case kUnorderedEqual:
   1640       __ j(parity_even, flabel, flabel_distance);
   1641     // Fall through.
   1642     case kEqual:
   1643       __ j(equal, tlabel);
   1644       break;
   1645     case kUnorderedNotEqual:
   1646       __ j(parity_even, tlabel);
   1647     // Fall through.
   1648     case kNotEqual:
   1649       __ j(not_equal, tlabel);
   1650       break;
   1651     case kSignedLessThan:
   1652       __ j(less, tlabel);
   1653       break;
   1654     case kSignedGreaterThanOrEqual:
   1655       __ j(greater_equal, tlabel);
   1656       break;
   1657     case kSignedLessThanOrEqual:
   1658       __ j(less_equal, tlabel);
   1659       break;
   1660     case kSignedGreaterThan:
   1661       __ j(greater, tlabel);
   1662       break;
   1663     case kUnsignedLessThan:
   1664       __ j(below, tlabel);
   1665       break;
   1666     case kUnsignedGreaterThanOrEqual:
   1667       __ j(above_equal, tlabel);
   1668       break;
   1669     case kUnsignedLessThanOrEqual:
   1670       __ j(below_equal, tlabel);
   1671       break;
   1672     case kUnsignedGreaterThan:
   1673       __ j(above, tlabel);
   1674       break;
   1675     case kOverflow:
   1676       __ j(overflow, tlabel);
   1677       break;
   1678     case kNotOverflow:
   1679       __ j(no_overflow, tlabel);
   1680       break;
   1681     default:
   1682       UNREACHABLE();
   1683       break;
   1684   }
   1685   if (!branch->fallthru) __ jmp(flabel, flabel_distance);
   1686 }
   1687 
   1688 
   1689 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   1690   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
   1691 }
   1692 
   1693 
   1694 // Assembles boolean materializations after this instruction.
   1695 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   1696                                         FlagsCondition condition) {
   1697   X64OperandConverter i(this, instr);
   1698   Label done;
   1699 
   1700   // Materialize a full 64-bit 1 or 0 value. The result register is always the
   1701   // last output of the instruction.
   1702   Label check;
   1703   DCHECK_NE(0u, instr->OutputCount());
   1704   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   1705   Condition cc = no_condition;
   1706   switch (condition) {
   1707     case kUnorderedEqual:
   1708       __ j(parity_odd, &check, Label::kNear);
   1709       __ movl(reg, Immediate(0));
   1710       __ jmp(&done, Label::kNear);
   1711     // Fall through.
   1712     case kEqual:
   1713       cc = equal;
   1714       break;
   1715     case kUnorderedNotEqual:
   1716       __ j(parity_odd, &check, Label::kNear);
   1717       __ movl(reg, Immediate(1));
   1718       __ jmp(&done, Label::kNear);
   1719     // Fall through.
   1720     case kNotEqual:
   1721       cc = not_equal;
   1722       break;
   1723     case kSignedLessThan:
   1724       cc = less;
   1725       break;
   1726     case kSignedGreaterThanOrEqual:
   1727       cc = greater_equal;
   1728       break;
   1729     case kSignedLessThanOrEqual:
   1730       cc = less_equal;
   1731       break;
   1732     case kSignedGreaterThan:
   1733       cc = greater;
   1734       break;
   1735     case kUnsignedLessThan:
   1736       cc = below;
   1737       break;
   1738     case kUnsignedGreaterThanOrEqual:
   1739       cc = above_equal;
   1740       break;
   1741     case kUnsignedLessThanOrEqual:
   1742       cc = below_equal;
   1743       break;
   1744     case kUnsignedGreaterThan:
   1745       cc = above;
   1746       break;
   1747     case kOverflow:
   1748       cc = overflow;
   1749       break;
   1750     case kNotOverflow:
   1751       cc = no_overflow;
   1752       break;
   1753     default:
   1754       UNREACHABLE();
   1755       break;
   1756   }
   1757   __ bind(&check);
   1758   __ setcc(cc, reg);
   1759   __ movzxbl(reg, reg);
   1760   __ bind(&done);
   1761 }
   1762 
   1763 
   1764 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   1765   X64OperandConverter i(this, instr);
   1766   Register input = i.InputRegister(0);
   1767   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   1768     __ cmpl(input, Immediate(i.InputInt32(index + 0)));
   1769     __ j(equal, GetLabel(i.InputRpo(index + 1)));
   1770   }
   1771   AssembleArchJump(i.InputRpo(1));
   1772 }
   1773 
   1774 
   1775 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   1776   X64OperandConverter i(this, instr);
   1777   Register input = i.InputRegister(0);
   1778   int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
   1779   Label** cases = zone()->NewArray<Label*>(case_count);
   1780   for (int32_t index = 0; index < case_count; ++index) {
   1781     cases[index] = GetLabel(i.InputRpo(index + 2));
   1782   }
   1783   Label* const table = AddJumpTable(cases, case_count);
   1784   __ cmpl(input, Immediate(case_count));
   1785   __ j(above_equal, GetLabel(i.InputRpo(1)));
   1786   __ leaq(kScratchRegister, Operand(table));
   1787   __ jmp(Operand(kScratchRegister, input, times_8, 0));
   1788 }
   1789 
   1790 
   1791 void CodeGenerator::AssembleDeoptimizerCall(
   1792     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   1793   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   1794       isolate(), deoptimization_id, bailout_type);
   1795   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   1796 }
   1797 
   1798 
   1799 namespace {
   1800 
   1801 static const int kQuadWordSize = 16;
   1802 
   1803 }  // namespace
   1804 
   1805 
   1806 void CodeGenerator::AssemblePrologue() {
   1807   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1808   if (descriptor->IsCFunctionCall()) {
   1809     __ pushq(rbp);
   1810     __ movq(rbp, rsp);
   1811   } else if (descriptor->IsJSFunctionCall()) {
   1812     __ Prologue(this->info()->GeneratePreagedPrologue());
   1813   } else if (frame()->needs_frame()) {
   1814     __ StubPrologue();
   1815   } else {
   1816     frame()->SetElidedFrameSizeInSlots(kPCOnStackSize / kPointerSize);
   1817   }
   1818   frame_access_state()->SetFrameAccessToDefault();
   1819 
   1820   int stack_shrink_slots = frame()->GetSpillSlotCount();
   1821   if (info()->is_osr()) {
   1822     // TurboFan OSR-compiled functions cannot be entered directly.
   1823     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   1824 
   1825     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   1826     // frame is still on the stack. Optimized code uses OSR values directly from
   1827     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   1828     // remaining stack slots.
   1829     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   1830     osr_pc_offset_ = __ pc_offset();
   1831     // TODO(titzer): cannot address target function == local #-1
   1832     __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
   1833     stack_shrink_slots -=
   1834         static_cast<int>(OsrHelper(info()).UnoptimizedFrameSlots());
   1835   }
   1836 
   1837   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   1838   if (saves_fp != 0) {
   1839     stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots();
   1840   }
   1841   if (stack_shrink_slots > 0) {
   1842     __ subq(rsp, Immediate(stack_shrink_slots * kPointerSize));
   1843   }
   1844 
   1845   if (saves_fp != 0) {  // Save callee-saved XMM registers.
   1846     const uint32_t saves_fp_count = base::bits::CountPopulation32(saves_fp);
   1847     const int stack_size = saves_fp_count * kQuadWordSize;
   1848     // Adjust the stack pointer.
   1849     __ subp(rsp, Immediate(stack_size));
   1850     // Store the registers on the stack.
   1851     int slot_idx = 0;
   1852     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   1853       if (!((1 << i) & saves_fp)) continue;
   1854       __ movdqu(Operand(rsp, kQuadWordSize * slot_idx),
   1855                 XMMRegister::from_code(i));
   1856       slot_idx++;
   1857     }
   1858     frame()->AllocateSavedCalleeRegisterSlots(saves_fp_count *
   1859                                               (kQuadWordSize / kPointerSize));
   1860   }
   1861 
   1862   const RegList saves = descriptor->CalleeSavedRegisters();
   1863   if (saves != 0) {  // Save callee-saved registers.
   1864     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
   1865       if (!((1 << i) & saves)) continue;
   1866       __ pushq(Register::from_code(i));
   1867       frame()->AllocateSavedCalleeRegisterSlots(1);
   1868     }
   1869   }
   1870 }
   1871 
   1872 
   1873 void CodeGenerator::AssembleReturn() {
   1874   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1875 
   1876   // Restore registers.
   1877   const RegList saves = descriptor->CalleeSavedRegisters();
   1878   if (saves != 0) {
   1879     for (int i = 0; i < Register::kNumRegisters; i++) {
   1880       if (!((1 << i) & saves)) continue;
   1881       __ popq(Register::from_code(i));
   1882     }
   1883   }
   1884   const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
   1885   if (saves_fp != 0) {
   1886     const uint32_t saves_fp_count = base::bits::CountPopulation32(saves_fp);
   1887     const int stack_size = saves_fp_count * kQuadWordSize;
   1888     // Load the registers from the stack.
   1889     int slot_idx = 0;
   1890     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   1891       if (!((1 << i) & saves_fp)) continue;
   1892       __ movdqu(XMMRegister::from_code(i),
   1893                 Operand(rsp, kQuadWordSize * slot_idx));
   1894       slot_idx++;
   1895     }
   1896     // Adjust the stack pointer.
   1897     __ addp(rsp, Immediate(stack_size));
   1898   }
   1899 
   1900   if (descriptor->IsCFunctionCall()) {
   1901     __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
   1902     __ popq(rbp);       // Pop caller's frame pointer.
   1903   } else if (frame()->needs_frame()) {
   1904     // Canonicalize JSFunction return sites for now.
   1905     if (return_label_.is_bound()) {
   1906       __ jmp(&return_label_);
   1907       return;
   1908     } else {
   1909       __ bind(&return_label_);
   1910       __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
   1911       __ popq(rbp);       // Pop caller's frame pointer.
   1912     }
   1913   }
   1914   size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
   1915   // Might need rcx for scratch if pop_size is too big.
   1916   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & rcx.bit());
   1917   __ Ret(static_cast<int>(pop_size), rcx);
   1918 }
   1919 
   1920 
   1921 void CodeGenerator::AssembleMove(InstructionOperand* source,
   1922                                  InstructionOperand* destination) {
   1923   X64OperandConverter g(this, nullptr);
   1924   // Dispatch on the source and destination operand kinds.  Not all
   1925   // combinations are possible.
   1926   if (source->IsRegister()) {
   1927     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1928     Register src = g.ToRegister(source);
   1929     if (destination->IsRegister()) {
   1930       __ movq(g.ToRegister(destination), src);
   1931     } else {
   1932       __ movq(g.ToOperand(destination), src);
   1933     }
   1934   } else if (source->IsStackSlot()) {
   1935     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1936     Operand src = g.ToOperand(source);
   1937     if (destination->IsRegister()) {
   1938       Register dst = g.ToRegister(destination);
   1939       __ movq(dst, src);
   1940     } else {
   1941       // Spill on demand to use a temporary register for memory-to-memory
   1942       // moves.
   1943       Register tmp = kScratchRegister;
   1944       Operand dst = g.ToOperand(destination);
   1945       __ movq(tmp, src);
   1946       __ movq(dst, tmp);
   1947     }
   1948   } else if (source->IsConstant()) {
   1949     ConstantOperand* constant_source = ConstantOperand::cast(source);
   1950     Constant src = g.ToConstant(constant_source);
   1951     if (destination->IsRegister() || destination->IsStackSlot()) {
   1952       Register dst = destination->IsRegister() ? g.ToRegister(destination)
   1953                                                : kScratchRegister;
   1954       switch (src.type()) {
   1955         case Constant::kInt32:
   1956           // TODO(dcarney): don't need scratch in this case.
   1957           __ Set(dst, src.ToInt32());
   1958           break;
   1959         case Constant::kInt64:
   1960           __ Set(dst, src.ToInt64());
   1961           break;
   1962         case Constant::kFloat32:
   1963           __ Move(dst,
   1964                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   1965           break;
   1966         case Constant::kFloat64:
   1967           __ Move(dst,
   1968                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   1969           break;
   1970         case Constant::kExternalReference:
   1971           __ Move(dst, src.ToExternalReference());
   1972           break;
   1973         case Constant::kHeapObject: {
   1974           Handle<HeapObject> src_object = src.ToHeapObject();
   1975           Heap::RootListIndex index;
   1976           int offset;
   1977           if (IsMaterializableFromFrame(src_object, &offset)) {
   1978             __ movp(dst, Operand(rbp, offset));
   1979           } else if (IsMaterializableFromRoot(src_object, &index)) {
   1980             __ LoadRoot(dst, index);
   1981           } else {
   1982             __ Move(dst, src_object);
   1983           }
   1984           break;
   1985         }
   1986         case Constant::kRpoNumber:
   1987           UNREACHABLE();  // TODO(dcarney): load of labels on x64.
   1988           break;
   1989       }
   1990       if (destination->IsStackSlot()) {
   1991         __ movq(g.ToOperand(destination), kScratchRegister);
   1992       }
   1993     } else if (src.type() == Constant::kFloat32) {
   1994       // TODO(turbofan): Can we do better here?
   1995       uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
   1996       if (destination->IsDoubleRegister()) {
   1997         __ Move(g.ToDoubleRegister(destination), src_const);
   1998       } else {
   1999         DCHECK(destination->IsDoubleStackSlot());
   2000         Operand dst = g.ToOperand(destination);
   2001         __ movl(dst, Immediate(src_const));
   2002       }
   2003     } else {
   2004       DCHECK_EQ(Constant::kFloat64, src.type());
   2005       uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
   2006       if (destination->IsDoubleRegister()) {
   2007         __ Move(g.ToDoubleRegister(destination), src_const);
   2008       } else {
   2009         DCHECK(destination->IsDoubleStackSlot());
   2010         __ movq(kScratchRegister, src_const);
   2011         __ movq(g.ToOperand(destination), kScratchRegister);
   2012       }
   2013     }
   2014   } else if (source->IsDoubleRegister()) {
   2015     XMMRegister src = g.ToDoubleRegister(source);
   2016     if (destination->IsDoubleRegister()) {
   2017       XMMRegister dst = g.ToDoubleRegister(destination);
   2018       __ Movapd(dst, src);
   2019     } else {
   2020       DCHECK(destination->IsDoubleStackSlot());
   2021       Operand dst = g.ToOperand(destination);
   2022       __ Movsd(dst, src);
   2023     }
   2024   } else if (source->IsDoubleStackSlot()) {
   2025     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
   2026     Operand src = g.ToOperand(source);
   2027     if (destination->IsDoubleRegister()) {
   2028       XMMRegister dst = g.ToDoubleRegister(destination);
   2029       __ Movsd(dst, src);
   2030     } else {
   2031       // We rely on having xmm0 available as a fixed scratch register.
   2032       Operand dst = g.ToOperand(destination);
   2033       __ Movsd(xmm0, src);
   2034       __ Movsd(dst, xmm0);
   2035     }
   2036   } else {
   2037     UNREACHABLE();
   2038   }
   2039 }
   2040 
   2041 
   2042 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   2043                                  InstructionOperand* destination) {
   2044   X64OperandConverter g(this, nullptr);
   2045   // Dispatch on the source and destination operand kinds.  Not all
   2046   // combinations are possible.
   2047   if (source->IsRegister() && destination->IsRegister()) {
   2048     // Register-register.
   2049     Register src = g.ToRegister(source);
   2050     Register dst = g.ToRegister(destination);
   2051     __ movq(kScratchRegister, src);
   2052     __ movq(src, dst);
   2053     __ movq(dst, kScratchRegister);
   2054   } else if (source->IsRegister() && destination->IsStackSlot()) {
   2055     Register src = g.ToRegister(source);
   2056     __ pushq(src);
   2057     frame_access_state()->IncreaseSPDelta(1);
   2058     Operand dst = g.ToOperand(destination);
   2059     __ movq(src, dst);
   2060     frame_access_state()->IncreaseSPDelta(-1);
   2061     dst = g.ToOperand(destination);
   2062     __ popq(dst);
   2063   } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
   2064              (source->IsDoubleStackSlot() &&
   2065               destination->IsDoubleStackSlot())) {
   2066     // Memory-memory.
   2067     Register tmp = kScratchRegister;
   2068     Operand src = g.ToOperand(source);
   2069     Operand dst = g.ToOperand(destination);
   2070     __ movq(tmp, dst);
   2071     __ pushq(src);
   2072     frame_access_state()->IncreaseSPDelta(1);
   2073     src = g.ToOperand(source);
   2074     __ movq(src, tmp);
   2075     frame_access_state()->IncreaseSPDelta(-1);
   2076     dst = g.ToOperand(destination);
   2077     __ popq(dst);
   2078   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
   2079     // XMM register-register swap. We rely on having xmm0
   2080     // available as a fixed scratch register.
   2081     XMMRegister src = g.ToDoubleRegister(source);
   2082     XMMRegister dst = g.ToDoubleRegister(destination);
   2083     __ Movapd(xmm0, src);
   2084     __ Movapd(src, dst);
   2085     __ Movapd(dst, xmm0);
   2086   } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
   2087     // XMM register-memory swap.  We rely on having xmm0
   2088     // available as a fixed scratch register.
   2089     XMMRegister src = g.ToDoubleRegister(source);
   2090     Operand dst = g.ToOperand(destination);
   2091     __ Movsd(xmm0, src);
   2092     __ Movsd(src, dst);
   2093     __ Movsd(dst, xmm0);
   2094   } else {
   2095     // No other combinations are possible.
   2096     UNREACHABLE();
   2097   }
   2098 }
   2099 
   2100 
   2101 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   2102   for (size_t index = 0; index < target_count; ++index) {
   2103     __ dq(targets[index]);
   2104   }
   2105 }
   2106 
   2107 
   2108 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
   2109 
   2110 
   2111 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   2112   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   2113     return;
   2114   }
   2115 
   2116   int space_needed = Deoptimizer::patch_size();
   2117   // Ensure that we have enough space after the previous lazy-bailout
   2118   // instruction for patching the code here.
   2119   int current_pc = masm()->pc_offset();
   2120   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   2121     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   2122     __ Nop(padding_size);
   2123   }
   2124 }
   2125 
   2126 #undef __
   2127 
   2128 }  // namespace compiler
   2129 }  // namespace internal
   2130 }  // namespace v8
   2131