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