[turbofan] remove some of the dependency of Instruction on Schedule
[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     Constant constant = ToConstant(operand);
38     if (constant.type() == Constant::kInt32) {
39       return Immediate(constant.ToInt32());
40     }
41     UNREACHABLE();
42     return Immediate(-1);
43   }
44
45   Operand ToOperand(InstructionOperand* op, int extra = 0) {
46     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
47     // The linkage computes where all spill slots are located.
48     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
49     return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
50   }
51
52   static int NextOffset(int* offset) {
53     int i = *offset;
54     (*offset)++;
55     return i;
56   }
57
58   static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
59     STATIC_ASSERT(0 == static_cast<int>(times_1));
60     STATIC_ASSERT(1 == static_cast<int>(times_2));
61     STATIC_ASSERT(2 == static_cast<int>(times_4));
62     STATIC_ASSERT(3 == static_cast<int>(times_8));
63     int scale = static_cast<int>(mode - one);
64     DCHECK(scale >= 0 && scale < 4);
65     return static_cast<ScaleFactor>(scale);
66   }
67
68   Operand MemoryOperand(int* offset) {
69     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
70     switch (mode) {
71       case kMode_MR: {
72         Register base = InputRegister(NextOffset(offset));
73         int32_t disp = 0;
74         return Operand(base, disp);
75       }
76       case kMode_MRI: {
77         Register base = InputRegister(NextOffset(offset));
78         int32_t disp = InputInt32(NextOffset(offset));
79         return Operand(base, disp);
80       }
81       case kMode_MR1:
82       case kMode_MR2:
83       case kMode_MR4:
84       case kMode_MR8: {
85         Register base = InputRegister(NextOffset(offset));
86         Register index = InputRegister(NextOffset(offset));
87         ScaleFactor scale = ScaleFor(kMode_MR1, mode);
88         int32_t disp = 0;
89         return Operand(base, index, scale, disp);
90       }
91       case kMode_MR1I:
92       case kMode_MR2I:
93       case kMode_MR4I:
94       case kMode_MR8I: {
95         Register base = InputRegister(NextOffset(offset));
96         Register index = InputRegister(NextOffset(offset));
97         ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
98         int32_t disp = InputInt32(NextOffset(offset));
99         return Operand(base, index, scale, disp);
100       }
101       case kMode_M1:
102       case kMode_M2:
103       case kMode_M4:
104       case kMode_M8: {
105         Register index = InputRegister(NextOffset(offset));
106         ScaleFactor scale = ScaleFor(kMode_M1, mode);
107         int32_t disp = 0;
108         return Operand(index, scale, disp);
109       }
110       case kMode_M1I:
111       case kMode_M2I:
112       case kMode_M4I:
113       case kMode_M8I: {
114         Register index = InputRegister(NextOffset(offset));
115         ScaleFactor scale = ScaleFor(kMode_M1I, mode);
116         int32_t disp = InputInt32(NextOffset(offset));
117         return Operand(index, scale, disp);
118       }
119       case kMode_None:
120         UNREACHABLE();
121         return Operand(no_reg, 0);
122     }
123     UNREACHABLE();
124     return Operand(no_reg, 0);
125   }
126
127   Operand MemoryOperand() {
128     int first_input = 0;
129     return MemoryOperand(&first_input);
130   }
131 };
132
133
134 static bool HasImmediateInput(Instruction* instr, int index) {
135   return instr->InputAt(index)->IsImmediate();
136 }
137
138
139 #define ASSEMBLE_UNOP(asm_instr)         \
140   do {                                   \
141     if (instr->Output()->IsRegister()) { \
142       __ asm_instr(i.OutputRegister());  \
143     } else {                             \
144       __ asm_instr(i.OutputOperand());   \
145     }                                    \
146   } while (0)
147
148
149 #define ASSEMBLE_BINOP(asm_instr)                              \
150   do {                                                         \
151     if (HasImmediateInput(instr, 1)) {                         \
152       if (instr->InputAt(0)->IsRegister()) {                   \
153         __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
154       } else {                                                 \
155         __ asm_instr(i.InputOperand(0), i.InputImmediate(1));  \
156       }                                                        \
157     } else {                                                   \
158       if (instr->InputAt(1)->IsRegister()) {                   \
159         __ asm_instr(i.InputRegister(0), i.InputRegister(1));  \
160       } else {                                                 \
161         __ asm_instr(i.InputRegister(0), i.InputOperand(1));   \
162       }                                                        \
163     }                                                          \
164   } while (0)
165
166
167 #define ASSEMBLE_MULT(asm_instr)                              \
168   do {                                                        \
169     if (HasImmediateInput(instr, 1)) {                        \
170       if (instr->InputAt(0)->IsRegister()) {                  \
171         __ asm_instr(i.OutputRegister(), i.InputRegister(0),  \
172                      i.InputImmediate(1));                    \
173       } else {                                                \
174         __ asm_instr(i.OutputRegister(), i.InputOperand(0),   \
175                      i.InputImmediate(1));                    \
176       }                                                       \
177     } else {                                                  \
178       if (instr->InputAt(1)->IsRegister()) {                  \
179         __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
180       } else {                                                \
181         __ asm_instr(i.OutputRegister(), i.InputOperand(1));  \
182       }                                                       \
183     }                                                         \
184   } while (0)
185
186
187 #define ASSEMBLE_SHIFT(asm_instr, width)                                   \
188   do {                                                                     \
189     if (HasImmediateInput(instr, 1)) {                                     \
190       if (instr->Output()->IsRegister()) {                                 \
191         __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
192       } else {                                                             \
193         __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1)));  \
194       }                                                                    \
195     } else {                                                               \
196       if (instr->Output()->IsRegister()) {                                 \
197         __ asm_instr##_cl(i.OutputRegister());                             \
198       } else {                                                             \
199         __ asm_instr##_cl(i.OutputOperand());                              \
200       }                                                                    \
201     }                                                                      \
202   } while (0)
203
204
205 // Assembles an instruction after register allocation, producing machine code.
206 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
207   X64OperandConverter i(this, instr);
208
209   switch (ArchOpcodeField::decode(instr->opcode())) {
210     case kArchCallCodeObject: {
211       EnsureSpaceForLazyDeopt();
212       if (HasImmediateInput(instr, 0)) {
213         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
214         __ Call(code, RelocInfo::CODE_TARGET);
215       } else {
216         Register reg = i.InputRegister(0);
217         int entry = Code::kHeaderSize - kHeapObjectTag;
218         __ Call(Operand(reg, entry));
219       }
220       AddSafepointAndDeopt(instr);
221       break;
222     }
223     case kArchCallJSFunction: {
224       EnsureSpaceForLazyDeopt();
225       Register func = i.InputRegister(0);
226       if (FLAG_debug_code) {
227         // Check the function's context matches the context argument.
228         __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
229         __ Assert(equal, kWrongFunctionContext);
230       }
231       __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
232       AddSafepointAndDeopt(instr);
233       break;
234     }
235     case kArchJmp:
236       __ jmp(code_->GetLabel(i.InputRpo(0)));
237       break;
238     case kArchNop:
239       // don't emit code for nops.
240       break;
241     case kArchRet:
242       AssembleReturn();
243       break;
244     case kArchStackPointer:
245       __ movq(i.OutputRegister(), rsp);
246       break;
247     case kArchTruncateDoubleToI:
248       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
249       break;
250     case kX64Add32:
251       ASSEMBLE_BINOP(addl);
252       break;
253     case kX64Add:
254       ASSEMBLE_BINOP(addq);
255       break;
256     case kX64Sub32:
257       ASSEMBLE_BINOP(subl);
258       break;
259     case kX64Sub:
260       ASSEMBLE_BINOP(subq);
261       break;
262     case kX64And32:
263       ASSEMBLE_BINOP(andl);
264       break;
265     case kX64And:
266       ASSEMBLE_BINOP(andq);
267       break;
268     case kX64Cmp32:
269       ASSEMBLE_BINOP(cmpl);
270       break;
271     case kX64Cmp:
272       ASSEMBLE_BINOP(cmpq);
273       break;
274     case kX64Test32:
275       ASSEMBLE_BINOP(testl);
276       break;
277     case kX64Test:
278       ASSEMBLE_BINOP(testq);
279       break;
280     case kX64Imul32:
281       ASSEMBLE_MULT(imull);
282       break;
283     case kX64Imul:
284       ASSEMBLE_MULT(imulq);
285       break;
286     case kX64Idiv32:
287       __ cdq();
288       __ idivl(i.InputRegister(1));
289       break;
290     case kX64Idiv:
291       __ cqo();
292       __ idivq(i.InputRegister(1));
293       break;
294     case kX64Udiv32:
295       __ xorl(rdx, rdx);
296       __ divl(i.InputRegister(1));
297       break;
298     case kX64Udiv:
299       __ xorq(rdx, rdx);
300       __ divq(i.InputRegister(1));
301       break;
302     case kX64Not:
303       ASSEMBLE_UNOP(notq);
304       break;
305     case kX64Not32:
306       ASSEMBLE_UNOP(notl);
307       break;
308     case kX64Neg:
309       ASSEMBLE_UNOP(negq);
310       break;
311     case kX64Neg32:
312       ASSEMBLE_UNOP(negl);
313       break;
314     case kX64Or32:
315       ASSEMBLE_BINOP(orl);
316       break;
317     case kX64Or:
318       ASSEMBLE_BINOP(orq);
319       break;
320     case kX64Xor32:
321       ASSEMBLE_BINOP(xorl);
322       break;
323     case kX64Xor:
324       ASSEMBLE_BINOP(xorq);
325       break;
326     case kX64Shl32:
327       ASSEMBLE_SHIFT(shll, 5);
328       break;
329     case kX64Shl:
330       ASSEMBLE_SHIFT(shlq, 6);
331       break;
332     case kX64Shr32:
333       ASSEMBLE_SHIFT(shrl, 5);
334       break;
335     case kX64Shr:
336       ASSEMBLE_SHIFT(shrq, 6);
337       break;
338     case kX64Sar32:
339       ASSEMBLE_SHIFT(sarl, 5);
340       break;
341     case kX64Sar:
342       ASSEMBLE_SHIFT(sarq, 6);
343       break;
344     case kX64Ror32:
345       ASSEMBLE_SHIFT(rorl, 5);
346       break;
347     case kX64Ror:
348       ASSEMBLE_SHIFT(rorq, 6);
349       break;
350     case kSSEFloat64Cmp:
351       if (instr->InputAt(1)->IsDoubleRegister()) {
352         __ ucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
353       } else {
354         __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
355       }
356       break;
357     case kSSEFloat64Add:
358       __ addsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
359       break;
360     case kSSEFloat64Sub:
361       __ subsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
362       break;
363     case kSSEFloat64Mul:
364       __ mulsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
365       break;
366     case kSSEFloat64Div:
367       __ divsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
368       break;
369     case kSSEFloat64Mod: {
370       __ subq(rsp, Immediate(kDoubleSize));
371       // Move values to st(0) and st(1).
372       __ movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
373       __ fld_d(Operand(rsp, 0));
374       __ movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
375       __ fld_d(Operand(rsp, 0));
376       // Loop while fprem isn't done.
377       Label mod_loop;
378       __ bind(&mod_loop);
379       // This instructions traps on all kinds inputs, but we are assuming the
380       // floating point control word is set to ignore them all.
381       __ fprem();
382       // The following 2 instruction implicitly use rax.
383       __ fnstsw_ax();
384       if (CpuFeatures::IsSupported(SAHF) && masm()->IsEnabled(SAHF)) {
385         __ sahf();
386       } else {
387         __ shrl(rax, Immediate(8));
388         __ andl(rax, Immediate(0xFF));
389         __ pushq(rax);
390         __ popfq();
391       }
392       __ j(parity_even, &mod_loop);
393       // Move output to stack and clean up.
394       __ fstp(1);
395       __ fstp_d(Operand(rsp, 0));
396       __ movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
397       __ addq(rsp, Immediate(kDoubleSize));
398       break;
399     }
400     case kSSEFloat64Sqrt:
401       if (instr->InputAt(0)->IsDoubleRegister()) {
402         __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
403       } else {
404         __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
405       }
406       break;
407     case kSSECvtss2sd:
408       if (instr->InputAt(0)->IsDoubleRegister()) {
409         __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
410       } else {
411         __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
412       }
413       break;
414     case kSSECvtsd2ss:
415       if (instr->InputAt(0)->IsDoubleRegister()) {
416         __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
417       } else {
418         __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
419       }
420       break;
421     case kSSEFloat64ToInt32:
422       if (instr->InputAt(0)->IsDoubleRegister()) {
423         __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
424       } else {
425         __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
426       }
427       break;
428     case kSSEFloat64ToUint32:
429       if (instr->InputAt(0)->IsDoubleRegister()) {
430         __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
431       } else {
432         __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
433       }
434       __ andl(i.OutputRegister(), i.OutputRegister());  // clear upper bits.
435       // TODO(turbofan): generated code should not look at the upper 32 bits
436       // of the result, but those bits could escape to the outside world.
437       break;
438     case kSSEInt32ToFloat64:
439       if (instr->InputAt(0)->IsRegister()) {
440         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
441       } else {
442         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
443       }
444       break;
445     case kSSEUint32ToFloat64:
446       if (instr->InputAt(0)->IsRegister()) {
447         __ cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
448       } else {
449         __ cvtqsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
450       }
451       break;
452     case kX64Movsxbl:
453       __ movsxbl(i.OutputRegister(), i.MemoryOperand());
454       break;
455     case kX64Movzxbl:
456       __ movzxbl(i.OutputRegister(), i.MemoryOperand());
457       break;
458     case kX64Movb: {
459       int index = 0;
460       Operand operand = i.MemoryOperand(&index);
461       if (HasImmediateInput(instr, index)) {
462         __ movb(operand, Immediate(i.InputInt8(index)));
463       } else {
464         __ movb(operand, i.InputRegister(index));
465       }
466       break;
467     }
468     case kX64Movsxwl:
469       __ movsxwl(i.OutputRegister(), i.MemoryOperand());
470       break;
471     case kX64Movzxwl:
472       __ movzxwl(i.OutputRegister(), i.MemoryOperand());
473       break;
474     case kX64Movw: {
475       int index = 0;
476       Operand operand = i.MemoryOperand(&index);
477       if (HasImmediateInput(instr, index)) {
478         __ movw(operand, Immediate(i.InputInt16(index)));
479       } else {
480         __ movw(operand, i.InputRegister(index));
481       }
482       break;
483     }
484     case kX64Movl:
485       if (instr->HasOutput()) {
486         if (instr->addressing_mode() == kMode_None) {
487           if (instr->InputAt(0)->IsRegister()) {
488             __ movl(i.OutputRegister(), i.InputRegister(0));
489           } else {
490             __ movl(i.OutputRegister(), i.InputOperand(0));
491           }
492         } else {
493           __ movl(i.OutputRegister(), i.MemoryOperand());
494         }
495       } else {
496         int index = 0;
497         Operand operand = i.MemoryOperand(&index);
498         if (HasImmediateInput(instr, index)) {
499           __ movl(operand, i.InputImmediate(index));
500         } else {
501           __ movl(operand, i.InputRegister(index));
502         }
503       }
504       break;
505     case kX64Movsxlq: {
506       if (instr->InputAt(0)->IsRegister()) {
507         __ movsxlq(i.OutputRegister(), i.InputRegister(0));
508       } else {
509         __ movsxlq(i.OutputRegister(), i.InputOperand(0));
510       }
511       break;
512     }
513     case kX64Movq:
514       if (instr->HasOutput()) {
515         __ movq(i.OutputRegister(), i.MemoryOperand());
516       } else {
517         int index = 0;
518         Operand operand = i.MemoryOperand(&index);
519         if (HasImmediateInput(instr, index)) {
520           __ movq(operand, i.InputImmediate(index));
521         } else {
522           __ movq(operand, i.InputRegister(index));
523         }
524       }
525       break;
526     case kX64Movss:
527       if (instr->HasOutput()) {
528         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
529       } else {
530         int index = 0;
531         Operand operand = i.MemoryOperand(&index);
532         __ movss(operand, i.InputDoubleRegister(index));
533       }
534       break;
535     case kX64Movsd:
536       if (instr->HasOutput()) {
537         __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
538       } else {
539         int index = 0;
540         Operand operand = i.MemoryOperand(&index);
541         __ movsd(operand, i.InputDoubleRegister(index));
542       }
543       break;
544     case kX64Lea32:
545       __ leal(i.OutputRegister(), i.MemoryOperand());
546       break;
547     case kX64Lea:
548       __ leaq(i.OutputRegister(), i.MemoryOperand());
549       break;
550     case kX64Push:
551       if (HasImmediateInput(instr, 0)) {
552         __ pushq(i.InputImmediate(0));
553       } else {
554         if (instr->InputAt(0)->IsRegister()) {
555           __ pushq(i.InputRegister(0));
556         } else {
557           __ pushq(i.InputOperand(0));
558         }
559       }
560       break;
561     case kX64StoreWriteBarrier: {
562       Register object = i.InputRegister(0);
563       Register index = i.InputRegister(1);
564       Register value = i.InputRegister(2);
565       __ movsxlq(index, index);
566       __ movq(Operand(object, index, times_1, 0), value);
567       __ leaq(index, Operand(object, index, times_1, 0));
568       SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
569                                 ? kSaveFPRegs
570                                 : kDontSaveFPRegs;
571       __ RecordWrite(object, index, value, mode);
572       break;
573     }
574   }
575 }
576
577
578 // Assembles branches after this instruction.
579 void CodeGenerator::AssembleArchBranch(Instruction* instr,
580                                        FlagsCondition condition) {
581   X64OperandConverter i(this, instr);
582   Label done;
583
584   // Emit a branch. The true and false targets are always the last two inputs
585   // to the instruction.
586   BasicBlock::RpoNumber tblock =
587       i.InputRpo(static_cast<int>(instr->InputCount()) - 2);
588   BasicBlock::RpoNumber fblock =
589       i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
590   bool fallthru = IsNextInAssemblyOrder(fblock);
591   Label* tlabel = code()->GetLabel(tblock);
592   Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
593   Label::Distance flabel_distance = fallthru ? Label::kNear : Label::kFar;
594   switch (condition) {
595     case kUnorderedEqual:
596       __ j(parity_even, flabel, flabel_distance);
597     // Fall through.
598     case kEqual:
599       __ j(equal, tlabel);
600       break;
601     case kUnorderedNotEqual:
602       __ j(parity_even, tlabel);
603     // Fall through.
604     case kNotEqual:
605       __ j(not_equal, tlabel);
606       break;
607     case kSignedLessThan:
608       __ j(less, tlabel);
609       break;
610     case kSignedGreaterThanOrEqual:
611       __ j(greater_equal, tlabel);
612       break;
613     case kSignedLessThanOrEqual:
614       __ j(less_equal, tlabel);
615       break;
616     case kSignedGreaterThan:
617       __ j(greater, tlabel);
618       break;
619     case kUnorderedLessThan:
620       __ j(parity_even, flabel, flabel_distance);
621     // Fall through.
622     case kUnsignedLessThan:
623       __ j(below, tlabel);
624       break;
625     case kUnorderedGreaterThanOrEqual:
626       __ j(parity_even, tlabel);
627     // Fall through.
628     case kUnsignedGreaterThanOrEqual:
629       __ j(above_equal, tlabel);
630       break;
631     case kUnorderedLessThanOrEqual:
632       __ j(parity_even, flabel, flabel_distance);
633     // Fall through.
634     case kUnsignedLessThanOrEqual:
635       __ j(below_equal, tlabel);
636       break;
637     case kUnorderedGreaterThan:
638       __ j(parity_even, tlabel);
639     // Fall through.
640     case kUnsignedGreaterThan:
641       __ j(above, tlabel);
642       break;
643     case kOverflow:
644       __ j(overflow, tlabel);
645       break;
646     case kNotOverflow:
647       __ j(no_overflow, tlabel);
648       break;
649   }
650   if (!fallthru) __ jmp(flabel, flabel_distance);  // no fallthru to flabel.
651   __ bind(&done);
652 }
653
654
655 // Assembles boolean materializations after this instruction.
656 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
657                                         FlagsCondition condition) {
658   X64OperandConverter i(this, instr);
659   Label done;
660
661   // Materialize a full 64-bit 1 or 0 value. The result register is always the
662   // last output of the instruction.
663   Label check;
664   DCHECK_NE(0, static_cast<int>(instr->OutputCount()));
665   Register reg = i.OutputRegister(static_cast<int>(instr->OutputCount() - 1));
666   Condition cc = no_condition;
667   switch (condition) {
668     case kUnorderedEqual:
669       __ j(parity_odd, &check, Label::kNear);
670       __ movl(reg, Immediate(0));
671       __ jmp(&done, Label::kNear);
672     // Fall through.
673     case kEqual:
674       cc = equal;
675       break;
676     case kUnorderedNotEqual:
677       __ j(parity_odd, &check, Label::kNear);
678       __ movl(reg, Immediate(1));
679       __ jmp(&done, Label::kNear);
680     // Fall through.
681     case kNotEqual:
682       cc = not_equal;
683       break;
684     case kSignedLessThan:
685       cc = less;
686       break;
687     case kSignedGreaterThanOrEqual:
688       cc = greater_equal;
689       break;
690     case kSignedLessThanOrEqual:
691       cc = less_equal;
692       break;
693     case kSignedGreaterThan:
694       cc = greater;
695       break;
696     case kUnorderedLessThan:
697       __ j(parity_odd, &check, Label::kNear);
698       __ movl(reg, Immediate(0));
699       __ jmp(&done, Label::kNear);
700     // Fall through.
701     case kUnsignedLessThan:
702       cc = below;
703       break;
704     case kUnorderedGreaterThanOrEqual:
705       __ j(parity_odd, &check, Label::kNear);
706       __ movl(reg, Immediate(1));
707       __ jmp(&done, Label::kNear);
708     // Fall through.
709     case kUnsignedGreaterThanOrEqual:
710       cc = above_equal;
711       break;
712     case kUnorderedLessThanOrEqual:
713       __ j(parity_odd, &check, Label::kNear);
714       __ movl(reg, Immediate(0));
715       __ jmp(&done, Label::kNear);
716     // Fall through.
717     case kUnsignedLessThanOrEqual:
718       cc = below_equal;
719       break;
720     case kUnorderedGreaterThan:
721       __ j(parity_odd, &check, Label::kNear);
722       __ movl(reg, Immediate(1));
723       __ jmp(&done, Label::kNear);
724     // Fall through.
725     case kUnsignedGreaterThan:
726       cc = above;
727       break;
728     case kOverflow:
729       cc = overflow;
730       break;
731     case kNotOverflow:
732       cc = no_overflow;
733       break;
734   }
735   __ bind(&check);
736   __ setcc(cc, reg);
737   __ movzxbl(reg, reg);
738   __ bind(&done);
739 }
740
741
742 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
743   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
744       isolate(), deoptimization_id, Deoptimizer::LAZY);
745   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
746 }
747
748
749 void CodeGenerator::AssemblePrologue() {
750   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
751   int stack_slots = frame()->GetSpillSlotCount();
752   if (descriptor->kind() == CallDescriptor::kCallAddress) {
753     __ pushq(rbp);
754     __ movq(rbp, rsp);
755     const RegList saves = descriptor->CalleeSavedRegisters();
756     if (saves != 0) {  // Save callee-saved registers.
757       int register_save_area_size = 0;
758       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
759         if (!((1 << i) & saves)) continue;
760         __ pushq(Register::from_code(i));
761         register_save_area_size += kPointerSize;
762       }
763       frame()->SetRegisterSaveAreaSize(register_save_area_size);
764     }
765   } else if (descriptor->IsJSFunctionCall()) {
766     CompilationInfo* info = linkage()->info();
767     __ Prologue(info->IsCodePreAgingActive());
768     frame()->SetRegisterSaveAreaSize(
769         StandardFrameConstants::kFixedFrameSizeFromFp);
770
771     // Sloppy mode functions and builtins need to replace the receiver with the
772     // global proxy when called as functions (without an explicit receiver
773     // object).
774     // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
775     if (info->strict_mode() == SLOPPY && !info->is_native()) {
776       Label ok;
777       StackArgumentsAccessor args(rbp, info->scope()->num_parameters());
778       __ movp(rcx, args.GetReceiverOperand());
779       __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
780       __ j(not_equal, &ok, Label::kNear);
781       __ movp(rcx, GlobalObjectOperand());
782       __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
783       __ movp(args.GetReceiverOperand(), rcx);
784       __ bind(&ok);
785     }
786
787   } else {
788     __ StubPrologue();
789     frame()->SetRegisterSaveAreaSize(
790         StandardFrameConstants::kFixedFrameSizeFromFp);
791   }
792   if (stack_slots > 0) {
793     __ subq(rsp, Immediate(stack_slots * kPointerSize));
794   }
795 }
796
797
798 void CodeGenerator::AssembleReturn() {
799   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
800   if (descriptor->kind() == CallDescriptor::kCallAddress) {
801     if (frame()->GetRegisterSaveAreaSize() > 0) {
802       // Remove this frame's spill slots first.
803       int stack_slots = frame()->GetSpillSlotCount();
804       if (stack_slots > 0) {
805         __ addq(rsp, Immediate(stack_slots * kPointerSize));
806       }
807       const RegList saves = descriptor->CalleeSavedRegisters();
808       // Restore registers.
809       if (saves != 0) {
810         for (int i = 0; i < Register::kNumRegisters; i++) {
811           if (!((1 << i) & saves)) continue;
812           __ popq(Register::from_code(i));
813         }
814       }
815       __ popq(rbp);  // Pop caller's frame pointer.
816       __ ret(0);
817     } else {
818       // No saved registers.
819       __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
820       __ popq(rbp);       // Pop caller's frame pointer.
821       __ ret(0);
822     }
823   } else {
824     __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
825     __ popq(rbp);       // Pop caller's frame pointer.
826     int pop_count = descriptor->IsJSFunctionCall()
827                         ? static_cast<int>(descriptor->JSParameterCount())
828                         : 0;
829     __ ret(pop_count * kPointerSize);
830   }
831 }
832
833
834 void CodeGenerator::AssembleMove(InstructionOperand* source,
835                                  InstructionOperand* destination) {
836   X64OperandConverter g(this, NULL);
837   // Dispatch on the source and destination operand kinds.  Not all
838   // combinations are possible.
839   if (source->IsRegister()) {
840     DCHECK(destination->IsRegister() || destination->IsStackSlot());
841     Register src = g.ToRegister(source);
842     if (destination->IsRegister()) {
843       __ movq(g.ToRegister(destination), src);
844     } else {
845       __ movq(g.ToOperand(destination), src);
846     }
847   } else if (source->IsStackSlot()) {
848     DCHECK(destination->IsRegister() || destination->IsStackSlot());
849     Operand src = g.ToOperand(source);
850     if (destination->IsRegister()) {
851       Register dst = g.ToRegister(destination);
852       __ movq(dst, src);
853     } else {
854       // Spill on demand to use a temporary register for memory-to-memory
855       // moves.
856       Register tmp = kScratchRegister;
857       Operand dst = g.ToOperand(destination);
858       __ movq(tmp, src);
859       __ movq(dst, tmp);
860     }
861   } else if (source->IsConstant()) {
862     ConstantOperand* constant_source = ConstantOperand::cast(source);
863     Constant src = g.ToConstant(constant_source);
864     if (destination->IsRegister() || destination->IsStackSlot()) {
865       Register dst = destination->IsRegister() ? g.ToRegister(destination)
866                                                : kScratchRegister;
867       switch (src.type()) {
868         case Constant::kInt32:
869           // TODO(dcarney): don't need scratch in this case.
870           __ movq(dst, Immediate(src.ToInt32()));
871           break;
872         case Constant::kInt64:
873           __ Set(dst, src.ToInt64());
874           break;
875         case Constant::kFloat32:
876           __ Move(dst,
877                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
878           break;
879         case Constant::kFloat64:
880           __ Move(dst,
881                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
882           break;
883         case Constant::kExternalReference:
884           __ Move(dst, src.ToExternalReference());
885           break;
886         case Constant::kHeapObject:
887           __ Move(dst, src.ToHeapObject());
888           break;
889       }
890       if (destination->IsStackSlot()) {
891         __ movq(g.ToOperand(destination), kScratchRegister);
892       }
893     } else if (src.type() == Constant::kFloat32) {
894       // TODO(turbofan): Can we do better here?
895       __ movl(kScratchRegister, Immediate(bit_cast<int32_t>(src.ToFloat32())));
896       if (destination->IsDoubleRegister()) {
897         XMMRegister dst = g.ToDoubleRegister(destination);
898         __ movq(dst, kScratchRegister);
899       } else {
900         DCHECK(destination->IsDoubleStackSlot());
901         Operand dst = g.ToOperand(destination);
902         __ movl(dst, kScratchRegister);
903       }
904     } else {
905       DCHECK_EQ(Constant::kFloat64, src.type());
906       __ movq(kScratchRegister, bit_cast<int64_t>(src.ToFloat64()));
907       if (destination->IsDoubleRegister()) {
908         __ movq(g.ToDoubleRegister(destination), kScratchRegister);
909       } else {
910         DCHECK(destination->IsDoubleStackSlot());
911         __ movq(g.ToOperand(destination), kScratchRegister);
912       }
913     }
914   } else if (source->IsDoubleRegister()) {
915     XMMRegister src = g.ToDoubleRegister(source);
916     if (destination->IsDoubleRegister()) {
917       XMMRegister dst = g.ToDoubleRegister(destination);
918       __ movsd(dst, src);
919     } else {
920       DCHECK(destination->IsDoubleStackSlot());
921       Operand dst = g.ToOperand(destination);
922       __ movsd(dst, src);
923     }
924   } else if (source->IsDoubleStackSlot()) {
925     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
926     Operand src = g.ToOperand(source);
927     if (destination->IsDoubleRegister()) {
928       XMMRegister dst = g.ToDoubleRegister(destination);
929       __ movsd(dst, src);
930     } else {
931       // We rely on having xmm0 available as a fixed scratch register.
932       Operand dst = g.ToOperand(destination);
933       __ movsd(xmm0, src);
934       __ movsd(dst, xmm0);
935     }
936   } else {
937     UNREACHABLE();
938   }
939 }
940
941
942 void CodeGenerator::AssembleSwap(InstructionOperand* source,
943                                  InstructionOperand* destination) {
944   X64OperandConverter g(this, NULL);
945   // Dispatch on the source and destination operand kinds.  Not all
946   // combinations are possible.
947   if (source->IsRegister() && destination->IsRegister()) {
948     // Register-register.
949     __ xchgq(g.ToRegister(source), g.ToRegister(destination));
950   } else if (source->IsRegister() && destination->IsStackSlot()) {
951     Register src = g.ToRegister(source);
952     Operand dst = g.ToOperand(destination);
953     __ xchgq(src, dst);
954   } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
955              (source->IsDoubleStackSlot() &&
956               destination->IsDoubleStackSlot())) {
957     // Memory-memory.
958     Register tmp = kScratchRegister;
959     Operand src = g.ToOperand(source);
960     Operand dst = g.ToOperand(destination);
961     __ movq(tmp, dst);
962     __ xchgq(tmp, src);
963     __ movq(dst, tmp);
964   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
965     // XMM register-register swap. We rely on having xmm0
966     // available as a fixed scratch register.
967     XMMRegister src = g.ToDoubleRegister(source);
968     XMMRegister dst = g.ToDoubleRegister(destination);
969     __ movsd(xmm0, src);
970     __ movsd(src, dst);
971     __ movsd(dst, xmm0);
972   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
973     // XMM register-memory swap.  We rely on having xmm0
974     // available as a fixed scratch register.
975     XMMRegister src = g.ToDoubleRegister(source);
976     Operand dst = g.ToOperand(destination);
977     __ movsd(xmm0, src);
978     __ movsd(src, dst);
979     __ movsd(dst, xmm0);
980   } else {
981     // No other combinations are possible.
982     UNREACHABLE();
983   }
984 }
985
986
987 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
988
989
990 void CodeGenerator::EnsureSpaceForLazyDeopt() {
991   int space_needed = Deoptimizer::patch_size();
992   if (!linkage()->info()->IsStub()) {
993     // Ensure that we have enough space after the previous lazy-bailout
994     // instruction for patching the code here.
995     int current_pc = masm()->pc_offset();
996     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
997       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
998       __ Nop(padding_size);
999     }
1000   }
1001   MarkLazyDeoptSite();
1002 }
1003
1004 #undef __
1005
1006 }  // namespace internal
1007 }  // namespace compiler
1008 }  // namespace v8