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.
5 #include "src/compiler/code-generator.h"
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/scopes.h"
11 #include "src/x64/assembler-x64.h"
12 #include "src/x64/macro-assembler-x64.h"
21 #define kScratchDoubleReg xmm0
24 // Adds X64 specific methods for decoding operands.
25 class X64OperandConverter : public InstructionOperandConverter {
27 X64OperandConverter(CodeGenerator* gen, Instruction* instr)
28 : InstructionOperandConverter(gen, instr) {}
30 Immediate InputImmediate(size_t index) {
31 return ToImmediate(instr_->InputAt(index));
34 Operand InputOperand(size_t index, int extra = 0) {
35 return ToOperand(instr_->InputAt(index), extra);
38 Operand OutputOperand() { return ToOperand(instr_->Output()); }
40 Immediate ToImmediate(InstructionOperand* operand) {
41 Constant constant = ToConstant(operand);
42 if (constant.type() == Constant::kFloat64) {
43 DCHECK_EQ(0, bit_cast<int64_t>(constant.ToFloat64()));
46 return Immediate(constant.ToInt32());
49 Operand ToOperand(InstructionOperand* op, int extra = 0) {
50 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
51 // The linkage computes where all spill slots are located.
52 FrameOffset offset = linkage()->GetFrameOffset(
53 AllocatedOperand::cast(op)->index(), frame(), extra);
54 return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
57 static size_t NextOffset(size_t* offset) {
63 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
64 STATIC_ASSERT(0 == static_cast<int>(times_1));
65 STATIC_ASSERT(1 == static_cast<int>(times_2));
66 STATIC_ASSERT(2 == static_cast<int>(times_4));
67 STATIC_ASSERT(3 == static_cast<int>(times_8));
68 int scale = static_cast<int>(mode - one);
69 DCHECK(scale >= 0 && scale < 4);
70 return static_cast<ScaleFactor>(scale);
73 Operand MemoryOperand(size_t* offset) {
74 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
77 Register base = InputRegister(NextOffset(offset));
79 return Operand(base, disp);
82 Register base = InputRegister(NextOffset(offset));
83 int32_t disp = InputInt32(NextOffset(offset));
84 return Operand(base, disp);
90 Register base = InputRegister(NextOffset(offset));
91 Register index = InputRegister(NextOffset(offset));
92 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
94 return Operand(base, index, scale, disp);
100 Register base = InputRegister(NextOffset(offset));
101 Register index = InputRegister(NextOffset(offset));
102 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
103 int32_t disp = InputInt32(NextOffset(offset));
104 return Operand(base, index, scale, disp);
107 Register base = InputRegister(NextOffset(offset));
109 return Operand(base, disp);
112 UNREACHABLE(); // Should use kModeMR with more compact encoding instead
113 return Operand(no_reg, 0);
116 Register index = InputRegister(NextOffset(offset));
117 ScaleFactor scale = ScaleFor(kMode_M1, mode);
119 return Operand(index, scale, disp);
125 Register index = InputRegister(NextOffset(offset));
126 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
127 int32_t disp = InputInt32(NextOffset(offset));
128 return Operand(index, scale, disp);
132 return Operand(no_reg, 0);
135 return Operand(no_reg, 0);
138 Operand MemoryOperand(size_t first_input = 0) {
139 return MemoryOperand(&first_input);
146 bool HasImmediateInput(Instruction* instr, size_t index) {
147 return instr->InputAt(index)->IsImmediate();
151 class OutOfLineLoadZero final : public OutOfLineCode {
153 OutOfLineLoadZero(CodeGenerator* gen, Register result)
154 : OutOfLineCode(gen), result_(result) {}
156 void Generate() final { __ xorl(result_, result_); }
159 Register const result_;
163 class OutOfLineLoadNaN final : public OutOfLineCode {
165 OutOfLineLoadNaN(CodeGenerator* gen, XMMRegister result)
166 : OutOfLineCode(gen), result_(result) {}
168 void Generate() final { __ pcmpeqd(result_, result_); }
171 XMMRegister const result_;
175 class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
177 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
179 : OutOfLineCode(gen), result_(result), input_(input) {}
181 void Generate() final {
182 __ subp(rsp, Immediate(kDoubleSize));
183 __ movsd(MemOperand(rsp, 0), input_);
184 __ SlowTruncateToI(result_, rsp, 0);
185 __ addp(rsp, Immediate(kDoubleSize));
189 Register const result_;
190 XMMRegister const input_;
196 #define ASSEMBLE_UNOP(asm_instr) \
198 if (instr->Output()->IsRegister()) { \
199 __ asm_instr(i.OutputRegister()); \
201 __ asm_instr(i.OutputOperand()); \
206 #define ASSEMBLE_BINOP(asm_instr) \
208 if (HasImmediateInput(instr, 1)) { \
209 if (instr->InputAt(0)->IsRegister()) { \
210 __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
212 __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
215 if (instr->InputAt(1)->IsRegister()) { \
216 __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
218 __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
224 #define ASSEMBLE_MULT(asm_instr) \
226 if (HasImmediateInput(instr, 1)) { \
227 if (instr->InputAt(0)->IsRegister()) { \
228 __ asm_instr(i.OutputRegister(), i.InputRegister(0), \
229 i.InputImmediate(1)); \
231 __ asm_instr(i.OutputRegister(), i.InputOperand(0), \
232 i.InputImmediate(1)); \
235 if (instr->InputAt(1)->IsRegister()) { \
236 __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
238 __ asm_instr(i.OutputRegister(), i.InputOperand(1)); \
244 #define ASSEMBLE_SHIFT(asm_instr, width) \
246 if (HasImmediateInput(instr, 1)) { \
247 if (instr->Output()->IsRegister()) { \
248 __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
250 __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1))); \
253 if (instr->Output()->IsRegister()) { \
254 __ asm_instr##_cl(i.OutputRegister()); \
256 __ asm_instr##_cl(i.OutputOperand()); \
262 #define ASSEMBLE_MOVX(asm_instr) \
264 if (instr->addressing_mode() != kMode_None) { \
265 __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
266 } else if (instr->InputAt(0)->IsRegister()) { \
267 __ asm_instr(i.OutputRegister(), i.InputRegister(0)); \
269 __ asm_instr(i.OutputRegister(), i.InputOperand(0)); \
274 #define ASSEMBLE_SSE_BINOP(asm_instr) \
276 if (instr->InputAt(1)->IsDoubleRegister()) { \
277 __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
279 __ asm_instr(i.InputDoubleRegister(0), i.InputOperand(1)); \
284 #define ASSEMBLE_SSE_UNOP(asm_instr) \
286 if (instr->InputAt(0)->IsDoubleRegister()) { \
287 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
289 __ asm_instr(i.OutputDoubleRegister(), i.InputOperand(0)); \
294 #define ASSEMBLE_AVX_BINOP(asm_instr) \
296 CpuFeatureScope avx_scope(masm(), AVX); \
297 if (instr->InputAt(1)->IsDoubleRegister()) { \
298 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
299 i.InputDoubleRegister(1)); \
301 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
302 i.InputOperand(1)); \
307 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
309 auto result = i.OutputDoubleRegister(); \
310 auto buffer = i.InputRegister(0); \
311 auto index1 = i.InputRegister(1); \
312 auto index2 = i.InputInt32(2); \
313 OutOfLineCode* ool; \
314 if (instr->InputAt(3)->IsRegister()) { \
315 auto length = i.InputRegister(3); \
316 DCHECK_EQ(0, index2); \
317 __ cmpl(index1, length); \
318 ool = new (zone()) OutOfLineLoadNaN(this, result); \
320 auto length = i.InputInt32(3); \
321 DCHECK_LE(index2, length); \
322 __ cmpq(index1, Immediate(length - index2)); \
323 class OutOfLineLoadFloat final : public OutOfLineCode { \
325 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result, \
326 Register buffer, Register index1, int32_t index2, \
328 : OutOfLineCode(gen), \
335 void Generate() final { \
336 __ leal(kScratchRegister, Operand(index1_, index2_)); \
337 __ pcmpeqd(result_, result_); \
338 __ cmpl(kScratchRegister, Immediate(length_)); \
339 __ j(above_equal, exit()); \
340 __ asm_instr(result_, \
341 Operand(buffer_, kScratchRegister, times_1, 0)); \
345 XMMRegister const result_; \
346 Register const buffer_; \
347 Register const index1_; \
348 int32_t const index2_; \
349 int32_t const length_; \
352 OutOfLineLoadFloat(this, result, buffer, index1, index2, length); \
354 __ j(above_equal, ool->entry()); \
355 __ asm_instr(result, Operand(buffer, index1, times_1, index2)); \
356 __ bind(ool->exit()); \
360 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
362 auto result = i.OutputRegister(); \
363 auto buffer = i.InputRegister(0); \
364 auto index1 = i.InputRegister(1); \
365 auto index2 = i.InputInt32(2); \
366 OutOfLineCode* ool; \
367 if (instr->InputAt(3)->IsRegister()) { \
368 auto length = i.InputRegister(3); \
369 DCHECK_EQ(0, index2); \
370 __ cmpl(index1, length); \
371 ool = new (zone()) OutOfLineLoadZero(this, result); \
373 auto length = i.InputInt32(3); \
374 DCHECK_LE(index2, length); \
375 __ cmpq(index1, Immediate(length - index2)); \
376 class OutOfLineLoadInteger final : public OutOfLineCode { \
378 OutOfLineLoadInteger(CodeGenerator* gen, Register result, \
379 Register buffer, Register index1, int32_t index2, \
381 : OutOfLineCode(gen), \
388 void Generate() final { \
390 __ leal(kScratchRegister, Operand(index1_, index2_)); \
391 __ cmpl(kScratchRegister, Immediate(length_)); \
392 __ j(above_equal, &oob, Label::kNear); \
393 __ asm_instr(result_, \
394 Operand(buffer_, kScratchRegister, times_1, 0)); \
397 __ xorl(result_, result_); \
401 Register const result_; \
402 Register const buffer_; \
403 Register const index1_; \
404 int32_t const index2_; \
405 int32_t const length_; \
408 OutOfLineLoadInteger(this, result, buffer, index1, index2, length); \
410 __ j(above_equal, ool->entry()); \
411 __ asm_instr(result, Operand(buffer, index1, times_1, index2)); \
412 __ bind(ool->exit()); \
416 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
418 auto buffer = i.InputRegister(0); \
419 auto index1 = i.InputRegister(1); \
420 auto index2 = i.InputInt32(2); \
421 auto value = i.InputDoubleRegister(4); \
422 if (instr->InputAt(3)->IsRegister()) { \
423 auto length = i.InputRegister(3); \
424 DCHECK_EQ(0, index2); \
426 __ cmpl(index1, length); \
427 __ j(above_equal, &done, Label::kNear); \
428 __ asm_instr(Operand(buffer, index1, times_1, index2), value); \
431 auto length = i.InputInt32(3); \
432 DCHECK_LE(index2, length); \
433 __ cmpq(index1, Immediate(length - index2)); \
434 class OutOfLineStoreFloat final : public OutOfLineCode { \
436 OutOfLineStoreFloat(CodeGenerator* gen, Register buffer, \
437 Register index1, int32_t index2, int32_t length, \
439 : OutOfLineCode(gen), \
446 void Generate() final { \
447 __ leal(kScratchRegister, Operand(index1_, index2_)); \
448 __ cmpl(kScratchRegister, Immediate(length_)); \
449 __ j(above_equal, exit()); \
450 __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \
455 Register const buffer_; \
456 Register const index1_; \
457 int32_t const index2_; \
458 int32_t const length_; \
459 XMMRegister const value_; \
461 auto ool = new (zone()) \
462 OutOfLineStoreFloat(this, buffer, index1, index2, length, value); \
463 __ j(above_equal, ool->entry()); \
464 __ asm_instr(Operand(buffer, index1, times_1, index2), value); \
465 __ bind(ool->exit()); \
470 #define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value) \
472 auto buffer = i.InputRegister(0); \
473 auto index1 = i.InputRegister(1); \
474 auto index2 = i.InputInt32(2); \
475 if (instr->InputAt(3)->IsRegister()) { \
476 auto length = i.InputRegister(3); \
477 DCHECK_EQ(0, index2); \
479 __ cmpl(index1, length); \
480 __ j(above_equal, &done, Label::kNear); \
481 __ asm_instr(Operand(buffer, index1, times_1, index2), value); \
484 auto length = i.InputInt32(3); \
485 DCHECK_LE(index2, length); \
486 __ cmpq(index1, Immediate(length - index2)); \
487 class OutOfLineStoreInteger final : public OutOfLineCode { \
489 OutOfLineStoreInteger(CodeGenerator* gen, Register buffer, \
490 Register index1, int32_t index2, int32_t length, \
492 : OutOfLineCode(gen), \
499 void Generate() final { \
500 __ leal(kScratchRegister, Operand(index1_, index2_)); \
501 __ cmpl(kScratchRegister, Immediate(length_)); \
502 __ j(above_equal, exit()); \
503 __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \
508 Register const buffer_; \
509 Register const index1_; \
510 int32_t const index2_; \
511 int32_t const length_; \
512 Value const value_; \
514 auto ool = new (zone()) \
515 OutOfLineStoreInteger(this, buffer, index1, index2, length, value); \
516 __ j(above_equal, ool->entry()); \
517 __ asm_instr(Operand(buffer, index1, times_1, index2), value); \
518 __ bind(ool->exit()); \
523 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
525 if (instr->InputAt(4)->IsRegister()) { \
526 Register value = i.InputRegister(4); \
527 ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Register); \
529 Immediate value = i.InputImmediate(4); \
530 ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Immediate); \
535 void CodeGenerator::AssembleDeconstructActivationRecord() {
536 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
537 int stack_slots = frame()->GetSpillSlotCount();
538 if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
541 int32_t bytes_to_pop =
542 descriptor->IsJSFunctionCall()
543 ? static_cast<int32_t>(descriptor->JSParameterCount() *
546 __ popq(Operand(rsp, bytes_to_pop));
547 __ addq(rsp, Immediate(bytes_to_pop));
552 // Assembles an instruction after register allocation, producing machine code.
553 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
554 X64OperandConverter i(this, instr);
556 switch (ArchOpcodeField::decode(instr->opcode())) {
557 case kArchCallCodeObject: {
558 EnsureSpaceForLazyDeopt();
559 if (HasImmediateInput(instr, 0)) {
560 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
561 __ Call(code, RelocInfo::CODE_TARGET);
563 Register reg = i.InputRegister(0);
564 int entry = Code::kHeaderSize - kHeapObjectTag;
565 __ Call(Operand(reg, entry));
567 RecordCallPosition(instr);
570 case kArchTailCallCodeObject: {
571 AssembleDeconstructActivationRecord();
572 if (HasImmediateInput(instr, 0)) {
573 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
574 __ jmp(code, RelocInfo::CODE_TARGET);
576 Register reg = i.InputRegister(0);
577 int entry = Code::kHeaderSize - kHeapObjectTag;
578 __ jmp(Operand(reg, entry));
582 case kArchCallJSFunction: {
583 EnsureSpaceForLazyDeopt();
584 Register func = i.InputRegister(0);
585 if (FLAG_debug_code) {
586 // Check the function's context matches the context argument.
587 __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
588 __ Assert(equal, kWrongFunctionContext);
590 __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
591 RecordCallPosition(instr);
594 case kArchTailCallJSFunction: {
595 Register func = i.InputRegister(0);
596 if (FLAG_debug_code) {
597 // Check the function's context matches the context argument.
598 __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
599 __ Assert(equal, kWrongFunctionContext);
601 AssembleDeconstructActivationRecord();
602 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
606 AssembleArchJump(i.InputRpo(0));
608 case kArchLookupSwitch:
609 AssembleArchLookupSwitch(instr);
611 case kArchTableSwitch:
612 AssembleArchTableSwitch(instr);
615 // don't emit code for nops.
617 case kArchDeoptimize: {
619 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
620 AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
626 case kArchStackPointer:
627 __ movq(i.OutputRegister(), rsp);
629 case kArchFramePointer:
630 __ movq(i.OutputRegister(), rbp);
632 case kArchTruncateDoubleToI: {
633 auto result = i.OutputRegister();
634 auto input = i.InputDoubleRegister(0);
635 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
636 __ cvttsd2siq(result, input);
637 __ cmpq(result, Immediate(1));
638 __ j(overflow, ool->entry());
639 __ bind(ool->exit());
643 ASSEMBLE_BINOP(addl);
646 ASSEMBLE_BINOP(addq);
649 ASSEMBLE_BINOP(subl);
652 ASSEMBLE_BINOP(subq);
655 ASSEMBLE_BINOP(andl);
658 ASSEMBLE_BINOP(andq);
661 ASSEMBLE_BINOP(cmpl);
664 ASSEMBLE_BINOP(cmpq);
667 ASSEMBLE_BINOP(testl);
670 ASSEMBLE_BINOP(testq);
673 ASSEMBLE_MULT(imull);
676 ASSEMBLE_MULT(imulq);
679 if (instr->InputAt(1)->IsRegister()) {
680 __ imull(i.InputRegister(1));
682 __ imull(i.InputOperand(1));
686 if (instr->InputAt(1)->IsRegister()) {
687 __ mull(i.InputRegister(1));
689 __ mull(i.InputOperand(1));
694 __ idivl(i.InputRegister(1));
698 __ idivq(i.InputRegister(1));
702 __ divl(i.InputRegister(1));
706 __ divq(i.InputRegister(1));
727 ASSEMBLE_BINOP(xorl);
730 ASSEMBLE_BINOP(xorq);
733 ASSEMBLE_SHIFT(shll, 5);
736 ASSEMBLE_SHIFT(shlq, 6);
739 ASSEMBLE_SHIFT(shrl, 5);
742 ASSEMBLE_SHIFT(shrq, 6);
745 ASSEMBLE_SHIFT(sarl, 5);
748 ASSEMBLE_SHIFT(sarq, 6);
751 ASSEMBLE_SHIFT(rorl, 5);
754 ASSEMBLE_SHIFT(rorq, 6);
757 if (instr->InputAt(0)->IsRegister()) {
758 __ Lzcntl(i.OutputRegister(), i.InputRegister(0));
760 __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
764 ASSEMBLE_SSE_BINOP(ucomiss);
767 ASSEMBLE_SSE_BINOP(addss);
770 ASSEMBLE_SSE_BINOP(subss);
773 ASSEMBLE_SSE_BINOP(mulss);
776 ASSEMBLE_SSE_BINOP(divss);
777 // Don't delete this mov. It may improve performance on some CPUs,
778 // when there is a (v)mulss depending on the result.
779 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
781 case kSSEFloat32Abs: {
782 // TODO(bmeurer): Use RIP relative 128-bit constants.
783 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
784 __ psrlq(kScratchDoubleReg, 33);
785 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
788 case kSSEFloat32Neg: {
789 // TODO(bmeurer): Use RIP relative 128-bit constants.
790 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
791 __ psllq(kScratchDoubleReg, 31);
792 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
795 case kSSEFloat32Sqrt:
796 ASSEMBLE_SSE_UNOP(sqrtss);
799 ASSEMBLE_SSE_BINOP(maxss);
802 ASSEMBLE_SSE_BINOP(minss);
804 case kSSEFloat32ToFloat64:
805 ASSEMBLE_SSE_UNOP(cvtss2sd);
808 ASSEMBLE_SSE_BINOP(ucomisd);
811 ASSEMBLE_SSE_BINOP(addsd);
814 ASSEMBLE_SSE_BINOP(subsd);
817 ASSEMBLE_SSE_BINOP(mulsd);
820 ASSEMBLE_SSE_BINOP(divsd);
821 // Don't delete this mov. It may improve performance on some CPUs,
822 // when there is a (v)mulsd depending on the result.
823 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
825 case kSSEFloat64Mod: {
826 __ subq(rsp, Immediate(kDoubleSize));
827 // Move values to st(0) and st(1).
828 __ movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
829 __ fld_d(Operand(rsp, 0));
830 __ movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
831 __ fld_d(Operand(rsp, 0));
832 // Loop while fprem isn't done.
835 // This instructions traps on all kinds inputs, but we are assuming the
836 // floating point control word is set to ignore them all.
838 // The following 2 instruction implicitly use rax.
840 if (CpuFeatures::IsSupported(SAHF)) {
841 CpuFeatureScope sahf_scope(masm(), SAHF);
844 __ shrl(rax, Immediate(8));
845 __ andl(rax, Immediate(0xFF));
849 __ j(parity_even, &mod_loop);
850 // Move output to stack and clean up.
852 __ fstp_d(Operand(rsp, 0));
853 __ movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
854 __ addq(rsp, Immediate(kDoubleSize));
858 ASSEMBLE_SSE_BINOP(maxsd);
861 ASSEMBLE_SSE_BINOP(minsd);
863 case kSSEFloat64Abs: {
864 // TODO(bmeurer): Use RIP relative 128-bit constants.
865 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
866 __ psrlq(kScratchDoubleReg, 1);
867 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
870 case kSSEFloat64Neg: {
871 // TODO(bmeurer): Use RIP relative 128-bit constants.
872 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
873 __ psllq(kScratchDoubleReg, 63);
874 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
877 case kSSEFloat64Sqrt:
878 ASSEMBLE_SSE_UNOP(sqrtsd);
880 case kSSEFloat64Round: {
881 CpuFeatureScope sse_scope(masm(), SSE4_1);
882 RoundingMode const mode =
883 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
884 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
887 case kSSEFloat64ToFloat32:
888 ASSEMBLE_SSE_UNOP(cvtsd2ss);
890 case kSSEFloat64ToInt32:
891 if (instr->InputAt(0)->IsDoubleRegister()) {
892 __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
894 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
897 case kSSEFloat64ToUint32: {
898 if (instr->InputAt(0)->IsDoubleRegister()) {
899 __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
901 __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
903 __ AssertZeroExtended(i.OutputRegister());
906 case kSSEInt32ToFloat64:
907 if (instr->InputAt(0)->IsRegister()) {
908 __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
910 __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
913 case kSSEUint32ToFloat64:
914 if (instr->InputAt(0)->IsRegister()) {
915 __ movl(kScratchRegister, i.InputRegister(0));
917 __ movl(kScratchRegister, i.InputOperand(0));
919 __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
921 case kSSEFloat64ExtractLowWord32:
922 if (instr->InputAt(0)->IsDoubleStackSlot()) {
923 __ movl(i.OutputRegister(), i.InputOperand(0));
925 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
928 case kSSEFloat64ExtractHighWord32:
929 if (instr->InputAt(0)->IsDoubleStackSlot()) {
930 __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
932 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
935 case kSSEFloat64InsertLowWord32:
936 if (instr->InputAt(1)->IsRegister()) {
937 __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
939 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
942 case kSSEFloat64InsertHighWord32:
943 if (instr->InputAt(1)->IsRegister()) {
944 __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
946 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
949 case kSSEFloat64LoadLowWord32:
950 if (instr->InputAt(0)->IsRegister()) {
951 __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
953 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
956 case kAVXFloat32Cmp: {
957 CpuFeatureScope avx_scope(masm(), AVX);
958 if (instr->InputAt(1)->IsDoubleRegister()) {
959 __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
961 __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
966 ASSEMBLE_AVX_BINOP(vaddss);
969 ASSEMBLE_AVX_BINOP(vsubss);
972 ASSEMBLE_AVX_BINOP(vmulss);
975 ASSEMBLE_AVX_BINOP(vdivss);
976 // Don't delete this mov. It may improve performance on some CPUs,
977 // when there is a (v)mulss depending on the result.
978 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
981 ASSEMBLE_AVX_BINOP(vmaxss);
984 ASSEMBLE_AVX_BINOP(vminss);
986 case kAVXFloat64Cmp: {
987 CpuFeatureScope avx_scope(masm(), AVX);
988 if (instr->InputAt(1)->IsDoubleRegister()) {
989 __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
991 __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
996 ASSEMBLE_AVX_BINOP(vaddsd);
999 ASSEMBLE_AVX_BINOP(vsubsd);
1001 case kAVXFloat64Mul:
1002 ASSEMBLE_AVX_BINOP(vmulsd);
1004 case kAVXFloat64Div:
1005 ASSEMBLE_AVX_BINOP(vdivsd);
1006 // Don't delete this mov. It may improve performance on some CPUs,
1007 // when there is a (v)mulsd depending on the result.
1008 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1010 case kAVXFloat64Max:
1011 ASSEMBLE_AVX_BINOP(vmaxsd);
1013 case kAVXFloat64Min:
1014 ASSEMBLE_AVX_BINOP(vminsd);
1016 case kAVXFloat32Abs: {
1017 // TODO(bmeurer): Use RIP relative 128-bit constants.
1018 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1019 __ psrlq(kScratchDoubleReg, 33);
1020 CpuFeatureScope avx_scope(masm(), AVX);
1021 if (instr->InputAt(0)->IsDoubleRegister()) {
1022 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
1023 i.InputDoubleRegister(0));
1025 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
1030 case kAVXFloat32Neg: {
1031 // TODO(bmeurer): Use RIP relative 128-bit constants.
1032 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1033 __ psllq(kScratchDoubleReg, 31);
1034 CpuFeatureScope avx_scope(masm(), AVX);
1035 if (instr->InputAt(0)->IsDoubleRegister()) {
1036 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
1037 i.InputDoubleRegister(0));
1039 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
1044 case kAVXFloat64Abs: {
1045 // TODO(bmeurer): Use RIP relative 128-bit constants.
1046 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1047 __ psrlq(kScratchDoubleReg, 1);
1048 CpuFeatureScope avx_scope(masm(), AVX);
1049 if (instr->InputAt(0)->IsDoubleRegister()) {
1050 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1051 i.InputDoubleRegister(0));
1053 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1058 case kAVXFloat64Neg: {
1059 // TODO(bmeurer): Use RIP relative 128-bit constants.
1060 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1061 __ psllq(kScratchDoubleReg, 63);
1062 CpuFeatureScope avx_scope(masm(), AVX);
1063 if (instr->InputAt(0)->IsDoubleRegister()) {
1064 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1065 i.InputDoubleRegister(0));
1067 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1073 ASSEMBLE_MOVX(movsxbl);
1074 __ AssertZeroExtended(i.OutputRegister());
1077 ASSEMBLE_MOVX(movzxbl);
1078 __ AssertZeroExtended(i.OutputRegister());
1082 Operand operand = i.MemoryOperand(&index);
1083 if (HasImmediateInput(instr, index)) {
1084 __ movb(operand, Immediate(i.InputInt8(index)));
1086 __ movb(operand, i.InputRegister(index));
1091 ASSEMBLE_MOVX(movsxwl);
1092 __ AssertZeroExtended(i.OutputRegister());
1095 ASSEMBLE_MOVX(movzxwl);
1096 __ AssertZeroExtended(i.OutputRegister());
1100 Operand operand = i.MemoryOperand(&index);
1101 if (HasImmediateInput(instr, index)) {
1102 __ movw(operand, Immediate(i.InputInt16(index)));
1104 __ movw(operand, i.InputRegister(index));
1109 if (instr->HasOutput()) {
1110 if (instr->addressing_mode() == kMode_None) {
1111 if (instr->InputAt(0)->IsRegister()) {
1112 __ movl(i.OutputRegister(), i.InputRegister(0));
1114 __ movl(i.OutputRegister(), i.InputOperand(0));
1117 __ movl(i.OutputRegister(), i.MemoryOperand());
1119 __ AssertZeroExtended(i.OutputRegister());
1122 Operand operand = i.MemoryOperand(&index);
1123 if (HasImmediateInput(instr, index)) {
1124 __ movl(operand, i.InputImmediate(index));
1126 __ movl(operand, i.InputRegister(index));
1131 ASSEMBLE_MOVX(movsxlq);
1134 if (instr->HasOutput()) {
1135 __ movq(i.OutputRegister(), i.MemoryOperand());
1138 Operand operand = i.MemoryOperand(&index);
1139 if (HasImmediateInput(instr, index)) {
1140 __ movq(operand, i.InputImmediate(index));
1142 __ movq(operand, i.InputRegister(index));
1147 if (instr->HasOutput()) {
1148 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
1151 Operand operand = i.MemoryOperand(&index);
1152 __ movss(operand, i.InputDoubleRegister(index));
1156 if (instr->HasOutput()) {
1157 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
1160 Operand operand = i.MemoryOperand(&index);
1161 __ movsd(operand, i.InputDoubleRegister(index));
1165 AddressingMode mode = AddressingModeField::decode(instr->opcode());
1166 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1167 // and addressing mode just happens to work out. The "addl"/"subl" forms
1168 // in these cases are faster based on measurements.
1169 if (i.InputRegister(0).is(i.OutputRegister())) {
1170 if (mode == kMode_MRI) {
1171 int32_t constant_summand = i.InputInt32(1);
1172 if (constant_summand > 0) {
1173 __ addl(i.OutputRegister(), Immediate(constant_summand));
1174 } else if (constant_summand < 0) {
1175 __ subl(i.OutputRegister(), Immediate(-constant_summand));
1177 } else if (mode == kMode_MR1) {
1178 if (i.InputRegister(1).is(i.OutputRegister())) {
1179 __ shll(i.OutputRegister(), Immediate(1));
1181 __ leal(i.OutputRegister(), i.MemoryOperand());
1183 } else if (mode == kMode_M2) {
1184 __ shll(i.OutputRegister(), Immediate(1));
1185 } else if (mode == kMode_M4) {
1186 __ shll(i.OutputRegister(), Immediate(2));
1187 } else if (mode == kMode_M8) {
1188 __ shll(i.OutputRegister(), Immediate(3));
1190 __ leal(i.OutputRegister(), i.MemoryOperand());
1193 __ leal(i.OutputRegister(), i.MemoryOperand());
1195 __ AssertZeroExtended(i.OutputRegister());
1199 __ leaq(i.OutputRegister(), i.MemoryOperand());
1202 __ decl(i.OutputRegister());
1205 __ incl(i.OutputRegister());
1208 if (HasImmediateInput(instr, 0)) {
1209 __ pushq(i.InputImmediate(0));
1211 if (instr->InputAt(0)->IsRegister()) {
1212 __ pushq(i.InputRegister(0));
1214 __ pushq(i.InputOperand(0));
1218 case kX64StoreWriteBarrier: {
1219 Register object = i.InputRegister(0);
1220 Register value = i.InputRegister(2);
1221 SaveFPRegsMode mode =
1222 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
1223 if (HasImmediateInput(instr, 1)) {
1224 int index = i.InputInt32(1);
1225 Register scratch = i.TempRegister(1);
1226 __ movq(Operand(object, index), value);
1227 __ RecordWriteContextSlot(object, index, value, scratch, mode);
1229 Register index = i.InputRegister(1);
1230 __ movq(Operand(object, index, times_1, 0), value);
1231 __ leaq(index, Operand(object, index, times_1, 0));
1232 __ RecordWrite(object, index, value, mode);
1236 case kCheckedLoadInt8:
1237 ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
1239 case kCheckedLoadUint8:
1240 ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
1242 case kCheckedLoadInt16:
1243 ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
1245 case kCheckedLoadUint16:
1246 ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
1248 case kCheckedLoadWord32:
1249 ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
1251 case kCheckedLoadFloat32:
1252 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
1254 case kCheckedLoadFloat64:
1255 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
1257 case kCheckedStoreWord8:
1258 ASSEMBLE_CHECKED_STORE_INTEGER(movb);
1260 case kCheckedStoreWord16:
1261 ASSEMBLE_CHECKED_STORE_INTEGER(movw);
1263 case kCheckedStoreWord32:
1264 ASSEMBLE_CHECKED_STORE_INTEGER(movl);
1266 case kCheckedStoreFloat32:
1267 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
1269 case kCheckedStoreFloat64:
1270 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
1272 case kX64StackCheck:
1273 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
1276 } // NOLINT(readability/fn_size)
1279 // Assembles branches after this instruction.
1280 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1281 X64OperandConverter i(this, instr);
1282 Label::Distance flabel_distance =
1283 branch->fallthru ? Label::kNear : Label::kFar;
1284 Label* tlabel = branch->true_label;
1285 Label* flabel = branch->false_label;
1286 switch (branch->condition) {
1287 case kUnorderedEqual:
1288 __ j(parity_even, flabel, flabel_distance);
1291 __ j(equal, tlabel);
1293 case kUnorderedNotEqual:
1294 __ j(parity_even, tlabel);
1297 __ j(not_equal, tlabel);
1299 case kSignedLessThan:
1302 case kSignedGreaterThanOrEqual:
1303 __ j(greater_equal, tlabel);
1305 case kSignedLessThanOrEqual:
1306 __ j(less_equal, tlabel);
1308 case kSignedGreaterThan:
1309 __ j(greater, tlabel);
1311 case kUnsignedLessThan:
1312 __ j(below, tlabel);
1314 case kUnsignedGreaterThanOrEqual:
1315 __ j(above_equal, tlabel);
1317 case kUnsignedLessThanOrEqual:
1318 __ j(below_equal, tlabel);
1320 case kUnsignedGreaterThan:
1321 __ j(above, tlabel);
1324 __ j(overflow, tlabel);
1327 __ j(no_overflow, tlabel);
1330 if (!branch->fallthru) __ jmp(flabel, flabel_distance);
1334 void CodeGenerator::AssembleArchJump(RpoNumber target) {
1335 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
1339 // Assembles boolean materializations after this instruction.
1340 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1341 FlagsCondition condition) {
1342 X64OperandConverter i(this, instr);
1345 // Materialize a full 64-bit 1 or 0 value. The result register is always the
1346 // last output of the instruction.
1348 DCHECK_NE(0u, instr->OutputCount());
1349 Register reg = i.OutputRegister(instr->OutputCount() - 1);
1350 Condition cc = no_condition;
1351 switch (condition) {
1352 case kUnorderedEqual:
1353 __ j(parity_odd, &check, Label::kNear);
1354 __ movl(reg, Immediate(0));
1355 __ jmp(&done, Label::kNear);
1360 case kUnorderedNotEqual:
1361 __ j(parity_odd, &check, Label::kNear);
1362 __ movl(reg, Immediate(1));
1363 __ jmp(&done, Label::kNear);
1368 case kSignedLessThan:
1371 case kSignedGreaterThanOrEqual:
1374 case kSignedLessThanOrEqual:
1377 case kSignedGreaterThan:
1380 case kUnsignedLessThan:
1383 case kUnsignedGreaterThanOrEqual:
1386 case kUnsignedLessThanOrEqual:
1389 case kUnsignedGreaterThan:
1401 __ movzxbl(reg, reg);
1406 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1407 X64OperandConverter i(this, instr);
1408 Register input = i.InputRegister(0);
1409 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1410 __ cmpl(input, Immediate(i.InputInt32(index + 0)));
1411 __ j(equal, GetLabel(i.InputRpo(index + 1)));
1413 AssembleArchJump(i.InputRpo(1));
1417 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1418 X64OperandConverter i(this, instr);
1419 Register input = i.InputRegister(0);
1420 int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
1421 Label** cases = zone()->NewArray<Label*>(case_count);
1422 for (int32_t index = 0; index < case_count; ++index) {
1423 cases[index] = GetLabel(i.InputRpo(index + 2));
1425 Label* const table = AddJumpTable(cases, case_count);
1426 __ cmpl(input, Immediate(case_count));
1427 __ j(above_equal, GetLabel(i.InputRpo(1)));
1428 __ leaq(kScratchRegister, Operand(table));
1429 __ jmp(Operand(kScratchRegister, input, times_8, 0));
1433 void CodeGenerator::AssembleDeoptimizerCall(
1434 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
1435 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
1436 isolate(), deoptimization_id, bailout_type);
1437 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1441 void CodeGenerator::AssemblePrologue() {
1442 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1443 int stack_slots = frame()->GetSpillSlotCount();
1444 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1447 const RegList saves = descriptor->CalleeSavedRegisters();
1448 if (saves != 0) { // Save callee-saved registers.
1449 int register_save_area_size = 0;
1450 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1451 if (!((1 << i) & saves)) continue;
1452 __ pushq(Register::from_code(i));
1453 register_save_area_size += kPointerSize;
1455 frame()->SetRegisterSaveAreaSize(register_save_area_size);
1457 } else if (descriptor->IsJSFunctionCall()) {
1458 CompilationInfo* info = this->info();
1459 __ Prologue(info->IsCodePreAgingActive());
1460 frame()->SetRegisterSaveAreaSize(
1461 StandardFrameConstants::kFixedFrameSizeFromFp);
1462 } else if (needs_frame_) {
1464 frame()->SetRegisterSaveAreaSize(
1465 StandardFrameConstants::kFixedFrameSizeFromFp);
1468 if (info()->is_osr()) {
1469 // TurboFan OSR-compiled functions cannot be entered directly.
1470 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1472 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1473 // frame is still on the stack. Optimized code uses OSR values directly from
1474 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1475 // remaining stack slots.
1476 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1477 osr_pc_offset_ = __ pc_offset();
1478 // TODO(titzer): cannot address target function == local #-1
1479 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1480 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
1481 stack_slots -= frame()->GetOsrStackSlotCount();
1484 if (stack_slots > 0) {
1485 __ subq(rsp, Immediate(stack_slots * kPointerSize));
1490 void CodeGenerator::AssembleReturn() {
1491 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1492 int stack_slots = frame()->GetSpillSlotCount();
1493 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1494 if (frame()->GetRegisterSaveAreaSize() > 0) {
1495 // Remove this frame's spill slots first.
1496 if (stack_slots > 0) {
1497 __ addq(rsp, Immediate(stack_slots * kPointerSize));
1499 const RegList saves = descriptor->CalleeSavedRegisters();
1500 // Restore registers.
1502 for (int i = 0; i < Register::kNumRegisters; i++) {
1503 if (!((1 << i) & saves)) continue;
1504 __ popq(Register::from_code(i));
1507 __ popq(rbp); // Pop caller's frame pointer.
1510 // No saved registers.
1511 __ movq(rsp, rbp); // Move stack pointer back to frame pointer.
1512 __ popq(rbp); // Pop caller's frame pointer.
1515 } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
1516 __ movq(rsp, rbp); // Move stack pointer back to frame pointer.
1517 __ popq(rbp); // Pop caller's frame pointer.
1518 int pop_count = descriptor->IsJSFunctionCall()
1519 ? static_cast<int>(descriptor->JSParameterCount())
1521 __ Ret(pop_count * kPointerSize, rbx);
1528 void CodeGenerator::AssembleMove(InstructionOperand* source,
1529 InstructionOperand* destination) {
1530 X64OperandConverter g(this, NULL);
1531 // Dispatch on the source and destination operand kinds. Not all
1532 // combinations are possible.
1533 if (source->IsRegister()) {
1534 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1535 Register src = g.ToRegister(source);
1536 if (destination->IsRegister()) {
1537 __ movq(g.ToRegister(destination), src);
1539 __ movq(g.ToOperand(destination), src);
1541 } else if (source->IsStackSlot()) {
1542 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1543 Operand src = g.ToOperand(source);
1544 if (destination->IsRegister()) {
1545 Register dst = g.ToRegister(destination);
1548 // Spill on demand to use a temporary register for memory-to-memory
1550 Register tmp = kScratchRegister;
1551 Operand dst = g.ToOperand(destination);
1555 } else if (source->IsConstant()) {
1556 ConstantOperand* constant_source = ConstantOperand::cast(source);
1557 Constant src = g.ToConstant(constant_source);
1558 if (destination->IsRegister() || destination->IsStackSlot()) {
1559 Register dst = destination->IsRegister() ? g.ToRegister(destination)
1561 switch (src.type()) {
1562 case Constant::kInt32:
1563 // TODO(dcarney): don't need scratch in this case.
1564 __ Set(dst, src.ToInt32());
1566 case Constant::kInt64:
1567 __ Set(dst, src.ToInt64());
1569 case Constant::kFloat32:
1571 isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1573 case Constant::kFloat64:
1575 isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1577 case Constant::kExternalReference:
1578 __ Move(dst, src.ToExternalReference());
1580 case Constant::kHeapObject: {
1581 Handle<HeapObject> src_object = src.ToHeapObject();
1582 Heap::RootListIndex index;
1584 if (IsMaterializableFromFrame(src_object, &offset)) {
1585 __ movp(dst, Operand(rbp, offset));
1586 } else if (IsMaterializableFromRoot(src_object, &index)) {
1587 __ LoadRoot(dst, index);
1589 __ Move(dst, src_object);
1593 case Constant::kRpoNumber:
1594 UNREACHABLE(); // TODO(dcarney): load of labels on x64.
1597 if (destination->IsStackSlot()) {
1598 __ movq(g.ToOperand(destination), kScratchRegister);
1600 } else if (src.type() == Constant::kFloat32) {
1601 // TODO(turbofan): Can we do better here?
1602 uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
1603 if (destination->IsDoubleRegister()) {
1604 __ Move(g.ToDoubleRegister(destination), src_const);
1606 DCHECK(destination->IsDoubleStackSlot());
1607 Operand dst = g.ToOperand(destination);
1608 __ movl(dst, Immediate(src_const));
1611 DCHECK_EQ(Constant::kFloat64, src.type());
1612 uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
1613 if (destination->IsDoubleRegister()) {
1614 __ Move(g.ToDoubleRegister(destination), src_const);
1616 DCHECK(destination->IsDoubleStackSlot());
1617 __ movq(kScratchRegister, src_const);
1618 __ movq(g.ToOperand(destination), kScratchRegister);
1621 } else if (source->IsDoubleRegister()) {
1622 XMMRegister src = g.ToDoubleRegister(source);
1623 if (destination->IsDoubleRegister()) {
1624 XMMRegister dst = g.ToDoubleRegister(destination);
1625 __ movaps(dst, src);
1627 DCHECK(destination->IsDoubleStackSlot());
1628 Operand dst = g.ToOperand(destination);
1631 } else if (source->IsDoubleStackSlot()) {
1632 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1633 Operand src = g.ToOperand(source);
1634 if (destination->IsDoubleRegister()) {
1635 XMMRegister dst = g.ToDoubleRegister(destination);
1638 // We rely on having xmm0 available as a fixed scratch register.
1639 Operand dst = g.ToOperand(destination);
1640 __ movsd(xmm0, src);
1641 __ movsd(dst, xmm0);
1649 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1650 InstructionOperand* destination) {
1651 X64OperandConverter g(this, NULL);
1652 // Dispatch on the source and destination operand kinds. Not all
1653 // combinations are possible.
1654 if (source->IsRegister() && destination->IsRegister()) {
1655 // Register-register.
1656 __ xchgq(g.ToRegister(source), g.ToRegister(destination));
1657 } else if (source->IsRegister() && destination->IsStackSlot()) {
1658 Register src = g.ToRegister(source);
1659 Operand dst = g.ToOperand(destination);
1661 } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
1662 (source->IsDoubleStackSlot() &&
1663 destination->IsDoubleStackSlot())) {
1665 Register tmp = kScratchRegister;
1666 Operand src = g.ToOperand(source);
1667 Operand dst = g.ToOperand(destination);
1671 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
1672 // XMM register-register swap. We rely on having xmm0
1673 // available as a fixed scratch register.
1674 XMMRegister src = g.ToDoubleRegister(source);
1675 XMMRegister dst = g.ToDoubleRegister(destination);
1676 __ movaps(xmm0, src);
1677 __ movaps(src, dst);
1678 __ movaps(dst, xmm0);
1679 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
1680 // XMM register-memory swap. We rely on having xmm0
1681 // available as a fixed scratch register.
1682 XMMRegister src = g.ToDoubleRegister(source);
1683 Operand dst = g.ToOperand(destination);
1684 __ movsd(xmm0, src);
1686 __ movsd(dst, xmm0);
1688 // No other combinations are possible.
1694 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1695 for (size_t index = 0; index < target_count; ++index) {
1696 __ dq(targets[index]);
1701 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
1704 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1705 int space_needed = Deoptimizer::patch_size();
1706 if (!info()->IsStub()) {
1707 // Ensure that we have enough space after the previous lazy-bailout
1708 // instruction for patching the code here.
1709 int current_pc = masm()->pc_offset();
1710 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1711 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1712 __ Nop(padding_size);
1715 MarkLazyDeoptSite();
1720 } // namespace internal
1721 } // namespace compiler