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