[turbofan] Add checked load/store operators.
[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/compiler/node-properties-inl.h"
11 #include "src/scopes.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 // Adds X64 specific methods for decoding operands.
23 class X64OperandConverter : public InstructionOperandConverter {
24  public:
25   X64OperandConverter(CodeGenerator* gen, Instruction* instr)
26       : InstructionOperandConverter(gen, instr) {}
27
28   Immediate InputImmediate(int index) {
29     return ToImmediate(instr_->InputAt(index));
30   }
31
32   Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
33
34   Operand OutputOperand() { return ToOperand(instr_->Output()); }
35
36   Immediate ToImmediate(InstructionOperand* operand) {
37     return Immediate(ToConstant(operand).ToInt32());
38   }
39
40   Operand ToOperand(InstructionOperand* op, int extra = 0) {
41     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
42     // The linkage computes where all spill slots are located.
43     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
44     return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
45   }
46
47   static int NextOffset(int* offset) {
48     int i = *offset;
49     (*offset)++;
50     return i;
51   }
52
53   static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
54     STATIC_ASSERT(0 == static_cast<int>(times_1));
55     STATIC_ASSERT(1 == static_cast<int>(times_2));
56     STATIC_ASSERT(2 == static_cast<int>(times_4));
57     STATIC_ASSERT(3 == static_cast<int>(times_8));
58     int scale = static_cast<int>(mode - one);
59     DCHECK(scale >= 0 && scale < 4);
60     return static_cast<ScaleFactor>(scale);
61   }
62
63   Operand MemoryOperand(int* offset) {
64     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
65     switch (mode) {
66       case kMode_MR: {
67         Register base = InputRegister(NextOffset(offset));
68         int32_t disp = 0;
69         return Operand(base, disp);
70       }
71       case kMode_MRI: {
72         Register base = InputRegister(NextOffset(offset));
73         int32_t disp = InputInt32(NextOffset(offset));
74         return Operand(base, disp);
75       }
76       case kMode_MR1:
77       case kMode_MR2:
78       case kMode_MR4:
79       case kMode_MR8: {
80         Register base = InputRegister(NextOffset(offset));
81         Register index = InputRegister(NextOffset(offset));
82         ScaleFactor scale = ScaleFor(kMode_MR1, mode);
83         int32_t disp = 0;
84         return Operand(base, index, scale, disp);
85       }
86       case kMode_MR1I:
87       case kMode_MR2I:
88       case kMode_MR4I:
89       case kMode_MR8I: {
90         Register base = InputRegister(NextOffset(offset));
91         Register index = InputRegister(NextOffset(offset));
92         ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
93         int32_t disp = InputInt32(NextOffset(offset));
94         return Operand(base, index, scale, disp);
95       }
96       case kMode_M1:
97       case kMode_M2:
98       case kMode_M4:
99       case kMode_M8: {
100         Register index = InputRegister(NextOffset(offset));
101         ScaleFactor scale = ScaleFor(kMode_M1, mode);
102         int32_t disp = 0;
103         return Operand(index, scale, disp);
104       }
105       case kMode_M1I:
106       case kMode_M2I:
107       case kMode_M4I:
108       case kMode_M8I: {
109         Register index = InputRegister(NextOffset(offset));
110         ScaleFactor scale = ScaleFor(kMode_M1I, mode);
111         int32_t disp = InputInt32(NextOffset(offset));
112         return Operand(index, scale, disp);
113       }
114       case kMode_None:
115         UNREACHABLE();
116         return Operand(no_reg, 0);
117     }
118     UNREACHABLE();
119     return Operand(no_reg, 0);
120   }
121
122   Operand MemoryOperand(int first_input = 0) {
123     return MemoryOperand(&first_input);
124   }
125 };
126
127
128 namespace {
129
130 bool HasImmediateInput(Instruction* instr, int index) {
131   return instr->InputAt(index)->IsImmediate();
132 }
133
134
135 class OutOfLineLoadInteger FINAL : public OutOfLineCode {
136  public:
137   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
138       : OutOfLineCode(gen), result_(result) {}
139
140   void Generate() FINAL { __ xorl(result_, result_); }
141
142  private:
143   Register const result_;
144 };
145
146
147 class OutOfLineLoadFloat FINAL : public OutOfLineCode {
148  public:
149   OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
150       : OutOfLineCode(gen), result_(result) {}
151
152   void Generate() FINAL { __ pcmpeqd(result_, result_); }
153
154  private:
155   XMMRegister const result_;
156 };
157
158 }  // namespace
159
160
161 #define ASSEMBLE_UNOP(asm_instr)         \
162   do {                                   \
163     if (instr->Output()->IsRegister()) { \
164       __ asm_instr(i.OutputRegister());  \
165     } else {                             \
166       __ asm_instr(i.OutputOperand());   \
167     }                                    \
168   } while (0)
169
170
171 #define ASSEMBLE_BINOP(asm_instr)                              \
172   do {                                                         \
173     if (HasImmediateInput(instr, 1)) {                         \
174       if (instr->InputAt(0)->IsRegister()) {                   \
175         __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
176       } else {                                                 \
177         __ asm_instr(i.InputOperand(0), i.InputImmediate(1));  \
178       }                                                        \
179     } else {                                                   \
180       if (instr->InputAt(1)->IsRegister()) {                   \
181         __ asm_instr(i.InputRegister(0), i.InputRegister(1));  \
182       } else {                                                 \
183         __ asm_instr(i.InputRegister(0), i.InputOperand(1));   \
184       }                                                        \
185     }                                                          \
186   } while (0)
187
188
189 #define ASSEMBLE_MULT(asm_instr)                              \
190   do {                                                        \
191     if (HasImmediateInput(instr, 1)) {                        \
192       if (instr->InputAt(0)->IsRegister()) {                  \
193         __ asm_instr(i.OutputRegister(), i.InputRegister(0),  \
194                      i.InputImmediate(1));                    \
195       } else {                                                \
196         __ asm_instr(i.OutputRegister(), i.InputOperand(0),   \
197                      i.InputImmediate(1));                    \
198       }                                                       \
199     } else {                                                  \
200       if (instr->InputAt(1)->IsRegister()) {                  \
201         __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
202       } else {                                                \
203         __ asm_instr(i.OutputRegister(), i.InputOperand(1));  \
204       }                                                       \
205     }                                                         \
206   } while (0)
207
208
209 #define ASSEMBLE_SHIFT(asm_instr, width)                                   \
210   do {                                                                     \
211     if (HasImmediateInput(instr, 1)) {                                     \
212       if (instr->Output()->IsRegister()) {                                 \
213         __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
214       } else {                                                             \
215         __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1)));  \
216       }                                                                    \
217     } else {                                                               \
218       if (instr->Output()->IsRegister()) {                                 \
219         __ asm_instr##_cl(i.OutputRegister());                             \
220       } else {                                                             \
221         __ asm_instr##_cl(i.OutputOperand());                              \
222       }                                                                    \
223     }                                                                      \
224   } while (0)
225
226
227 #define ASSEMBLE_DOUBLE_BINOP(asm_instr)                                \
228   do {                                                                  \
229     if (instr->InputAt(1)->IsDoubleRegister()) {                        \
230       __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
231     } else {                                                            \
232       __ asm_instr(i.InputDoubleRegister(0), i.InputOperand(1));        \
233     }                                                                   \
234   } while (0)
235
236
237 #define ASSEMBLE_AVX_DOUBLE_BINOP(asm_instr)                           \
238   do {                                                                 \
239     CpuFeatureScope avx_scope(masm(), AVX);                            \
240     if (instr->InputAt(1)->IsDoubleRegister()) {                       \
241       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
242                    i.InputDoubleRegister(1));                          \
243     } else {                                                           \
244       __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
245                    i.InputOperand(1));                                 \
246     }                                                                  \
247   } while (0)
248
249
250 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr)                          \
251   do {                                                                  \
252     auto result = i.OutputDoubleRegister();                             \
253     auto offset = i.InputRegister(0);                                   \
254     if (instr->InputAt(1)->IsRegister()) {                              \
255       __ cmpl(offset, i.InputRegister(1));                              \
256     } else {                                                            \
257       __ cmpl(offset, i.InputImmediate(1));                             \
258     }                                                                   \
259     OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
260     __ j(above_equal, ool->entry());                                    \
261     __ asm_instr(result, i.MemoryOperand(2));                           \
262     __ bind(ool->exit());                                               \
263   } while (false)
264
265
266 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                          \
267   do {                                                                    \
268     auto result = i.OutputRegister();                                     \
269     auto offset = i.InputRegister(0);                                     \
270     if (instr->InputAt(1)->IsRegister()) {                                \
271       __ cmpl(offset, i.InputRegister(1));                                \
272     } else {                                                              \
273       __ cmpl(offset, i.InputImmediate(1));                               \
274     }                                                                     \
275     OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
276     __ j(above_equal, ool->entry());                                      \
277     __ asm_instr(result, i.MemoryOperand(2));                             \
278     __ bind(ool->exit());                                                 \
279   } while (false)
280
281
282 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)                 \
283   do {                                                          \
284     auto offset = i.InputRegister(0);                           \
285     if (instr->InputAt(1)->IsRegister()) {                      \
286       __ cmpl(offset, i.InputRegister(1));                      \
287     } else {                                                    \
288       __ cmpl(offset, i.InputImmediate(1));                     \
289     }                                                           \
290     Label done;                                                 \
291     __ j(above_equal, &done, Label::kNear);                     \
292     __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
293     __ bind(&done);                                             \
294   } while (false)
295
296
297 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)            \
298   do {                                                       \
299     auto offset = i.InputRegister(0);                        \
300     if (instr->InputAt(1)->IsRegister()) {                   \
301       __ cmpl(offset, i.InputRegister(1));                   \
302     } else {                                                 \
303       __ cmpl(offset, i.InputImmediate(1));                  \
304     }                                                        \
305     Label done;                                              \
306     __ j(above_equal, &done, Label::kNear);                  \
307     if (instr->InputAt(2)->IsRegister()) {                   \
308       __ asm_instr(i.MemoryOperand(3), i.InputRegister(2));  \
309     } else {                                                 \
310       __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
311     }                                                        \
312     __ bind(&done);                                          \
313   } while (false)
314
315
316 // Assembles an instruction after register allocation, producing machine code.
317 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
318   X64OperandConverter i(this, instr);
319
320   switch (ArchOpcodeField::decode(instr->opcode())) {
321     case kArchCallCodeObject: {
322       EnsureSpaceForLazyDeopt();
323       if (HasImmediateInput(instr, 0)) {
324         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
325         __ Call(code, RelocInfo::CODE_TARGET);
326       } else {
327         Register reg = i.InputRegister(0);
328         int entry = Code::kHeaderSize - kHeapObjectTag;
329         __ Call(Operand(reg, entry));
330       }
331       AddSafepointAndDeopt(instr);
332       break;
333     }
334     case kArchCallJSFunction: {
335       EnsureSpaceForLazyDeopt();
336       Register func = i.InputRegister(0);
337       if (FLAG_debug_code) {
338         // Check the function's context matches the context argument.
339         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
340         __ Assert(equal, kWrongFunctionContext);
341       }
342       __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
343       AddSafepointAndDeopt(instr);
344       break;
345     }
346     case kArchJmp:
347       AssembleArchJump(i.InputRpo(0));
348       break;
349     case kArchNop:
350       // don't emit code for nops.
351       break;
352     case kArchRet:
353       AssembleReturn();
354       break;
355     case kArchStackPointer:
356       __ movq(i.OutputRegister(), rsp);
357       break;
358     case kArchTruncateDoubleToI:
359       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
360       break;
361     case kX64Add32:
362       ASSEMBLE_BINOP(addl);
363       break;
364     case kX64Add:
365       ASSEMBLE_BINOP(addq);
366       break;
367     case kX64Sub32:
368       ASSEMBLE_BINOP(subl);
369       break;
370     case kX64Sub:
371       ASSEMBLE_BINOP(subq);
372       break;
373     case kX64And32:
374       ASSEMBLE_BINOP(andl);
375       break;
376     case kX64And:
377       ASSEMBLE_BINOP(andq);
378       break;
379     case kX64Cmp32:
380       ASSEMBLE_BINOP(cmpl);
381       break;
382     case kX64Cmp:
383       ASSEMBLE_BINOP(cmpq);
384       break;
385     case kX64Test32:
386       ASSEMBLE_BINOP(testl);
387       break;
388     case kX64Test:
389       ASSEMBLE_BINOP(testq);
390       break;
391     case kX64Imul32:
392       ASSEMBLE_MULT(imull);
393       break;
394     case kX64Imul:
395       ASSEMBLE_MULT(imulq);
396       break;
397     case kX64ImulHigh32:
398       if (instr->InputAt(1)->IsRegister()) {
399         __ imull(i.InputRegister(1));
400       } else {
401         __ imull(i.InputOperand(1));
402       }
403       break;
404     case kX64UmulHigh32:
405       if (instr->InputAt(1)->IsRegister()) {
406         __ mull(i.InputRegister(1));
407       } else {
408         __ mull(i.InputOperand(1));
409       }
410       break;
411     case kX64Idiv32:
412       __ cdq();
413       __ idivl(i.InputRegister(1));
414       break;
415     case kX64Idiv:
416       __ cqo();
417       __ idivq(i.InputRegister(1));
418       break;
419     case kX64Udiv32:
420       __ xorl(rdx, rdx);
421       __ divl(i.InputRegister(1));
422       break;
423     case kX64Udiv:
424       __ xorq(rdx, rdx);
425       __ divq(i.InputRegister(1));
426       break;
427     case kX64Not:
428       ASSEMBLE_UNOP(notq);
429       break;
430     case kX64Not32:
431       ASSEMBLE_UNOP(notl);
432       break;
433     case kX64Neg:
434       ASSEMBLE_UNOP(negq);
435       break;
436     case kX64Neg32:
437       ASSEMBLE_UNOP(negl);
438       break;
439     case kX64Or32:
440       ASSEMBLE_BINOP(orl);
441       break;
442     case kX64Or:
443       ASSEMBLE_BINOP(orq);
444       break;
445     case kX64Xor32:
446       ASSEMBLE_BINOP(xorl);
447       break;
448     case kX64Xor:
449       ASSEMBLE_BINOP(xorq);
450       break;
451     case kX64Shl32:
452       ASSEMBLE_SHIFT(shll, 5);
453       break;
454     case kX64Shl:
455       ASSEMBLE_SHIFT(shlq, 6);
456       break;
457     case kX64Shr32:
458       ASSEMBLE_SHIFT(shrl, 5);
459       break;
460     case kX64Shr:
461       ASSEMBLE_SHIFT(shrq, 6);
462       break;
463     case kX64Sar32:
464       ASSEMBLE_SHIFT(sarl, 5);
465       break;
466     case kX64Sar:
467       ASSEMBLE_SHIFT(sarq, 6);
468       break;
469     case kX64Ror32:
470       ASSEMBLE_SHIFT(rorl, 5);
471       break;
472     case kX64Ror:
473       ASSEMBLE_SHIFT(rorq, 6);
474       break;
475     case kSSEFloat64Cmp:
476       ASSEMBLE_DOUBLE_BINOP(ucomisd);
477       break;
478     case kSSEFloat64Add:
479       ASSEMBLE_DOUBLE_BINOP(addsd);
480       break;
481     case kSSEFloat64Sub:
482       ASSEMBLE_DOUBLE_BINOP(subsd);
483       break;
484     case kSSEFloat64Mul:
485       ASSEMBLE_DOUBLE_BINOP(mulsd);
486       break;
487     case kSSEFloat64Div:
488       ASSEMBLE_DOUBLE_BINOP(divsd);
489       break;
490     case kSSEFloat64Mod: {
491       __ subq(rsp, Immediate(kDoubleSize));
492       // Move values to st(0) and st(1).
493       __ movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
494       __ fld_d(Operand(rsp, 0));
495       __ movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
496       __ fld_d(Operand(rsp, 0));
497       // Loop while fprem isn't done.
498       Label mod_loop;
499       __ bind(&mod_loop);
500       // This instructions traps on all kinds inputs, but we are assuming the
501       // floating point control word is set to ignore them all.
502       __ fprem();
503       // The following 2 instruction implicitly use rax.
504       __ fnstsw_ax();
505       if (CpuFeatures::IsSupported(SAHF) && masm()->IsEnabled(SAHF)) {
506         __ sahf();
507       } else {
508         __ shrl(rax, Immediate(8));
509         __ andl(rax, Immediate(0xFF));
510         __ pushq(rax);
511         __ popfq();
512       }
513       __ j(parity_even, &mod_loop);
514       // Move output to stack and clean up.
515       __ fstp(1);
516       __ fstp_d(Operand(rsp, 0));
517       __ movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
518       __ addq(rsp, Immediate(kDoubleSize));
519       break;
520     }
521     case kSSEFloat64Sqrt:
522       if (instr->InputAt(0)->IsDoubleRegister()) {
523         __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
524       } else {
525         __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
526       }
527       break;
528     case kSSEFloat64Floor: {
529       CpuFeatureScope sse_scope(masm(), SSE4_1);
530       __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
531                  v8::internal::Assembler::kRoundDown);
532       break;
533     }
534     case kSSEFloat64Ceil: {
535       CpuFeatureScope sse_scope(masm(), SSE4_1);
536       __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
537                  v8::internal::Assembler::kRoundUp);
538       break;
539     }
540     case kSSEFloat64RoundTruncate: {
541       CpuFeatureScope sse_scope(masm(), SSE4_1);
542       __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
543                  v8::internal::Assembler::kRoundToZero);
544       break;
545     }
546     case kSSECvtss2sd:
547       if (instr->InputAt(0)->IsDoubleRegister()) {
548         __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
549       } else {
550         __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
551       }
552       break;
553     case kSSECvtsd2ss:
554       if (instr->InputAt(0)->IsDoubleRegister()) {
555         __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
556       } else {
557         __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
558       }
559       break;
560     case kSSEFloat64ToInt32:
561       if (instr->InputAt(0)->IsDoubleRegister()) {
562         __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
563       } else {
564         __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
565       }
566       break;
567     case kSSEFloat64ToUint32: {
568       if (instr->InputAt(0)->IsDoubleRegister()) {
569         __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
570       } else {
571         __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
572       }
573       __ AssertZeroExtended(i.OutputRegister());
574       break;
575     }
576     case kSSEInt32ToFloat64:
577       if (instr->InputAt(0)->IsRegister()) {
578         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
579       } else {
580         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
581       }
582       break;
583     case kSSEUint32ToFloat64:
584       if (instr->InputAt(0)->IsRegister()) {
585         __ movl(kScratchRegister, i.InputRegister(0));
586       } else {
587         __ movl(kScratchRegister, i.InputOperand(0));
588       }
589       __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
590       break;
591     case kAVXFloat64Add:
592       ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
593       break;
594     case kAVXFloat64Sub:
595       ASSEMBLE_AVX_DOUBLE_BINOP(vsubsd);
596       break;
597     case kAVXFloat64Mul:
598       ASSEMBLE_AVX_DOUBLE_BINOP(vmulsd);
599       break;
600     case kAVXFloat64Div:
601       ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
602       break;
603     case kX64Movsxbl:
604       if (instr->addressing_mode() != kMode_None) {
605         __ movsxbl(i.OutputRegister(), i.MemoryOperand());
606       } else if (instr->InputAt(0)->IsRegister()) {
607         __ movsxbl(i.OutputRegister(), i.InputRegister(0));
608       } else {
609         __ movsxbl(i.OutputRegister(), i.InputOperand(0));
610       }
611       __ AssertZeroExtended(i.OutputRegister());
612       break;
613     case kX64Movzxbl:
614       __ movzxbl(i.OutputRegister(), i.MemoryOperand());
615       break;
616     case kX64Movb: {
617       int index = 0;
618       Operand operand = i.MemoryOperand(&index);
619       if (HasImmediateInput(instr, index)) {
620         __ movb(operand, Immediate(i.InputInt8(index)));
621       } else {
622         __ movb(operand, i.InputRegister(index));
623       }
624       break;
625     }
626     case kX64Movsxwl:
627       if (instr->addressing_mode() != kMode_None) {
628         __ movsxwl(i.OutputRegister(), i.MemoryOperand());
629       } else if (instr->InputAt(0)->IsRegister()) {
630         __ movsxwl(i.OutputRegister(), i.InputRegister(0));
631       } else {
632         __ movsxwl(i.OutputRegister(), i.InputOperand(0));
633       }
634       __ AssertZeroExtended(i.OutputRegister());
635       break;
636     case kX64Movzxwl:
637       __ movzxwl(i.OutputRegister(), i.MemoryOperand());
638       __ AssertZeroExtended(i.OutputRegister());
639       break;
640     case kX64Movw: {
641       int index = 0;
642       Operand operand = i.MemoryOperand(&index);
643       if (HasImmediateInput(instr, index)) {
644         __ movw(operand, Immediate(i.InputInt16(index)));
645       } else {
646         __ movw(operand, i.InputRegister(index));
647       }
648       break;
649     }
650     case kX64Movl:
651       if (instr->HasOutput()) {
652         if (instr->addressing_mode() == kMode_None) {
653           if (instr->InputAt(0)->IsRegister()) {
654             __ movl(i.OutputRegister(), i.InputRegister(0));
655           } else {
656             __ movl(i.OutputRegister(), i.InputOperand(0));
657           }
658         } else {
659           __ movl(i.OutputRegister(), i.MemoryOperand());
660         }
661         __ AssertZeroExtended(i.OutputRegister());
662       } else {
663         int index = 0;
664         Operand operand = i.MemoryOperand(&index);
665         if (HasImmediateInput(instr, index)) {
666           __ movl(operand, i.InputImmediate(index));
667         } else {
668           __ movl(operand, i.InputRegister(index));
669         }
670       }
671       break;
672     case kX64Movsxlq: {
673       if (instr->InputAt(0)->IsRegister()) {
674         __ movsxlq(i.OutputRegister(), i.InputRegister(0));
675       } else {
676         __ movsxlq(i.OutputRegister(), i.InputOperand(0));
677       }
678       break;
679     }
680     case kX64Movq:
681       if (instr->HasOutput()) {
682         __ movq(i.OutputRegister(), i.MemoryOperand());
683       } else {
684         int index = 0;
685         Operand operand = i.MemoryOperand(&index);
686         if (HasImmediateInput(instr, index)) {
687           __ movq(operand, i.InputImmediate(index));
688         } else {
689           __ movq(operand, i.InputRegister(index));
690         }
691       }
692       break;
693     case kX64Movss:
694       if (instr->HasOutput()) {
695         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
696       } else {
697         int index = 0;
698         Operand operand = i.MemoryOperand(&index);
699         __ movss(operand, i.InputDoubleRegister(index));
700       }
701       break;
702     case kX64Movsd:
703       if (instr->HasOutput()) {
704         __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
705       } else {
706         int index = 0;
707         Operand operand = i.MemoryOperand(&index);
708         __ movsd(operand, i.InputDoubleRegister(index));
709       }
710       break;
711     case kX64Lea32: {
712       AddressingMode mode = AddressingModeField::decode(instr->opcode());
713       // Shorten "leal" to "addl" or "subl" if the register allocation just
714       // happens to work out for operations with immediate operands where the
715       // non-constant input register is the same as output register. The
716       // "addl"/"subl" forms in these cases are faster based on empirical
717       // measurements.
718       if (mode == kMode_MRI && i.InputRegister(0).is(i.OutputRegister())) {
719         int32_t constant_summand = i.InputInt32(1);
720         if (constant_summand > 0) {
721           __ addl(i.OutputRegister(), Immediate(constant_summand));
722         } else if (constant_summand < 0) {
723           __ subl(i.OutputRegister(), Immediate(-constant_summand));
724         }
725       } else {
726         __ leal(i.OutputRegister(), i.MemoryOperand());
727       }
728       __ AssertZeroExtended(i.OutputRegister());
729       break;
730     }
731     case kX64Lea:
732       __ leaq(i.OutputRegister(), i.MemoryOperand());
733       break;
734     case kX64Dec32:
735       __ decl(i.OutputRegister());
736       break;
737     case kX64Inc32:
738       __ incl(i.OutputRegister());
739       break;
740     case kX64Push:
741       if (HasImmediateInput(instr, 0)) {
742         __ pushq(i.InputImmediate(0));
743       } else {
744         if (instr->InputAt(0)->IsRegister()) {
745           __ pushq(i.InputRegister(0));
746         } else {
747           __ pushq(i.InputOperand(0));
748         }
749       }
750       break;
751     case kX64StoreWriteBarrier: {
752       Register object = i.InputRegister(0);
753       Register index = i.InputRegister(1);
754       Register value = i.InputRegister(2);
755       __ movsxlq(index, index);
756       __ movq(Operand(object, index, times_1, 0), value);
757       __ leaq(index, Operand(object, index, times_1, 0));
758       SaveFPRegsMode mode =
759           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
760       __ RecordWrite(object, index, value, mode);
761       break;
762     }
763     case kCheckedLoadInt8:
764       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
765       break;
766     case kCheckedLoadUint8:
767       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
768       break;
769     case kCheckedLoadInt16:
770       ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
771       break;
772     case kCheckedLoadUint16:
773       ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
774       break;
775     case kCheckedLoadWord32:
776       ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
777       break;
778     case kCheckedLoadFloat32:
779       ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
780       break;
781     case kCheckedLoadFloat64:
782       ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
783       break;
784     case kCheckedStoreWord8:
785       ASSEMBLE_CHECKED_STORE_INTEGER(movb);
786       break;
787     case kCheckedStoreWord16:
788       ASSEMBLE_CHECKED_STORE_INTEGER(movw);
789       break;
790     case kCheckedStoreWord32:
791       ASSEMBLE_CHECKED_STORE_INTEGER(movl);
792       break;
793     case kCheckedStoreFloat32:
794       ASSEMBLE_CHECKED_STORE_FLOAT(movss);
795       break;
796     case kCheckedStoreFloat64:
797       ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
798       break;
799   }
800 }
801
802
803 // Assembles branches after this instruction.
804 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
805   X64OperandConverter i(this, instr);
806   Label::Distance flabel_distance =
807       branch->fallthru ? Label::kNear : Label::kFar;
808   Label* tlabel = branch->true_label;
809   Label* flabel = branch->false_label;
810   switch (branch->condition) {
811     case kUnorderedEqual:
812       __ j(parity_even, flabel, flabel_distance);
813     // Fall through.
814     case kEqual:
815       __ j(equal, tlabel);
816       break;
817     case kUnorderedNotEqual:
818       __ j(parity_even, tlabel);
819     // Fall through.
820     case kNotEqual:
821       __ j(not_equal, tlabel);
822       break;
823     case kSignedLessThan:
824       __ j(less, tlabel);
825       break;
826     case kSignedGreaterThanOrEqual:
827       __ j(greater_equal, tlabel);
828       break;
829     case kSignedLessThanOrEqual:
830       __ j(less_equal, tlabel);
831       break;
832     case kSignedGreaterThan:
833       __ j(greater, tlabel);
834       break;
835     case kUnorderedLessThan:
836       __ j(parity_even, flabel, flabel_distance);
837     // Fall through.
838     case kUnsignedLessThan:
839       __ j(below, tlabel);
840       break;
841     case kUnorderedGreaterThanOrEqual:
842       __ j(parity_even, tlabel);
843     // Fall through.
844     case kUnsignedGreaterThanOrEqual:
845       __ j(above_equal, tlabel);
846       break;
847     case kUnorderedLessThanOrEqual:
848       __ j(parity_even, flabel, flabel_distance);
849     // Fall through.
850     case kUnsignedLessThanOrEqual:
851       __ j(below_equal, tlabel);
852       break;
853     case kUnorderedGreaterThan:
854       __ j(parity_even, tlabel);
855     // Fall through.
856     case kUnsignedGreaterThan:
857       __ j(above, tlabel);
858       break;
859     case kOverflow:
860       __ j(overflow, tlabel);
861       break;
862     case kNotOverflow:
863       __ j(no_overflow, tlabel);
864       break;
865   }
866   if (!branch->fallthru) __ jmp(flabel, flabel_distance);
867 }
868
869
870 void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
871   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
872 }
873
874
875 // Assembles boolean materializations after this instruction.
876 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
877                                         FlagsCondition condition) {
878   X64OperandConverter i(this, instr);
879   Label done;
880
881   // Materialize a full 64-bit 1 or 0 value. The result register is always the
882   // last output of the instruction.
883   Label check;
884   DCHECK_NE(0, static_cast<int>(instr->OutputCount()));
885   Register reg = i.OutputRegister(static_cast<int>(instr->OutputCount() - 1));
886   Condition cc = no_condition;
887   switch (condition) {
888     case kUnorderedEqual:
889       __ j(parity_odd, &check, Label::kNear);
890       __ movl(reg, Immediate(0));
891       __ jmp(&done, Label::kNear);
892     // Fall through.
893     case kEqual:
894       cc = equal;
895       break;
896     case kUnorderedNotEqual:
897       __ j(parity_odd, &check, Label::kNear);
898       __ movl(reg, Immediate(1));
899       __ jmp(&done, Label::kNear);
900     // Fall through.
901     case kNotEqual:
902       cc = not_equal;
903       break;
904     case kSignedLessThan:
905       cc = less;
906       break;
907     case kSignedGreaterThanOrEqual:
908       cc = greater_equal;
909       break;
910     case kSignedLessThanOrEqual:
911       cc = less_equal;
912       break;
913     case kSignedGreaterThan:
914       cc = greater;
915       break;
916     case kUnorderedLessThan:
917       __ j(parity_odd, &check, Label::kNear);
918       __ movl(reg, Immediate(0));
919       __ jmp(&done, Label::kNear);
920     // Fall through.
921     case kUnsignedLessThan:
922       cc = below;
923       break;
924     case kUnorderedGreaterThanOrEqual:
925       __ j(parity_odd, &check, Label::kNear);
926       __ movl(reg, Immediate(1));
927       __ jmp(&done, Label::kNear);
928     // Fall through.
929     case kUnsignedGreaterThanOrEqual:
930       cc = above_equal;
931       break;
932     case kUnorderedLessThanOrEqual:
933       __ j(parity_odd, &check, Label::kNear);
934       __ movl(reg, Immediate(0));
935       __ jmp(&done, Label::kNear);
936     // Fall through.
937     case kUnsignedLessThanOrEqual:
938       cc = below_equal;
939       break;
940     case kUnorderedGreaterThan:
941       __ j(parity_odd, &check, Label::kNear);
942       __ movl(reg, Immediate(1));
943       __ jmp(&done, Label::kNear);
944     // Fall through.
945     case kUnsignedGreaterThan:
946       cc = above;
947       break;
948     case kOverflow:
949       cc = overflow;
950       break;
951     case kNotOverflow:
952       cc = no_overflow;
953       break;
954   }
955   __ bind(&check);
956   __ setcc(cc, reg);
957   __ movzxbl(reg, reg);
958   __ bind(&done);
959 }
960
961
962 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
963   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
964       isolate(), deoptimization_id, Deoptimizer::LAZY);
965   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
966 }
967
968
969 void CodeGenerator::AssemblePrologue() {
970   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
971   int stack_slots = frame()->GetSpillSlotCount();
972   if (descriptor->kind() == CallDescriptor::kCallAddress) {
973     __ pushq(rbp);
974     __ movq(rbp, rsp);
975     const RegList saves = descriptor->CalleeSavedRegisters();
976     if (saves != 0) {  // Save callee-saved registers.
977       int register_save_area_size = 0;
978       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
979         if (!((1 << i) & saves)) continue;
980         __ pushq(Register::from_code(i));
981         register_save_area_size += kPointerSize;
982       }
983       frame()->SetRegisterSaveAreaSize(register_save_area_size);
984     }
985   } else if (descriptor->IsJSFunctionCall()) {
986     CompilationInfo* info = this->info();
987     __ Prologue(info->IsCodePreAgingActive());
988     frame()->SetRegisterSaveAreaSize(
989         StandardFrameConstants::kFixedFrameSizeFromFp);
990   } else {
991     __ StubPrologue();
992     frame()->SetRegisterSaveAreaSize(
993         StandardFrameConstants::kFixedFrameSizeFromFp);
994   }
995   if (stack_slots > 0) {
996     __ subq(rsp, Immediate(stack_slots * kPointerSize));
997   }
998 }
999
1000
1001 void CodeGenerator::AssembleReturn() {
1002   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1003   if (descriptor->kind() == CallDescriptor::kCallAddress) {
1004     if (frame()->GetRegisterSaveAreaSize() > 0) {
1005       // Remove this frame's spill slots first.
1006       int stack_slots = frame()->GetSpillSlotCount();
1007       if (stack_slots > 0) {
1008         __ addq(rsp, Immediate(stack_slots * kPointerSize));
1009       }
1010       const RegList saves = descriptor->CalleeSavedRegisters();
1011       // Restore registers.
1012       if (saves != 0) {
1013         for (int i = 0; i < Register::kNumRegisters; i++) {
1014           if (!((1 << i) & saves)) continue;
1015           __ popq(Register::from_code(i));
1016         }
1017       }
1018       __ popq(rbp);  // Pop caller's frame pointer.
1019       __ ret(0);
1020     } else {
1021       // No saved registers.
1022       __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
1023       __ popq(rbp);       // Pop caller's frame pointer.
1024       __ ret(0);
1025     }
1026   } else {
1027     __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
1028     __ popq(rbp);       // Pop caller's frame pointer.
1029     int pop_count = descriptor->IsJSFunctionCall()
1030                         ? static_cast<int>(descriptor->JSParameterCount())
1031                         : 0;
1032     __ ret(pop_count * kPointerSize);
1033   }
1034 }
1035
1036
1037 void CodeGenerator::AssembleMove(InstructionOperand* source,
1038                                  InstructionOperand* destination) {
1039   X64OperandConverter g(this, NULL);
1040   // Dispatch on the source and destination operand kinds.  Not all
1041   // combinations are possible.
1042   if (source->IsRegister()) {
1043     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1044     Register src = g.ToRegister(source);
1045     if (destination->IsRegister()) {
1046       __ movq(g.ToRegister(destination), src);
1047     } else {
1048       __ movq(g.ToOperand(destination), src);
1049     }
1050   } else if (source->IsStackSlot()) {
1051     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1052     Operand src = g.ToOperand(source);
1053     if (destination->IsRegister()) {
1054       Register dst = g.ToRegister(destination);
1055       __ movq(dst, src);
1056     } else {
1057       // Spill on demand to use a temporary register for memory-to-memory
1058       // moves.
1059       Register tmp = kScratchRegister;
1060       Operand dst = g.ToOperand(destination);
1061       __ movq(tmp, src);
1062       __ movq(dst, tmp);
1063     }
1064   } else if (source->IsConstant()) {
1065     ConstantOperand* constant_source = ConstantOperand::cast(source);
1066     Constant src = g.ToConstant(constant_source);
1067     if (destination->IsRegister() || destination->IsStackSlot()) {
1068       Register dst = destination->IsRegister() ? g.ToRegister(destination)
1069                                                : kScratchRegister;
1070       switch (src.type()) {
1071         case Constant::kInt32:
1072           // TODO(dcarney): don't need scratch in this case.
1073           __ Set(dst, src.ToInt32());
1074           break;
1075         case Constant::kInt64:
1076           __ Set(dst, src.ToInt64());
1077           break;
1078         case Constant::kFloat32:
1079           __ Move(dst,
1080                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1081           break;
1082         case Constant::kFloat64:
1083           __ Move(dst,
1084                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1085           break;
1086         case Constant::kExternalReference:
1087           __ Move(dst, src.ToExternalReference());
1088           break;
1089         case Constant::kHeapObject:
1090           __ Move(dst, src.ToHeapObject());
1091           break;
1092         case Constant::kRpoNumber:
1093           UNREACHABLE();  // TODO(dcarney): load of labels on x64.
1094           break;
1095       }
1096       if (destination->IsStackSlot()) {
1097         __ movq(g.ToOperand(destination), kScratchRegister);
1098       }
1099     } else if (src.type() == Constant::kFloat32) {
1100       // TODO(turbofan): Can we do better here?
1101       uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
1102       if (destination->IsDoubleRegister()) {
1103         __ Move(g.ToDoubleRegister(destination), src_const);
1104       } else {
1105         DCHECK(destination->IsDoubleStackSlot());
1106         Operand dst = g.ToOperand(destination);
1107         __ movl(dst, Immediate(src_const));
1108       }
1109     } else {
1110       DCHECK_EQ(Constant::kFloat64, src.type());
1111       uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
1112       if (destination->IsDoubleRegister()) {
1113         __ Move(g.ToDoubleRegister(destination), src_const);
1114       } else {
1115         DCHECK(destination->IsDoubleStackSlot());
1116         __ movq(kScratchRegister, src_const);
1117         __ movq(g.ToOperand(destination), kScratchRegister);
1118       }
1119     }
1120   } else if (source->IsDoubleRegister()) {
1121     XMMRegister src = g.ToDoubleRegister(source);
1122     if (destination->IsDoubleRegister()) {
1123       XMMRegister dst = g.ToDoubleRegister(destination);
1124       __ movsd(dst, src);
1125     } else {
1126       DCHECK(destination->IsDoubleStackSlot());
1127       Operand dst = g.ToOperand(destination);
1128       __ movsd(dst, src);
1129     }
1130   } else if (source->IsDoubleStackSlot()) {
1131     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1132     Operand src = g.ToOperand(source);
1133     if (destination->IsDoubleRegister()) {
1134       XMMRegister dst = g.ToDoubleRegister(destination);
1135       __ movsd(dst, src);
1136     } else {
1137       // We rely on having xmm0 available as a fixed scratch register.
1138       Operand dst = g.ToOperand(destination);
1139       __ movsd(xmm0, src);
1140       __ movsd(dst, xmm0);
1141     }
1142   } else {
1143     UNREACHABLE();
1144   }
1145 }
1146
1147
1148 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1149                                  InstructionOperand* destination) {
1150   X64OperandConverter g(this, NULL);
1151   // Dispatch on the source and destination operand kinds.  Not all
1152   // combinations are possible.
1153   if (source->IsRegister() && destination->IsRegister()) {
1154     // Register-register.
1155     __ xchgq(g.ToRegister(source), g.ToRegister(destination));
1156   } else if (source->IsRegister() && destination->IsStackSlot()) {
1157     Register src = g.ToRegister(source);
1158     Operand dst = g.ToOperand(destination);
1159     __ xchgq(src, dst);
1160   } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
1161              (source->IsDoubleStackSlot() &&
1162               destination->IsDoubleStackSlot())) {
1163     // Memory-memory.
1164     Register tmp = kScratchRegister;
1165     Operand src = g.ToOperand(source);
1166     Operand dst = g.ToOperand(destination);
1167     __ movq(tmp, dst);
1168     __ xchgq(tmp, src);
1169     __ movq(dst, tmp);
1170   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
1171     // XMM register-register swap. We rely on having xmm0
1172     // available as a fixed scratch register.
1173     XMMRegister src = g.ToDoubleRegister(source);
1174     XMMRegister dst = g.ToDoubleRegister(destination);
1175     __ movsd(xmm0, src);
1176     __ movsd(src, dst);
1177     __ movsd(dst, xmm0);
1178   } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
1179     // XMM register-memory swap.  We rely on having xmm0
1180     // available as a fixed scratch register.
1181     XMMRegister src = g.ToDoubleRegister(source);
1182     Operand dst = g.ToOperand(destination);
1183     __ movsd(xmm0, src);
1184     __ movsd(src, dst);
1185     __ movsd(dst, xmm0);
1186   } else {
1187     // No other combinations are possible.
1188     UNREACHABLE();
1189   }
1190 }
1191
1192
1193 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
1194
1195
1196 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1197   int space_needed = Deoptimizer::patch_size();
1198   if (!info()->IsStub()) {
1199     // Ensure that we have enough space after the previous lazy-bailout
1200     // instruction for patching the code here.
1201     int current_pc = masm()->pc_offset();
1202     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1203       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1204       __ Nop(padding_size);
1205     }
1206   }
1207   MarkLazyDeoptSite();
1208 }
1209
1210 #undef __
1211
1212 }  // namespace internal
1213 }  // namespace compiler
1214 }  // namespace v8