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