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));
605 case kArchPrepareCallCFunction: {
606 int const num_parameters = MiscField::decode(instr->opcode());
607 __ PrepareCallCFunction(num_parameters);
610 case kArchCallCFunction: {
611 int const num_parameters = MiscField::decode(instr->opcode());
612 if (HasImmediateInput(instr, 0)) {
613 ExternalReference ref = i.InputExternalReference(0);
614 __ CallCFunction(ref, num_parameters);
616 Register func = i.InputRegister(0);
617 __ CallCFunction(func, num_parameters);
622 AssembleArchJump(i.InputRpo(0));
624 case kArchLookupSwitch:
625 AssembleArchLookupSwitch(instr);
627 case kArchTableSwitch:
628 AssembleArchTableSwitch(instr);
631 // don't emit code for nops.
633 case kArchDeoptimize: {
635 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
636 AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
642 case kArchStackPointer:
643 __ movq(i.OutputRegister(), rsp);
645 case kArchFramePointer:
646 __ movq(i.OutputRegister(), rbp);
648 case kArchTruncateDoubleToI: {
649 auto result = i.OutputRegister();
650 auto input = i.InputDoubleRegister(0);
651 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
652 __ cvttsd2siq(result, input);
653 __ cmpq(result, Immediate(1));
654 __ j(overflow, ool->entry());
655 __ bind(ool->exit());
659 ASSEMBLE_BINOP(addl);
662 ASSEMBLE_BINOP(addq);
665 ASSEMBLE_BINOP(subl);
668 ASSEMBLE_BINOP(subq);
671 ASSEMBLE_BINOP(andl);
674 ASSEMBLE_BINOP(andq);
677 ASSEMBLE_BINOP(cmpl);
680 ASSEMBLE_BINOP(cmpq);
683 ASSEMBLE_BINOP(testl);
686 ASSEMBLE_BINOP(testq);
689 ASSEMBLE_MULT(imull);
692 ASSEMBLE_MULT(imulq);
695 if (instr->InputAt(1)->IsRegister()) {
696 __ imull(i.InputRegister(1));
698 __ imull(i.InputOperand(1));
702 if (instr->InputAt(1)->IsRegister()) {
703 __ mull(i.InputRegister(1));
705 __ mull(i.InputOperand(1));
710 __ idivl(i.InputRegister(1));
714 __ idivq(i.InputRegister(1));
718 __ divl(i.InputRegister(1));
722 __ divq(i.InputRegister(1));
743 ASSEMBLE_BINOP(xorl);
746 ASSEMBLE_BINOP(xorq);
749 ASSEMBLE_SHIFT(shll, 5);
752 ASSEMBLE_SHIFT(shlq, 6);
755 ASSEMBLE_SHIFT(shrl, 5);
758 ASSEMBLE_SHIFT(shrq, 6);
761 ASSEMBLE_SHIFT(sarl, 5);
764 ASSEMBLE_SHIFT(sarq, 6);
767 ASSEMBLE_SHIFT(rorl, 5);
770 ASSEMBLE_SHIFT(rorq, 6);
773 if (instr->InputAt(0)->IsRegister()) {
774 __ Lzcntl(i.OutputRegister(), i.InputRegister(0));
776 __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
780 ASSEMBLE_SSE_BINOP(ucomiss);
783 ASSEMBLE_SSE_BINOP(addss);
786 ASSEMBLE_SSE_BINOP(subss);
789 ASSEMBLE_SSE_BINOP(mulss);
792 ASSEMBLE_SSE_BINOP(divss);
793 // Don't delete this mov. It may improve performance on some CPUs,
794 // when there is a (v)mulss depending on the result.
795 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
797 case kSSEFloat32Abs: {
798 // TODO(bmeurer): Use RIP relative 128-bit constants.
799 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
800 __ psrlq(kScratchDoubleReg, 33);
801 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
804 case kSSEFloat32Neg: {
805 // TODO(bmeurer): Use RIP relative 128-bit constants.
806 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
807 __ psllq(kScratchDoubleReg, 31);
808 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
811 case kSSEFloat32Sqrt:
812 ASSEMBLE_SSE_UNOP(sqrtss);
815 ASSEMBLE_SSE_BINOP(maxss);
818 ASSEMBLE_SSE_BINOP(minss);
820 case kSSEFloat32ToFloat64:
821 ASSEMBLE_SSE_UNOP(cvtss2sd);
824 ASSEMBLE_SSE_BINOP(ucomisd);
827 ASSEMBLE_SSE_BINOP(addsd);
830 ASSEMBLE_SSE_BINOP(subsd);
833 ASSEMBLE_SSE_BINOP(mulsd);
836 ASSEMBLE_SSE_BINOP(divsd);
837 // Don't delete this mov. It may improve performance on some CPUs,
838 // when there is a (v)mulsd depending on the result.
839 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
841 case kSSEFloat64Mod: {
842 __ subq(rsp, Immediate(kDoubleSize));
843 // Move values to st(0) and st(1).
844 __ movsd(Operand(rsp, 0), i.InputDoubleRegister(1));
845 __ fld_d(Operand(rsp, 0));
846 __ movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
847 __ fld_d(Operand(rsp, 0));
848 // Loop while fprem isn't done.
851 // This instructions traps on all kinds inputs, but we are assuming the
852 // floating point control word is set to ignore them all.
854 // The following 2 instruction implicitly use rax.
856 if (CpuFeatures::IsSupported(SAHF)) {
857 CpuFeatureScope sahf_scope(masm(), SAHF);
860 __ shrl(rax, Immediate(8));
861 __ andl(rax, Immediate(0xFF));
865 __ j(parity_even, &mod_loop);
866 // Move output to stack and clean up.
868 __ fstp_d(Operand(rsp, 0));
869 __ movsd(i.OutputDoubleRegister(), Operand(rsp, 0));
870 __ addq(rsp, Immediate(kDoubleSize));
874 ASSEMBLE_SSE_BINOP(maxsd);
877 ASSEMBLE_SSE_BINOP(minsd);
879 case kSSEFloat64Abs: {
880 // TODO(bmeurer): Use RIP relative 128-bit constants.
881 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
882 __ psrlq(kScratchDoubleReg, 1);
883 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
886 case kSSEFloat64Neg: {
887 // TODO(bmeurer): Use RIP relative 128-bit constants.
888 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
889 __ psllq(kScratchDoubleReg, 63);
890 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
893 case kSSEFloat64Sqrt:
894 ASSEMBLE_SSE_UNOP(sqrtsd);
896 case kSSEFloat64Round: {
897 CpuFeatureScope sse_scope(masm(), SSE4_1);
898 RoundingMode const mode =
899 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
900 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
903 case kSSEFloat64ToFloat32:
904 ASSEMBLE_SSE_UNOP(cvtsd2ss);
906 case kSSEFloat64ToInt32:
907 if (instr->InputAt(0)->IsDoubleRegister()) {
908 __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
910 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
913 case kSSEFloat64ToUint32: {
914 if (instr->InputAt(0)->IsDoubleRegister()) {
915 __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
917 __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
919 __ AssertZeroExtended(i.OutputRegister());
922 case kSSEInt32ToFloat64:
923 if (instr->InputAt(0)->IsRegister()) {
924 __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
926 __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
929 case kSSEUint32ToFloat64:
930 if (instr->InputAt(0)->IsRegister()) {
931 __ movl(kScratchRegister, i.InputRegister(0));
933 __ movl(kScratchRegister, i.InputOperand(0));
935 __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
937 case kSSEFloat64ExtractLowWord32:
938 if (instr->InputAt(0)->IsDoubleStackSlot()) {
939 __ movl(i.OutputRegister(), i.InputOperand(0));
941 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
944 case kSSEFloat64ExtractHighWord32:
945 if (instr->InputAt(0)->IsDoubleStackSlot()) {
946 __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
948 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
951 case kSSEFloat64InsertLowWord32:
952 if (instr->InputAt(1)->IsRegister()) {
953 __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
955 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
958 case kSSEFloat64InsertHighWord32:
959 if (instr->InputAt(1)->IsRegister()) {
960 __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
962 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
965 case kSSEFloat64LoadLowWord32:
966 if (instr->InputAt(0)->IsRegister()) {
967 __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
969 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
972 case kAVXFloat32Cmp: {
973 CpuFeatureScope avx_scope(masm(), AVX);
974 if (instr->InputAt(1)->IsDoubleRegister()) {
975 __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
977 __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
982 ASSEMBLE_AVX_BINOP(vaddss);
985 ASSEMBLE_AVX_BINOP(vsubss);
988 ASSEMBLE_AVX_BINOP(vmulss);
991 ASSEMBLE_AVX_BINOP(vdivss);
992 // Don't delete this mov. It may improve performance on some CPUs,
993 // when there is a (v)mulss depending on the result.
994 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
997 ASSEMBLE_AVX_BINOP(vmaxss);
1000 ASSEMBLE_AVX_BINOP(vminss);
1002 case kAVXFloat64Cmp: {
1003 CpuFeatureScope avx_scope(masm(), AVX);
1004 if (instr->InputAt(1)->IsDoubleRegister()) {
1005 __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1007 __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
1011 case kAVXFloat64Add:
1012 ASSEMBLE_AVX_BINOP(vaddsd);
1014 case kAVXFloat64Sub:
1015 ASSEMBLE_AVX_BINOP(vsubsd);
1017 case kAVXFloat64Mul:
1018 ASSEMBLE_AVX_BINOP(vmulsd);
1020 case kAVXFloat64Div:
1021 ASSEMBLE_AVX_BINOP(vdivsd);
1022 // Don't delete this mov. It may improve performance on some CPUs,
1023 // when there is a (v)mulsd depending on the result.
1024 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1026 case kAVXFloat64Max:
1027 ASSEMBLE_AVX_BINOP(vmaxsd);
1029 case kAVXFloat64Min:
1030 ASSEMBLE_AVX_BINOP(vminsd);
1032 case kAVXFloat32Abs: {
1033 // TODO(bmeurer): Use RIP relative 128-bit constants.
1034 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1035 __ psrlq(kScratchDoubleReg, 33);
1036 CpuFeatureScope avx_scope(masm(), AVX);
1037 if (instr->InputAt(0)->IsDoubleRegister()) {
1038 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
1039 i.InputDoubleRegister(0));
1041 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
1046 case kAVXFloat32Neg: {
1047 // TODO(bmeurer): Use RIP relative 128-bit constants.
1048 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1049 __ psllq(kScratchDoubleReg, 31);
1050 CpuFeatureScope avx_scope(masm(), AVX);
1051 if (instr->InputAt(0)->IsDoubleRegister()) {
1052 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
1053 i.InputDoubleRegister(0));
1055 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
1060 case kAVXFloat64Abs: {
1061 // TODO(bmeurer): Use RIP relative 128-bit constants.
1062 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1063 __ psrlq(kScratchDoubleReg, 1);
1064 CpuFeatureScope avx_scope(masm(), AVX);
1065 if (instr->InputAt(0)->IsDoubleRegister()) {
1066 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1067 i.InputDoubleRegister(0));
1069 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1074 case kAVXFloat64Neg: {
1075 // TODO(bmeurer): Use RIP relative 128-bit constants.
1076 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1077 __ psllq(kScratchDoubleReg, 63);
1078 CpuFeatureScope avx_scope(masm(), AVX);
1079 if (instr->InputAt(0)->IsDoubleRegister()) {
1080 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1081 i.InputDoubleRegister(0));
1083 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
1089 ASSEMBLE_MOVX(movsxbl);
1090 __ AssertZeroExtended(i.OutputRegister());
1093 ASSEMBLE_MOVX(movzxbl);
1094 __ AssertZeroExtended(i.OutputRegister());
1098 Operand operand = i.MemoryOperand(&index);
1099 if (HasImmediateInput(instr, index)) {
1100 __ movb(operand, Immediate(i.InputInt8(index)));
1102 __ movb(operand, i.InputRegister(index));
1107 ASSEMBLE_MOVX(movsxwl);
1108 __ AssertZeroExtended(i.OutputRegister());
1111 ASSEMBLE_MOVX(movzxwl);
1112 __ AssertZeroExtended(i.OutputRegister());
1116 Operand operand = i.MemoryOperand(&index);
1117 if (HasImmediateInput(instr, index)) {
1118 __ movw(operand, Immediate(i.InputInt16(index)));
1120 __ movw(operand, i.InputRegister(index));
1125 if (instr->HasOutput()) {
1126 if (instr->addressing_mode() == kMode_None) {
1127 if (instr->InputAt(0)->IsRegister()) {
1128 __ movl(i.OutputRegister(), i.InputRegister(0));
1130 __ movl(i.OutputRegister(), i.InputOperand(0));
1133 __ movl(i.OutputRegister(), i.MemoryOperand());
1135 __ AssertZeroExtended(i.OutputRegister());
1138 Operand operand = i.MemoryOperand(&index);
1139 if (HasImmediateInput(instr, index)) {
1140 __ movl(operand, i.InputImmediate(index));
1142 __ movl(operand, i.InputRegister(index));
1147 ASSEMBLE_MOVX(movsxlq);
1150 if (instr->HasOutput()) {
1151 __ movq(i.OutputRegister(), i.MemoryOperand());
1154 Operand operand = i.MemoryOperand(&index);
1155 if (HasImmediateInput(instr, index)) {
1156 __ movq(operand, i.InputImmediate(index));
1158 __ movq(operand, i.InputRegister(index));
1163 if (instr->HasOutput()) {
1164 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
1167 Operand operand = i.MemoryOperand(&index);
1168 __ movss(operand, i.InputDoubleRegister(index));
1172 if (instr->HasOutput()) {
1173 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
1176 Operand operand = i.MemoryOperand(&index);
1177 __ movsd(operand, i.InputDoubleRegister(index));
1181 AddressingMode mode = AddressingModeField::decode(instr->opcode());
1182 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1183 // and addressing mode just happens to work out. The "addl"/"subl" forms
1184 // in these cases are faster based on measurements.
1185 if (i.InputRegister(0).is(i.OutputRegister())) {
1186 if (mode == kMode_MRI) {
1187 int32_t constant_summand = i.InputInt32(1);
1188 if (constant_summand > 0) {
1189 __ addl(i.OutputRegister(), Immediate(constant_summand));
1190 } else if (constant_summand < 0) {
1191 __ subl(i.OutputRegister(), Immediate(-constant_summand));
1193 } else if (mode == kMode_MR1) {
1194 if (i.InputRegister(1).is(i.OutputRegister())) {
1195 __ shll(i.OutputRegister(), Immediate(1));
1197 __ leal(i.OutputRegister(), i.MemoryOperand());
1199 } else if (mode == kMode_M2) {
1200 __ shll(i.OutputRegister(), Immediate(1));
1201 } else if (mode == kMode_M4) {
1202 __ shll(i.OutputRegister(), Immediate(2));
1203 } else if (mode == kMode_M8) {
1204 __ shll(i.OutputRegister(), Immediate(3));
1206 __ leal(i.OutputRegister(), i.MemoryOperand());
1209 __ leal(i.OutputRegister(), i.MemoryOperand());
1211 __ AssertZeroExtended(i.OutputRegister());
1215 __ leaq(i.OutputRegister(), i.MemoryOperand());
1218 __ decl(i.OutputRegister());
1221 __ incl(i.OutputRegister());
1224 if (HasImmediateInput(instr, 0)) {
1225 __ pushq(i.InputImmediate(0));
1227 if (instr->InputAt(0)->IsRegister()) {
1228 __ pushq(i.InputRegister(0));
1230 __ pushq(i.InputOperand(0));
1235 int const slot = MiscField::decode(instr->opcode());
1236 if (HasImmediateInput(instr, 0)) {
1237 __ movq(Operand(rsp, slot * kPointerSize), i.InputImmediate(0));
1239 __ movq(Operand(rsp, slot * kPointerSize), i.InputRegister(0));
1243 case kX64StoreWriteBarrier: {
1244 Register object = i.InputRegister(0);
1245 Register value = i.InputRegister(2);
1246 SaveFPRegsMode mode =
1247 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
1248 if (HasImmediateInput(instr, 1)) {
1249 int index = i.InputInt32(1);
1250 Register scratch = i.TempRegister(1);
1251 __ movq(Operand(object, index), value);
1252 __ RecordWriteContextSlot(object, index, value, scratch, mode);
1254 Register index = i.InputRegister(1);
1255 __ movq(Operand(object, index, times_1, 0), value);
1256 __ leaq(index, Operand(object, index, times_1, 0));
1257 __ RecordWrite(object, index, value, mode);
1261 case kCheckedLoadInt8:
1262 ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
1264 case kCheckedLoadUint8:
1265 ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
1267 case kCheckedLoadInt16:
1268 ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
1270 case kCheckedLoadUint16:
1271 ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
1273 case kCheckedLoadWord32:
1274 ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
1276 case kCheckedLoadFloat32:
1277 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
1279 case kCheckedLoadFloat64:
1280 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
1282 case kCheckedStoreWord8:
1283 ASSEMBLE_CHECKED_STORE_INTEGER(movb);
1285 case kCheckedStoreWord16:
1286 ASSEMBLE_CHECKED_STORE_INTEGER(movw);
1288 case kCheckedStoreWord32:
1289 ASSEMBLE_CHECKED_STORE_INTEGER(movl);
1291 case kCheckedStoreFloat32:
1292 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
1294 case kCheckedStoreFloat64:
1295 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
1297 case kX64StackCheck:
1298 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
1301 } // NOLINT(readability/fn_size)
1304 // Assembles branches after this instruction.
1305 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1306 X64OperandConverter i(this, instr);
1307 Label::Distance flabel_distance =
1308 branch->fallthru ? Label::kNear : Label::kFar;
1309 Label* tlabel = branch->true_label;
1310 Label* flabel = branch->false_label;
1311 switch (branch->condition) {
1312 case kUnorderedEqual:
1313 __ j(parity_even, flabel, flabel_distance);
1316 __ j(equal, tlabel);
1318 case kUnorderedNotEqual:
1319 __ j(parity_even, tlabel);
1322 __ j(not_equal, tlabel);
1324 case kSignedLessThan:
1327 case kSignedGreaterThanOrEqual:
1328 __ j(greater_equal, tlabel);
1330 case kSignedLessThanOrEqual:
1331 __ j(less_equal, tlabel);
1333 case kSignedGreaterThan:
1334 __ j(greater, tlabel);
1336 case kUnsignedLessThan:
1337 __ j(below, tlabel);
1339 case kUnsignedGreaterThanOrEqual:
1340 __ j(above_equal, tlabel);
1342 case kUnsignedLessThanOrEqual:
1343 __ j(below_equal, tlabel);
1345 case kUnsignedGreaterThan:
1346 __ j(above, tlabel);
1349 __ j(overflow, tlabel);
1352 __ j(no_overflow, tlabel);
1355 if (!branch->fallthru) __ jmp(flabel, flabel_distance);
1359 void CodeGenerator::AssembleArchJump(RpoNumber target) {
1360 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
1364 // Assembles boolean materializations after this instruction.
1365 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1366 FlagsCondition condition) {
1367 X64OperandConverter i(this, instr);
1370 // Materialize a full 64-bit 1 or 0 value. The result register is always the
1371 // last output of the instruction.
1373 DCHECK_NE(0u, instr->OutputCount());
1374 Register reg = i.OutputRegister(instr->OutputCount() - 1);
1375 Condition cc = no_condition;
1376 switch (condition) {
1377 case kUnorderedEqual:
1378 __ j(parity_odd, &check, Label::kNear);
1379 __ movl(reg, Immediate(0));
1380 __ jmp(&done, Label::kNear);
1385 case kUnorderedNotEqual:
1386 __ j(parity_odd, &check, Label::kNear);
1387 __ movl(reg, Immediate(1));
1388 __ jmp(&done, Label::kNear);
1393 case kSignedLessThan:
1396 case kSignedGreaterThanOrEqual:
1399 case kSignedLessThanOrEqual:
1402 case kSignedGreaterThan:
1405 case kUnsignedLessThan:
1408 case kUnsignedGreaterThanOrEqual:
1411 case kUnsignedLessThanOrEqual:
1414 case kUnsignedGreaterThan:
1426 __ movzxbl(reg, reg);
1431 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1432 X64OperandConverter i(this, instr);
1433 Register input = i.InputRegister(0);
1434 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1435 __ cmpl(input, Immediate(i.InputInt32(index + 0)));
1436 __ j(equal, GetLabel(i.InputRpo(index + 1)));
1438 AssembleArchJump(i.InputRpo(1));
1442 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1443 X64OperandConverter i(this, instr);
1444 Register input = i.InputRegister(0);
1445 int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
1446 Label** cases = zone()->NewArray<Label*>(case_count);
1447 for (int32_t index = 0; index < case_count; ++index) {
1448 cases[index] = GetLabel(i.InputRpo(index + 2));
1450 Label* const table = AddJumpTable(cases, case_count);
1451 __ cmpl(input, Immediate(case_count));
1452 __ j(above_equal, GetLabel(i.InputRpo(1)));
1453 __ leaq(kScratchRegister, Operand(table));
1454 __ jmp(Operand(kScratchRegister, input, times_8, 0));
1458 void CodeGenerator::AssembleDeoptimizerCall(
1459 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
1460 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
1461 isolate(), deoptimization_id, bailout_type);
1462 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1466 void CodeGenerator::AssemblePrologue() {
1467 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1468 int stack_slots = frame()->GetSpillSlotCount();
1469 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1472 const RegList saves = descriptor->CalleeSavedRegisters();
1473 if (saves != 0) { // Save callee-saved registers.
1474 int register_save_area_size = 0;
1475 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1476 if (!((1 << i) & saves)) continue;
1477 __ pushq(Register::from_code(i));
1478 register_save_area_size += kPointerSize;
1480 frame()->SetRegisterSaveAreaSize(register_save_area_size);
1482 } else if (descriptor->IsJSFunctionCall()) {
1483 CompilationInfo* info = this->info();
1484 __ Prologue(info->IsCodePreAgingActive());
1485 frame()->SetRegisterSaveAreaSize(
1486 StandardFrameConstants::kFixedFrameSizeFromFp);
1487 } else if (needs_frame_) {
1489 frame()->SetRegisterSaveAreaSize(
1490 StandardFrameConstants::kFixedFrameSizeFromFp);
1493 if (info()->is_osr()) {
1494 // TurboFan OSR-compiled functions cannot be entered directly.
1495 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1497 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1498 // frame is still on the stack. Optimized code uses OSR values directly from
1499 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1500 // remaining stack slots.
1501 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1502 osr_pc_offset_ = __ pc_offset();
1503 // TODO(titzer): cannot address target function == local #-1
1504 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1505 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
1506 stack_slots -= frame()->GetOsrStackSlotCount();
1509 if (stack_slots > 0) {
1510 __ subq(rsp, Immediate(stack_slots * kPointerSize));
1515 void CodeGenerator::AssembleReturn() {
1516 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1517 int stack_slots = frame()->GetSpillSlotCount();
1518 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1519 if (frame()->GetRegisterSaveAreaSize() > 0) {
1520 // Remove this frame's spill slots first.
1521 if (stack_slots > 0) {
1522 __ addq(rsp, Immediate(stack_slots * kPointerSize));
1524 const RegList saves = descriptor->CalleeSavedRegisters();
1525 // Restore registers.
1527 for (int i = 0; i < Register::kNumRegisters; i++) {
1528 if (!((1 << i) & saves)) continue;
1529 __ popq(Register::from_code(i));
1532 __ popq(rbp); // Pop caller's frame pointer.
1535 // No saved registers.
1536 __ movq(rsp, rbp); // Move stack pointer back to frame pointer.
1537 __ popq(rbp); // Pop caller's frame pointer.
1540 } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
1541 // Canonicalize JSFunction return sites for now.
1542 if (return_label_.is_bound()) {
1543 __ jmp(&return_label_);
1545 __ bind(&return_label_);
1546 __ movq(rsp, rbp); // Move stack pointer back to frame pointer.
1547 __ popq(rbp); // Pop caller's frame pointer.
1548 int pop_count = descriptor->IsJSFunctionCall()
1549 ? static_cast<int>(descriptor->JSParameterCount())
1551 __ Ret(pop_count * kPointerSize, rbx);
1559 void CodeGenerator::AssembleMove(InstructionOperand* source,
1560 InstructionOperand* destination) {
1561 X64OperandConverter g(this, NULL);
1562 // Dispatch on the source and destination operand kinds. Not all
1563 // combinations are possible.
1564 if (source->IsRegister()) {
1565 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1566 Register src = g.ToRegister(source);
1567 if (destination->IsRegister()) {
1568 __ movq(g.ToRegister(destination), src);
1570 __ movq(g.ToOperand(destination), src);
1572 } else if (source->IsStackSlot()) {
1573 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1574 Operand src = g.ToOperand(source);
1575 if (destination->IsRegister()) {
1576 Register dst = g.ToRegister(destination);
1579 // Spill on demand to use a temporary register for memory-to-memory
1581 Register tmp = kScratchRegister;
1582 Operand dst = g.ToOperand(destination);
1586 } else if (source->IsConstant()) {
1587 ConstantOperand* constant_source = ConstantOperand::cast(source);
1588 Constant src = g.ToConstant(constant_source);
1589 if (destination->IsRegister() || destination->IsStackSlot()) {
1590 Register dst = destination->IsRegister() ? g.ToRegister(destination)
1592 switch (src.type()) {
1593 case Constant::kInt32:
1594 // TODO(dcarney): don't need scratch in this case.
1595 __ Set(dst, src.ToInt32());
1597 case Constant::kInt64:
1598 __ Set(dst, src.ToInt64());
1600 case Constant::kFloat32:
1602 isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1604 case Constant::kFloat64:
1606 isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1608 case Constant::kExternalReference:
1609 __ Move(dst, src.ToExternalReference());
1611 case Constant::kHeapObject: {
1612 Handle<HeapObject> src_object = src.ToHeapObject();
1613 Heap::RootListIndex index;
1615 if (IsMaterializableFromFrame(src_object, &offset)) {
1616 __ movp(dst, Operand(rbp, offset));
1617 } else if (IsMaterializableFromRoot(src_object, &index)) {
1618 __ LoadRoot(dst, index);
1620 __ Move(dst, src_object);
1624 case Constant::kRpoNumber:
1625 UNREACHABLE(); // TODO(dcarney): load of labels on x64.
1628 if (destination->IsStackSlot()) {
1629 __ movq(g.ToOperand(destination), kScratchRegister);
1631 } else if (src.type() == Constant::kFloat32) {
1632 // TODO(turbofan): Can we do better here?
1633 uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
1634 if (destination->IsDoubleRegister()) {
1635 __ Move(g.ToDoubleRegister(destination), src_const);
1637 DCHECK(destination->IsDoubleStackSlot());
1638 Operand dst = g.ToOperand(destination);
1639 __ movl(dst, Immediate(src_const));
1642 DCHECK_EQ(Constant::kFloat64, src.type());
1643 uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
1644 if (destination->IsDoubleRegister()) {
1645 __ Move(g.ToDoubleRegister(destination), src_const);
1647 DCHECK(destination->IsDoubleStackSlot());
1648 __ movq(kScratchRegister, src_const);
1649 __ movq(g.ToOperand(destination), kScratchRegister);
1652 } else if (source->IsDoubleRegister()) {
1653 XMMRegister src = g.ToDoubleRegister(source);
1654 if (destination->IsDoubleRegister()) {
1655 XMMRegister dst = g.ToDoubleRegister(destination);
1656 __ movaps(dst, src);
1658 DCHECK(destination->IsDoubleStackSlot());
1659 Operand dst = g.ToOperand(destination);
1662 } else if (source->IsDoubleStackSlot()) {
1663 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1664 Operand src = g.ToOperand(source);
1665 if (destination->IsDoubleRegister()) {
1666 XMMRegister dst = g.ToDoubleRegister(destination);
1669 // We rely on having xmm0 available as a fixed scratch register.
1670 Operand dst = g.ToOperand(destination);
1671 __ movsd(xmm0, src);
1672 __ movsd(dst, xmm0);
1680 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1681 InstructionOperand* destination) {
1682 X64OperandConverter g(this, NULL);
1683 // Dispatch on the source and destination operand kinds. Not all
1684 // combinations are possible.
1685 if (source->IsRegister() && destination->IsRegister()) {
1686 // Register-register.
1687 __ xchgq(g.ToRegister(source), g.ToRegister(destination));
1688 } else if (source->IsRegister() && destination->IsStackSlot()) {
1689 Register src = g.ToRegister(source);
1690 Operand dst = g.ToOperand(destination);
1692 } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
1693 (source->IsDoubleStackSlot() &&
1694 destination->IsDoubleStackSlot())) {
1696 Register tmp = kScratchRegister;
1697 Operand src = g.ToOperand(source);
1698 Operand dst = g.ToOperand(destination);
1702 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
1703 // XMM register-register swap. We rely on having xmm0
1704 // available as a fixed scratch register.
1705 XMMRegister src = g.ToDoubleRegister(source);
1706 XMMRegister dst = g.ToDoubleRegister(destination);
1707 __ movaps(xmm0, src);
1708 __ movaps(src, dst);
1709 __ movaps(dst, xmm0);
1710 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
1711 // XMM register-memory swap. We rely on having xmm0
1712 // available as a fixed scratch register.
1713 XMMRegister src = g.ToDoubleRegister(source);
1714 Operand dst = g.ToOperand(destination);
1715 __ movsd(xmm0, src);
1717 __ movsd(dst, xmm0);
1719 // No other combinations are possible.
1725 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1726 for (size_t index = 0; index < target_count; ++index) {
1727 __ dq(targets[index]);
1732 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
1735 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1736 int space_needed = Deoptimizer::patch_size();
1737 if (!info()->IsStub()) {
1738 // Ensure that we have enough space after the previous lazy-bailout
1739 // instruction for patching the code here.
1740 int current_pc = masm()->pc_offset();
1741 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1742 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1743 __ Nop(padding_size);
1750 } // namespace internal
1751 } // namespace compiler