Make V8 compile with Win64 dbg
[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.InputBlock(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       __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
409       break;
410     case kSSECvtsd2ss:
411       __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
412       break;
413     case kSSEFloat64ToInt32:
414       if (instr->InputAt(0)->IsDoubleRegister()) {
415         __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
416       } else {
417         __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
418       }
419       break;
420     case kSSEFloat64ToUint32:
421       if (instr->InputAt(0)->IsDoubleRegister()) {
422         __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
423       } else {
424         __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
425       }
426       __ andl(i.OutputRegister(), i.OutputRegister());  // clear upper bits.
427       // TODO(turbofan): generated code should not look at the upper 32 bits
428       // of the result, but those bits could escape to the outside world.
429       break;
430     case kSSEInt32ToFloat64:
431       if (instr->InputAt(0)->IsRegister()) {
432         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
433       } else {
434         __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
435       }
436       break;
437     case kSSEUint32ToFloat64:
438       if (instr->InputAt(0)->IsRegister()) {
439         __ cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
440       } else {
441         __ cvtqsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
442       }
443       break;
444     case kX64Movsxbl:
445       __ movsxbl(i.OutputRegister(), i.MemoryOperand());
446       break;
447     case kX64Movzxbl:
448       __ movzxbl(i.OutputRegister(), i.MemoryOperand());
449       break;
450     case kX64Movb: {
451       int index = 0;
452       Operand operand = i.MemoryOperand(&index);
453       if (HasImmediateInput(instr, index)) {
454         __ movb(operand, Immediate(i.InputInt8(index)));
455       } else {
456         __ movb(operand, i.InputRegister(index));
457       }
458       break;
459     }
460     case kX64Movsxwl:
461       __ movsxwl(i.OutputRegister(), i.MemoryOperand());
462       break;
463     case kX64Movzxwl:
464       __ movzxwl(i.OutputRegister(), i.MemoryOperand());
465       break;
466     case kX64Movw: {
467       int index = 0;
468       Operand operand = i.MemoryOperand(&index);
469       if (HasImmediateInput(instr, index)) {
470         __ movw(operand, Immediate(i.InputInt16(index)));
471       } else {
472         __ movw(operand, i.InputRegister(index));
473       }
474       break;
475     }
476     case kX64Movl:
477       if (instr->HasOutput()) {
478         if (instr->addressing_mode() == kMode_None) {
479           if (instr->InputAt(0)->IsRegister()) {
480             __ movl(i.OutputRegister(), i.InputRegister(0));
481           } else {
482             __ movl(i.OutputRegister(), i.InputOperand(0));
483           }
484         } else {
485           __ movl(i.OutputRegister(), i.MemoryOperand());
486         }
487       } else {
488         int index = 0;
489         Operand operand = i.MemoryOperand(&index);
490         if (HasImmediateInput(instr, index)) {
491           __ movl(operand, i.InputImmediate(index));
492         } else {
493           __ movl(operand, i.InputRegister(index));
494         }
495       }
496       break;
497     case kX64Movsxlq: {
498       if (instr->InputAt(0)->IsRegister()) {
499         __ movsxlq(i.OutputRegister(), i.InputRegister(0));
500       } else {
501         __ movsxlq(i.OutputRegister(), i.InputOperand(0));
502       }
503       break;
504     }
505     case kX64Movq:
506       if (instr->HasOutput()) {
507         __ movq(i.OutputRegister(), i.MemoryOperand());
508       } else {
509         int index = 0;
510         Operand operand = i.MemoryOperand(&index);
511         if (HasImmediateInput(instr, index)) {
512           __ movq(operand, i.InputImmediate(index));
513         } else {
514           __ movq(operand, i.InputRegister(index));
515         }
516       }
517       break;
518     case kX64Movss:
519       if (instr->HasOutput()) {
520         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
521       } else {
522         int index = 0;
523         Operand operand = i.MemoryOperand(&index);
524         __ movss(operand, i.InputDoubleRegister(index));
525       }
526       break;
527     case kX64Movsd:
528       if (instr->HasOutput()) {
529         __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
530       } else {
531         int index = 0;
532         Operand operand = i.MemoryOperand(&index);
533         __ movsd(operand, i.InputDoubleRegister(index));
534       }
535       break;
536     case kX64Lea32:
537       __ leal(i.OutputRegister(), i.MemoryOperand());
538       break;
539     case kX64Lea:
540       __ leaq(i.OutputRegister(), i.MemoryOperand());
541       break;
542     case kX64Push:
543       if (HasImmediateInput(instr, 0)) {
544         __ pushq(i.InputImmediate(0));
545       } else {
546         if (instr->InputAt(0)->IsRegister()) {
547           __ pushq(i.InputRegister(0));
548         } else {
549           __ pushq(i.InputOperand(0));
550         }
551       }
552       break;
553     case kX64StoreWriteBarrier: {
554       Register object = i.InputRegister(0);
555       Register index = i.InputRegister(1);
556       Register value = i.InputRegister(2);
557       __ movsxlq(index, index);
558       __ movq(Operand(object, index, times_1, 0), value);
559       __ leaq(index, Operand(object, index, times_1, 0));
560       SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
561                                 ? kSaveFPRegs
562                                 : kDontSaveFPRegs;
563       __ RecordWrite(object, index, value, mode);
564       break;
565     }
566   }
567 }
568
569
570 // Assembles branches after this instruction.
571 void CodeGenerator::AssembleArchBranch(Instruction* instr,
572                                        FlagsCondition condition) {
573   X64OperandConverter i(this, instr);
574   Label done;
575
576   // Emit a branch. The true and false targets are always the last two inputs
577   // to the instruction.
578   BasicBlock* tblock = i.InputBlock(static_cast<int>(instr->InputCount()) - 2);
579   BasicBlock* fblock = i.InputBlock(static_cast<int>(instr->InputCount()) - 1);
580   bool fallthru = IsNextInAssemblyOrder(fblock);
581   Label* tlabel = code()->GetLabel(tblock);
582   Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
583   Label::Distance flabel_distance = fallthru ? Label::kNear : Label::kFar;
584   switch (condition) {
585     case kUnorderedEqual:
586       __ j(parity_even, flabel, flabel_distance);
587     // Fall through.
588     case kEqual:
589       __ j(equal, tlabel);
590       break;
591     case kUnorderedNotEqual:
592       __ j(parity_even, tlabel);
593     // Fall through.
594     case kNotEqual:
595       __ j(not_equal, tlabel);
596       break;
597     case kSignedLessThan:
598       __ j(less, tlabel);
599       break;
600     case kSignedGreaterThanOrEqual:
601       __ j(greater_equal, tlabel);
602       break;
603     case kSignedLessThanOrEqual:
604       __ j(less_equal, tlabel);
605       break;
606     case kSignedGreaterThan:
607       __ j(greater, tlabel);
608       break;
609     case kUnorderedLessThan:
610       __ j(parity_even, flabel, flabel_distance);
611     // Fall through.
612     case kUnsignedLessThan:
613       __ j(below, tlabel);
614       break;
615     case kUnorderedGreaterThanOrEqual:
616       __ j(parity_even, tlabel);
617     // Fall through.
618     case kUnsignedGreaterThanOrEqual:
619       __ j(above_equal, tlabel);
620       break;
621     case kUnorderedLessThanOrEqual:
622       __ j(parity_even, flabel, flabel_distance);
623     // Fall through.
624     case kUnsignedLessThanOrEqual:
625       __ j(below_equal, tlabel);
626       break;
627     case kUnorderedGreaterThan:
628       __ j(parity_even, tlabel);
629     // Fall through.
630     case kUnsignedGreaterThan:
631       __ j(above, tlabel);
632       break;
633     case kOverflow:
634       __ j(overflow, tlabel);
635       break;
636     case kNotOverflow:
637       __ j(no_overflow, tlabel);
638       break;
639   }
640   if (!fallthru) __ jmp(flabel, flabel_distance);  // no fallthru to flabel.
641   __ bind(&done);
642 }
643
644
645 // Assembles boolean materializations after this instruction.
646 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
647                                         FlagsCondition condition) {
648   X64OperandConverter i(this, instr);
649   Label done;
650
651   // Materialize a full 64-bit 1 or 0 value. The result register is always the
652   // last output of the instruction.
653   Label check;
654   DCHECK_NE(0, static_cast<int>(instr->OutputCount()));
655   Register reg = i.OutputRegister(static_cast<int>(instr->OutputCount() - 1));
656   Condition cc = no_condition;
657   switch (condition) {
658     case kUnorderedEqual:
659       __ j(parity_odd, &check, Label::kNear);
660       __ movl(reg, Immediate(0));
661       __ jmp(&done, Label::kNear);
662     // Fall through.
663     case kEqual:
664       cc = equal;
665       break;
666     case kUnorderedNotEqual:
667       __ j(parity_odd, &check, Label::kNear);
668       __ movl(reg, Immediate(1));
669       __ jmp(&done, Label::kNear);
670     // Fall through.
671     case kNotEqual:
672       cc = not_equal;
673       break;
674     case kSignedLessThan:
675       cc = less;
676       break;
677     case kSignedGreaterThanOrEqual:
678       cc = greater_equal;
679       break;
680     case kSignedLessThanOrEqual:
681       cc = less_equal;
682       break;
683     case kSignedGreaterThan:
684       cc = greater;
685       break;
686     case kUnorderedLessThan:
687       __ j(parity_odd, &check, Label::kNear);
688       __ movl(reg, Immediate(0));
689       __ jmp(&done, Label::kNear);
690     // Fall through.
691     case kUnsignedLessThan:
692       cc = below;
693       break;
694     case kUnorderedGreaterThanOrEqual:
695       __ j(parity_odd, &check, Label::kNear);
696       __ movl(reg, Immediate(1));
697       __ jmp(&done, Label::kNear);
698     // Fall through.
699     case kUnsignedGreaterThanOrEqual:
700       cc = above_equal;
701       break;
702     case kUnorderedLessThanOrEqual:
703       __ j(parity_odd, &check, Label::kNear);
704       __ movl(reg, Immediate(0));
705       __ jmp(&done, Label::kNear);
706     // Fall through.
707     case kUnsignedLessThanOrEqual:
708       cc = below_equal;
709       break;
710     case kUnorderedGreaterThan:
711       __ j(parity_odd, &check, Label::kNear);
712       __ movl(reg, Immediate(1));
713       __ jmp(&done, Label::kNear);
714     // Fall through.
715     case kUnsignedGreaterThan:
716       cc = above;
717       break;
718     case kOverflow:
719       cc = overflow;
720       break;
721     case kNotOverflow:
722       cc = no_overflow;
723       break;
724   }
725   __ bind(&check);
726   __ setcc(cc, reg);
727   __ movzxbl(reg, reg);
728   __ bind(&done);
729 }
730
731
732 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
733   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
734       isolate(), deoptimization_id, Deoptimizer::LAZY);
735   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
736 }
737
738
739 void CodeGenerator::AssemblePrologue() {
740   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
741   int stack_slots = frame()->GetSpillSlotCount();
742   if (descriptor->kind() == CallDescriptor::kCallAddress) {
743     __ pushq(rbp);
744     __ movq(rbp, rsp);
745     const RegList saves = descriptor->CalleeSavedRegisters();
746     if (saves != 0) {  // Save callee-saved registers.
747       int register_save_area_size = 0;
748       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
749         if (!((1 << i) & saves)) continue;
750         __ pushq(Register::from_code(i));
751         register_save_area_size += kPointerSize;
752       }
753       frame()->SetRegisterSaveAreaSize(register_save_area_size);
754     }
755   } else if (descriptor->IsJSFunctionCall()) {
756     CompilationInfo* info = linkage()->info();
757     __ Prologue(info->IsCodePreAgingActive());
758     frame()->SetRegisterSaveAreaSize(
759         StandardFrameConstants::kFixedFrameSizeFromFp);
760
761     // Sloppy mode functions and builtins need to replace the receiver with the
762     // global proxy when called as functions (without an explicit receiver
763     // object).
764     // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
765     if (info->strict_mode() == SLOPPY && !info->is_native()) {
766       Label ok;
767       StackArgumentsAccessor args(rbp, info->scope()->num_parameters());
768       __ movp(rcx, args.GetReceiverOperand());
769       __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
770       __ j(not_equal, &ok, Label::kNear);
771       __ movp(rcx, GlobalObjectOperand());
772       __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
773       __ movp(args.GetReceiverOperand(), rcx);
774       __ bind(&ok);
775     }
776
777   } else {
778     __ StubPrologue();
779     frame()->SetRegisterSaveAreaSize(
780         StandardFrameConstants::kFixedFrameSizeFromFp);
781   }
782   if (stack_slots > 0) {
783     __ subq(rsp, Immediate(stack_slots * kPointerSize));
784   }
785 }
786
787
788 void CodeGenerator::AssembleReturn() {
789   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
790   if (descriptor->kind() == CallDescriptor::kCallAddress) {
791     if (frame()->GetRegisterSaveAreaSize() > 0) {
792       // Remove this frame's spill slots first.
793       int stack_slots = frame()->GetSpillSlotCount();
794       if (stack_slots > 0) {
795         __ addq(rsp, Immediate(stack_slots * kPointerSize));
796       }
797       const RegList saves = descriptor->CalleeSavedRegisters();
798       // Restore registers.
799       if (saves != 0) {
800         for (int i = 0; i < Register::kNumRegisters; i++) {
801           if (!((1 << i) & saves)) continue;
802           __ popq(Register::from_code(i));
803         }
804       }
805       __ popq(rbp);  // Pop caller's frame pointer.
806       __ ret(0);
807     } else {
808       // No saved registers.
809       __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
810       __ popq(rbp);       // Pop caller's frame pointer.
811       __ ret(0);
812     }
813   } else {
814     __ movq(rsp, rbp);  // Move stack pointer back to frame pointer.
815     __ popq(rbp);       // Pop caller's frame pointer.
816     int pop_count = descriptor->IsJSFunctionCall()
817                         ? static_cast<int>(descriptor->JSParameterCount())
818                         : 0;
819     __ ret(pop_count * kPointerSize);
820   }
821 }
822
823
824 void CodeGenerator::AssembleMove(InstructionOperand* source,
825                                  InstructionOperand* destination) {
826   X64OperandConverter g(this, NULL);
827   // Dispatch on the source and destination operand kinds.  Not all
828   // combinations are possible.
829   if (source->IsRegister()) {
830     DCHECK(destination->IsRegister() || destination->IsStackSlot());
831     Register src = g.ToRegister(source);
832     if (destination->IsRegister()) {
833       __ movq(g.ToRegister(destination), src);
834     } else {
835       __ movq(g.ToOperand(destination), src);
836     }
837   } else if (source->IsStackSlot()) {
838     DCHECK(destination->IsRegister() || destination->IsStackSlot());
839     Operand src = g.ToOperand(source);
840     if (destination->IsRegister()) {
841       Register dst = g.ToRegister(destination);
842       __ movq(dst, src);
843     } else {
844       // Spill on demand to use a temporary register for memory-to-memory
845       // moves.
846       Register tmp = kScratchRegister;
847       Operand dst = g.ToOperand(destination);
848       __ movq(tmp, src);
849       __ movq(dst, tmp);
850     }
851   } else if (source->IsConstant()) {
852     ConstantOperand* constant_source = ConstantOperand::cast(source);
853     Constant src = g.ToConstant(constant_source);
854     if (destination->IsRegister() || destination->IsStackSlot()) {
855       Register dst = destination->IsRegister() ? g.ToRegister(destination)
856                                                : kScratchRegister;
857       switch (src.type()) {
858         case Constant::kInt32:
859           // TODO(dcarney): don't need scratch in this case.
860           __ movq(dst, Immediate(src.ToInt32()));
861           break;
862         case Constant::kInt64:
863           __ Set(dst, src.ToInt64());
864           break;
865         case Constant::kFloat32:
866           __ Move(dst,
867                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
868           break;
869         case Constant::kFloat64:
870           __ Move(dst,
871                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
872           break;
873         case Constant::kExternalReference:
874           __ Move(dst, src.ToExternalReference());
875           break;
876         case Constant::kHeapObject:
877           __ Move(dst, src.ToHeapObject());
878           break;
879       }
880       if (destination->IsStackSlot()) {
881         __ movq(g.ToOperand(destination), kScratchRegister);
882       }
883     } else if (src.type() == Constant::kFloat32) {
884       // TODO(turbofan): Can we do better here?
885       __ movl(kScratchRegister, Immediate(bit_cast<int32_t>(src.ToFloat32())));
886       if (destination->IsDoubleRegister()) {
887         XMMRegister dst = g.ToDoubleRegister(destination);
888         __ movq(dst, kScratchRegister);
889       } else {
890         DCHECK(destination->IsDoubleStackSlot());
891         Operand dst = g.ToOperand(destination);
892         __ movl(dst, kScratchRegister);
893       }
894     } else {
895       DCHECK_EQ(Constant::kFloat64, src.type());
896       __ movq(kScratchRegister, bit_cast<int64_t>(src.ToFloat64()));
897       if (destination->IsDoubleRegister()) {
898         __ movq(g.ToDoubleRegister(destination), kScratchRegister);
899       } else {
900         DCHECK(destination->IsDoubleStackSlot());
901         __ movq(g.ToOperand(destination), kScratchRegister);
902       }
903     }
904   } else if (source->IsDoubleRegister()) {
905     XMMRegister src = g.ToDoubleRegister(source);
906     if (destination->IsDoubleRegister()) {
907       XMMRegister dst = g.ToDoubleRegister(destination);
908       __ movsd(dst, src);
909     } else {
910       DCHECK(destination->IsDoubleStackSlot());
911       Operand dst = g.ToOperand(destination);
912       __ movsd(dst, src);
913     }
914   } else if (source->IsDoubleStackSlot()) {
915     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
916     Operand src = g.ToOperand(source);
917     if (destination->IsDoubleRegister()) {
918       XMMRegister dst = g.ToDoubleRegister(destination);
919       __ movsd(dst, src);
920     } else {
921       // We rely on having xmm0 available as a fixed scratch register.
922       Operand dst = g.ToOperand(destination);
923       __ movsd(xmm0, src);
924       __ movsd(dst, xmm0);
925     }
926   } else {
927     UNREACHABLE();
928   }
929 }
930
931
932 void CodeGenerator::AssembleSwap(InstructionOperand* source,
933                                  InstructionOperand* destination) {
934   X64OperandConverter g(this, NULL);
935   // Dispatch on the source and destination operand kinds.  Not all
936   // combinations are possible.
937   if (source->IsRegister() && destination->IsRegister()) {
938     // Register-register.
939     __ xchgq(g.ToRegister(source), g.ToRegister(destination));
940   } else if (source->IsRegister() && destination->IsStackSlot()) {
941     Register src = g.ToRegister(source);
942     Operand dst = g.ToOperand(destination);
943     __ xchgq(src, dst);
944   } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
945              (source->IsDoubleStackSlot() &&
946               destination->IsDoubleStackSlot())) {
947     // Memory-memory.
948     Register tmp = kScratchRegister;
949     Operand src = g.ToOperand(source);
950     Operand dst = g.ToOperand(destination);
951     __ movq(tmp, dst);
952     __ xchgq(tmp, src);
953     __ movq(dst, tmp);
954   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
955     // XMM register-register swap. We rely on having xmm0
956     // available as a fixed scratch register.
957     XMMRegister src = g.ToDoubleRegister(source);
958     XMMRegister dst = g.ToDoubleRegister(destination);
959     __ movsd(xmm0, src);
960     __ movsd(src, dst);
961     __ movsd(dst, xmm0);
962   } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
963     // XMM register-memory swap.  We rely on having xmm0
964     // available as a fixed scratch register.
965     XMMRegister src = g.ToDoubleRegister(source);
966     Operand dst = g.ToOperand(destination);
967     __ movsd(xmm0, src);
968     __ movsd(src, dst);
969     __ movsd(dst, xmm0);
970   } else {
971     // No other combinations are possible.
972     UNREACHABLE();
973   }
974 }
975
976
977 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
978
979
980 void CodeGenerator::EnsureSpaceForLazyDeopt() {
981   int space_needed = Deoptimizer::patch_size();
982   if (!linkage()->info()->IsStub()) {
983     // Ensure that we have enough space after the previous lazy-bailout
984     // instruction for patching the code here.
985     int current_pc = masm()->pc_offset();
986     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
987       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
988       __ Nop(padding_size);
989     }
990   }
991   MarkLazyDeoptSite();
992 }
993
994 #undef __
995
996 }  // namespace internal
997 }  // namespace compiler
998 }  // namespace v8