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/ia32/assembler-ia32.h"
11 #include "src/ia32/macro-assembler-ia32.h"
12 #include "src/scopes.h"
21 // Adds IA-32 specific methods for decoding operands.
22 class IA32OperandConverter : public InstructionOperandConverter {
24 IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
25 : InstructionOperandConverter(gen, instr) {}
27 Operand InputOperand(size_t index, int extra = 0) {
28 return ToOperand(instr_->InputAt(index), extra);
31 Immediate InputImmediate(size_t index) {
32 return ToImmediate(instr_->InputAt(index));
35 Operand OutputOperand() { return ToOperand(instr_->Output()); }
37 Operand ToOperand(InstructionOperand* op, int extra = 0) {
38 if (op->IsRegister()) {
40 return Operand(ToRegister(op));
41 } else if (op->IsDoubleRegister()) {
43 return Operand(ToDoubleRegister(op));
45 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
46 // The linkage computes where all spill slots are located.
47 FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
48 return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
51 Operand HighOperand(InstructionOperand* op) {
52 DCHECK(op->IsDoubleStackSlot());
53 return ToOperand(op, kPointerSize);
56 Immediate ToImmediate(InstructionOperand* operand) {
57 Constant constant = ToConstant(operand);
58 switch (constant.type()) {
59 case Constant::kInt32:
60 return Immediate(constant.ToInt32());
61 case Constant::kFloat32:
63 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
64 case Constant::kFloat64:
66 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
67 case Constant::kExternalReference:
68 return Immediate(constant.ToExternalReference());
69 case Constant::kHeapObject:
70 return Immediate(constant.ToHeapObject());
71 case Constant::kInt64:
73 case Constant::kRpoNumber:
74 return Immediate::CodeRelativeOffset(ToLabel(operand));
80 static size_t NextOffset(size_t* offset) {
86 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
87 STATIC_ASSERT(0 == static_cast<int>(times_1));
88 STATIC_ASSERT(1 == static_cast<int>(times_2));
89 STATIC_ASSERT(2 == static_cast<int>(times_4));
90 STATIC_ASSERT(3 == static_cast<int>(times_8));
91 int scale = static_cast<int>(mode - one);
92 DCHECK(scale >= 0 && scale < 4);
93 return static_cast<ScaleFactor>(scale);
96 Operand MemoryOperand(size_t* offset) {
97 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
100 Register base = InputRegister(NextOffset(offset));
102 return Operand(base, disp);
105 Register base = InputRegister(NextOffset(offset));
106 int32_t disp = InputInt32(NextOffset(offset));
107 return Operand(base, disp);
113 Register base = InputRegister(NextOffset(offset));
114 Register index = InputRegister(NextOffset(offset));
115 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
117 return Operand(base, index, scale, disp);
123 Register base = InputRegister(NextOffset(offset));
124 Register index = InputRegister(NextOffset(offset));
125 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
126 int32_t disp = InputInt32(NextOffset(offset));
127 return Operand(base, index, scale, disp);
133 Register index = InputRegister(NextOffset(offset));
134 ScaleFactor scale = ScaleFor(kMode_M1, mode);
136 return Operand(index, scale, disp);
142 Register index = InputRegister(NextOffset(offset));
143 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
144 int32_t disp = InputInt32(NextOffset(offset));
145 return Operand(index, scale, disp);
148 int32_t disp = InputInt32(NextOffset(offset));
149 return Operand(Immediate(disp));
153 return Operand(no_reg, 0);
156 return Operand(no_reg, 0);
159 Operand MemoryOperand(size_t first_input = 0) {
160 return MemoryOperand(&first_input);
167 bool HasImmediateInput(Instruction* instr, size_t index) {
168 return instr->InputAt(index)->IsImmediate();
172 class OutOfLineLoadInteger FINAL : public OutOfLineCode {
174 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
175 : OutOfLineCode(gen), result_(result) {}
177 void Generate() FINAL { __ xor_(result_, result_); }
180 Register const result_;
184 class OutOfLineLoadFloat FINAL : public OutOfLineCode {
186 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
187 : OutOfLineCode(gen), result_(result) {}
189 void Generate() FINAL { __ pcmpeqd(result_, result_); }
192 XMMRegister const result_;
196 class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
198 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
200 : OutOfLineCode(gen), result_(result), input_(input) {}
202 void Generate() FINAL {
203 __ sub(esp, Immediate(kDoubleSize));
204 __ movsd(MemOperand(esp, 0), input_);
205 __ SlowTruncateToI(result_, esp, 0);
206 __ add(esp, Immediate(kDoubleSize));
210 Register const result_;
211 XMMRegister const input_;
217 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
219 auto result = i.OutputDoubleRegister(); \
220 auto offset = i.InputRegister(0); \
221 if (instr->InputAt(1)->IsRegister()) { \
222 __ cmp(offset, i.InputRegister(1)); \
224 __ cmp(offset, i.InputImmediate(1)); \
226 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
227 __ j(above_equal, ool->entry()); \
228 __ asm_instr(result, i.MemoryOperand(2)); \
229 __ bind(ool->exit()); \
233 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
235 auto result = i.OutputRegister(); \
236 auto offset = i.InputRegister(0); \
237 if (instr->InputAt(1)->IsRegister()) { \
238 __ cmp(offset, i.InputRegister(1)); \
240 __ cmp(offset, i.InputImmediate(1)); \
242 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
243 __ j(above_equal, ool->entry()); \
244 __ asm_instr(result, i.MemoryOperand(2)); \
245 __ bind(ool->exit()); \
249 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
251 auto offset = i.InputRegister(0); \
252 if (instr->InputAt(1)->IsRegister()) { \
253 __ cmp(offset, i.InputRegister(1)); \
255 __ cmp(offset, i.InputImmediate(1)); \
258 __ j(above_equal, &done, Label::kNear); \
259 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
264 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
266 auto offset = i.InputRegister(0); \
267 if (instr->InputAt(1)->IsRegister()) { \
268 __ cmp(offset, i.InputRegister(1)); \
270 __ cmp(offset, i.InputImmediate(1)); \
273 __ j(above_equal, &done, Label::kNear); \
274 if (instr->InputAt(2)->IsRegister()) { \
275 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
277 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
283 // Assembles an instruction after register allocation, producing machine code.
284 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
285 IA32OperandConverter i(this, instr);
287 switch (ArchOpcodeField::decode(instr->opcode())) {
288 case kArchCallCodeObject: {
289 EnsureSpaceForLazyDeopt();
290 if (HasImmediateInput(instr, 0)) {
291 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
292 __ call(code, RelocInfo::CODE_TARGET);
294 Register reg = i.InputRegister(0);
295 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
297 RecordCallPosition(instr);
300 case kArchCallJSFunction: {
301 EnsureSpaceForLazyDeopt();
302 Register func = i.InputRegister(0);
303 if (FLAG_debug_code) {
304 // Check the function's context matches the context argument.
305 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
306 __ Assert(equal, kWrongFunctionContext);
308 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
309 RecordCallPosition(instr);
313 AssembleArchJump(i.InputRpo(0));
315 case kArchLookupSwitch:
316 AssembleArchLookupSwitch(instr);
318 case kArchTableSwitch:
319 AssembleArchTableSwitch(instr);
322 // don't emit code for nops.
324 case kArchDeoptimize: {
326 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
327 AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
333 case kArchStackPointer:
334 __ mov(i.OutputRegister(), esp);
336 case kArchTruncateDoubleToI: {
337 auto result = i.OutputRegister();
338 auto input = i.InputDoubleRegister(0);
339 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
340 __ cvttsd2si(result, Operand(input));
342 __ j(overflow, ool->entry());
343 __ bind(ool->exit());
347 if (HasImmediateInput(instr, 1)) {
348 __ add(i.InputOperand(0), i.InputImmediate(1));
350 __ add(i.InputRegister(0), i.InputOperand(1));
354 if (HasImmediateInput(instr, 1)) {
355 __ and_(i.InputOperand(0), i.InputImmediate(1));
357 __ and_(i.InputRegister(0), i.InputOperand(1));
361 if (HasImmediateInput(instr, 1)) {
362 __ cmp(i.InputOperand(0), i.InputImmediate(1));
364 __ cmp(i.InputRegister(0), i.InputOperand(1));
368 if (HasImmediateInput(instr, 1)) {
369 __ test(i.InputOperand(0), i.InputImmediate(1));
371 __ test(i.InputRegister(0), i.InputOperand(1));
375 if (HasImmediateInput(instr, 1)) {
376 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
378 __ imul(i.OutputRegister(), i.InputOperand(1));
382 __ imul(i.InputRegister(1));
385 __ mul(i.InputRegister(1));
389 __ idiv(i.InputOperand(1));
392 __ Move(edx, Immediate(0));
393 __ div(i.InputOperand(1));
396 __ not_(i.OutputOperand());
399 __ neg(i.OutputOperand());
402 if (HasImmediateInput(instr, 1)) {
403 __ or_(i.InputOperand(0), i.InputImmediate(1));
405 __ or_(i.InputRegister(0), i.InputOperand(1));
409 if (HasImmediateInput(instr, 1)) {
410 __ xor_(i.InputOperand(0), i.InputImmediate(1));
412 __ xor_(i.InputRegister(0), i.InputOperand(1));
416 if (HasImmediateInput(instr, 1)) {
417 __ sub(i.InputOperand(0), i.InputImmediate(1));
419 __ sub(i.InputRegister(0), i.InputOperand(1));
423 if (HasImmediateInput(instr, 1)) {
424 __ shl(i.OutputOperand(), i.InputInt5(1));
426 __ shl_cl(i.OutputOperand());
430 if (HasImmediateInput(instr, 1)) {
431 __ shr(i.OutputOperand(), i.InputInt5(1));
433 __ shr_cl(i.OutputOperand());
437 if (HasImmediateInput(instr, 1)) {
438 __ sar(i.OutputOperand(), i.InputInt5(1));
440 __ sar_cl(i.OutputOperand());
444 if (HasImmediateInput(instr, 1)) {
445 __ ror(i.OutputOperand(), i.InputInt5(1));
447 __ ror_cl(i.OutputOperand());
451 __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
454 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
457 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
460 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
463 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
466 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
469 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
472 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
474 case kSSEFloat64Mod: {
475 // TODO(dcarney): alignment is wrong.
476 __ sub(esp, Immediate(kDoubleSize));
477 // Move values to st(0) and st(1).
478 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
479 __ fld_d(Operand(esp, 0));
480 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
481 __ fld_d(Operand(esp, 0));
482 // Loop while fprem isn't done.
485 // This instructions traps on all kinds inputs, but we are assuming the
486 // floating point control word is set to ignore them all.
488 // The following 2 instruction implicitly use eax.
491 __ j(parity_even, &mod_loop);
492 // Move output to stack and clean up.
494 __ fstp_d(Operand(esp, 0));
495 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
496 __ add(esp, Immediate(kDoubleSize));
499 case kSSEFloat64Sqrt:
500 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
502 case kSSEFloat64Round: {
503 CpuFeatureScope sse_scope(masm(), SSE4_1);
504 RoundingMode const mode =
505 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
506 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
510 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
513 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
515 case kSSEFloat64ToInt32:
516 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
518 case kSSEFloat64ToUint32: {
519 XMMRegister scratch = xmm0;
520 __ Move(scratch, -2147483648.0);
521 __ addsd(scratch, i.InputOperand(0));
522 __ cvttsd2si(i.OutputRegister(), scratch);
523 __ add(i.OutputRegister(), Immediate(0x80000000));
526 case kSSEInt32ToFloat64:
527 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
529 case kSSEUint32ToFloat64:
530 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
532 case kSSEFloat64ExtractLowWord32:
533 if (instr->InputAt(0)->IsDoubleStackSlot()) {
534 __ mov(i.OutputRegister(), i.InputOperand(0));
536 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
539 case kSSEFloat64ExtractHighWord32:
540 if (instr->InputAt(0)->IsDoubleStackSlot()) {
541 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
543 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
546 case kSSEFloat64InsertLowWord32:
547 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
549 case kSSEFloat64InsertHighWord32:
550 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
552 case kSSEFloat64LoadLowWord32:
553 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
555 case kAVXFloat64Add: {
556 CpuFeatureScope avx_scope(masm(), AVX);
557 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
561 case kAVXFloat64Sub: {
562 CpuFeatureScope avx_scope(masm(), AVX);
563 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
567 case kAVXFloat64Mul: {
568 CpuFeatureScope avx_scope(masm(), AVX);
569 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
573 case kAVXFloat64Div: {
574 CpuFeatureScope avx_scope(masm(), AVX);
575 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
579 case kAVXFloat64Max: {
580 CpuFeatureScope avx_scope(masm(), AVX);
581 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
585 case kAVXFloat64Min: {
586 CpuFeatureScope avx_scope(masm(), AVX);
587 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
592 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
595 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
599 Operand operand = i.MemoryOperand(&index);
600 if (HasImmediateInput(instr, index)) {
601 __ mov_b(operand, i.InputInt8(index));
603 __ mov_b(operand, i.InputRegister(index));
608 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
611 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
615 Operand operand = i.MemoryOperand(&index);
616 if (HasImmediateInput(instr, index)) {
617 __ mov_w(operand, i.InputInt16(index));
619 __ mov_w(operand, i.InputRegister(index));
624 if (instr->HasOutput()) {
625 __ mov(i.OutputRegister(), i.MemoryOperand());
628 Operand operand = i.MemoryOperand(&index);
629 if (HasImmediateInput(instr, index)) {
630 __ mov(operand, i.InputImmediate(index));
632 __ mov(operand, i.InputRegister(index));
637 if (instr->HasOutput()) {
638 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
641 Operand operand = i.MemoryOperand(&index);
642 __ movsd(operand, i.InputDoubleRegister(index));
646 if (instr->HasOutput()) {
647 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
650 Operand operand = i.MemoryOperand(&index);
651 __ movss(operand, i.InputDoubleRegister(index));
655 AddressingMode mode = AddressingModeField::decode(instr->opcode());
656 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
657 // and addressing mode just happens to work out. The "addl"/"subl" forms
658 // in these cases are faster based on measurements.
659 if (mode == kMode_MI) {
660 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
661 } else if (i.InputRegister(0).is(i.OutputRegister())) {
662 if (mode == kMode_MRI) {
663 int32_t constant_summand = i.InputInt32(1);
664 if (constant_summand > 0) {
665 __ add(i.OutputRegister(), Immediate(constant_summand));
666 } else if (constant_summand < 0) {
667 __ sub(i.OutputRegister(), Immediate(-constant_summand));
669 } else if (mode == kMode_MR1) {
670 if (i.InputRegister(1).is(i.OutputRegister())) {
671 __ shl(i.OutputRegister(), 1);
673 __ lea(i.OutputRegister(), i.MemoryOperand());
675 } else if (mode == kMode_M2) {
676 __ shl(i.OutputRegister(), 1);
677 } else if (mode == kMode_M4) {
678 __ shl(i.OutputRegister(), 2);
679 } else if (mode == kMode_M8) {
680 __ shl(i.OutputRegister(), 3);
682 __ lea(i.OutputRegister(), i.MemoryOperand());
685 __ lea(i.OutputRegister(), i.MemoryOperand());
690 if (HasImmediateInput(instr, 0)) {
691 __ push(i.InputImmediate(0));
693 __ push(i.InputOperand(0));
696 case kIA32StoreWriteBarrier: {
697 Register object = i.InputRegister(0);
698 Register index = i.InputRegister(1);
699 Register value = i.InputRegister(2);
700 __ mov(Operand(object, index, times_1, 0), value);
701 __ lea(index, Operand(object, index, times_1, 0));
702 SaveFPRegsMode mode =
703 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
704 __ RecordWrite(object, index, value, mode);
707 case kCheckedLoadInt8:
708 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
710 case kCheckedLoadUint8:
711 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
713 case kCheckedLoadInt16:
714 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
716 case kCheckedLoadUint16:
717 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
719 case kCheckedLoadWord32:
720 ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
722 case kCheckedLoadFloat32:
723 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
725 case kCheckedLoadFloat64:
726 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
728 case kCheckedStoreWord8:
729 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
731 case kCheckedStoreWord16:
732 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
734 case kCheckedStoreWord32:
735 ASSEMBLE_CHECKED_STORE_INTEGER(mov);
737 case kCheckedStoreFloat32:
738 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
740 case kCheckedStoreFloat64:
741 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
743 case kIA32StackCheck: {
744 ExternalReference const stack_limit =
745 ExternalReference::address_of_stack_limit(isolate());
746 __ cmp(esp, Operand::StaticVariable(stack_limit));
753 // Assembles a branch after an instruction.
754 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
755 IA32OperandConverter i(this, instr);
756 Label::Distance flabel_distance =
757 branch->fallthru ? Label::kNear : Label::kFar;
758 Label* tlabel = branch->true_label;
759 Label* flabel = branch->false_label;
760 switch (branch->condition) {
761 case kUnorderedEqual:
762 __ j(parity_even, flabel, flabel_distance);
767 case kUnorderedNotEqual:
768 __ j(parity_even, tlabel);
771 __ j(not_equal, tlabel);
773 case kSignedLessThan:
776 case kSignedGreaterThanOrEqual:
777 __ j(greater_equal, tlabel);
779 case kSignedLessThanOrEqual:
780 __ j(less_equal, tlabel);
782 case kSignedGreaterThan:
783 __ j(greater, tlabel);
785 case kUnsignedLessThan:
788 case kUnsignedGreaterThanOrEqual:
789 __ j(above_equal, tlabel);
791 case kUnsignedLessThanOrEqual:
792 __ j(below_equal, tlabel);
794 case kUnsignedGreaterThan:
798 __ j(overflow, tlabel);
801 __ j(no_overflow, tlabel);
804 // Add a jump if not falling through to the next block.
805 if (!branch->fallthru) __ jmp(flabel);
809 void CodeGenerator::AssembleArchJump(RpoNumber target) {
810 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
814 // Assembles boolean materializations after an instruction.
815 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
816 FlagsCondition condition) {
817 IA32OperandConverter i(this, instr);
820 // Materialize a full 32-bit 1 or 0 value. The result register is always the
821 // last output of the instruction.
823 DCHECK_NE(0u, instr->OutputCount());
824 Register reg = i.OutputRegister(instr->OutputCount() - 1);
825 Condition cc = no_condition;
827 case kUnorderedEqual:
828 __ j(parity_odd, &check, Label::kNear);
829 __ Move(reg, Immediate(0));
830 __ jmp(&done, Label::kNear);
835 case kUnorderedNotEqual:
836 __ j(parity_odd, &check, Label::kNear);
837 __ mov(reg, Immediate(1));
838 __ jmp(&done, Label::kNear);
843 case kSignedLessThan:
846 case kSignedGreaterThanOrEqual:
849 case kSignedLessThanOrEqual:
852 case kSignedGreaterThan:
855 case kUnsignedLessThan:
858 case kUnsignedGreaterThanOrEqual:
861 case kUnsignedLessThanOrEqual:
864 case kUnsignedGreaterThan:
875 if (reg.is_byte_register()) {
876 // setcc for byte registers (al, bl, cl, dl).
878 __ movzx_b(reg, reg);
880 // Emit a branch to set a register to either 1 or 0.
882 __ j(cc, &set, Label::kNear);
883 __ Move(reg, Immediate(0));
884 __ jmp(&done, Label::kNear);
886 __ mov(reg, Immediate(1));
892 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
893 IA32OperandConverter i(this, instr);
894 Register input = i.InputRegister(0);
895 for (size_t index = 2; index < instr->InputCount(); index += 2) {
896 __ cmp(input, Immediate(i.InputInt32(index + 0)));
897 __ j(equal, GetLabel(i.InputRpo(index + 1)));
899 AssembleArchJump(i.InputRpo(1));
903 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
904 IA32OperandConverter i(this, instr);
905 Register input = i.InputRegister(0);
906 size_t const case_count = instr->InputCount() - 2;
907 Label** cases = zone()->NewArray<Label*>(case_count);
908 for (size_t index = 0; index < case_count; ++index) {
909 cases[index] = GetLabel(i.InputRpo(index + 2));
911 Label* const table = AddJumpTable(cases, case_count);
912 __ cmp(input, Immediate(case_count));
913 __ j(above_equal, GetLabel(i.InputRpo(1)));
914 __ jmp(Operand::JumpTable(input, times_4, table));
918 void CodeGenerator::AssembleDeoptimizerCall(
919 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
920 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
921 isolate(), deoptimization_id, bailout_type);
922 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
926 // The calling convention for JSFunctions on IA32 passes arguments on the
927 // stack and the JSFunction and context in EDI and ESI, respectively, thus
928 // the steps of the call look as follows:
930 // --{ before the call instruction }--------------------------------------------
934 // --{ push arguments and setup ESI, EDI }--------------------------------------
935 // | args + receiver | caller frame |
937 // [edi = JSFunction, esi = context]
939 // --{ call [edi + kCodeEntryOffset] }------------------------------------------
940 // | RET | args + receiver | caller frame |
943 // =={ prologue of called function }============================================
944 // --{ push ebp }---------------------------------------------------------------
945 // | FP | RET | args + receiver | caller frame |
948 // --{ mov ebp, esp }-----------------------------------------------------------
949 // | FP | RET | args + receiver | caller frame |
952 // --{ push esi }---------------------------------------------------------------
953 // | CTX | FP | RET | args + receiver | caller frame |
956 // --{ push edi }---------------------------------------------------------------
957 // | FNC | CTX | FP | RET | args + receiver | caller frame |
960 // --{ subi esp, #N }-----------------------------------------------------------
961 // | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
964 // =={ body of called function }================================================
966 // =={ epilogue of called function }============================================
967 // --{ mov esp, ebp }-----------------------------------------------------------
968 // | FP | RET | args + receiver | caller frame |
971 // --{ pop ebp }-----------------------------------------------------------
972 // | | RET | args + receiver | caller frame |
975 // --{ ret #A+1 }-----------------------------------------------------------
976 // | | caller frame |
980 // Runtime function calls are accomplished by doing a stub call to the
981 // CEntryStub (a real code object). On IA32 passes arguments on the
982 // stack, the number of arguments in EAX, the address of the runtime function
983 // in EBX, and the context in ESI.
985 // --{ before the call instruction }--------------------------------------------
989 // --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
990 // | args + receiver | caller frame |
992 // [eax = #args, ebx = runtime function, esi = context]
994 // --{ call #CEntryStub }-------------------------------------------------------
995 // | RET | args + receiver | caller frame |
998 // =={ body of runtime function }===============================================
1000 // --{ runtime returns }--------------------------------------------------------
1004 // Other custom linkages (e.g. for calling directly into and out of C++) may
1005 // need to save callee-saved registers on the stack, which is done in the
1006 // function prologue of generated code.
1008 // --{ before the call instruction }--------------------------------------------
1012 // --{ set up arguments in registers on stack }---------------------------------
1013 // | args | caller frame |
1015 // [r0 = arg0, r1 = arg1, ...]
1017 // --{ call code }--------------------------------------------------------------
1018 // | RET | args | caller frame |
1021 // =={ prologue of called function }============================================
1022 // --{ push ebp }---------------------------------------------------------------
1023 // | FP | RET | args | caller frame |
1026 // --{ mov ebp, esp }-----------------------------------------------------------
1027 // | FP | RET | args | caller frame |
1030 // --{ save registers }---------------------------------------------------------
1031 // | regs | FP | RET | args | caller frame |
1034 // --{ subi esp, #N }-----------------------------------------------------------
1035 // | callee frame | regs | FP | RET | args | caller frame |
1038 // =={ body of called function }================================================
1040 // =={ epilogue of called function }============================================
1041 // --{ restore registers }------------------------------------------------------
1042 // | regs | FP | RET | args | caller frame |
1045 // --{ mov esp, ebp }-----------------------------------------------------------
1046 // | FP | RET | args | caller frame |
1049 // --{ pop ebp }----------------------------------------------------------------
1050 // | RET | args | caller frame |
1054 void CodeGenerator::AssemblePrologue() {
1055 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1056 int stack_slots = frame()->GetSpillSlotCount();
1057 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1058 // Assemble a prologue similar the to cdecl calling convention.
1061 const RegList saves = descriptor->CalleeSavedRegisters();
1062 if (saves != 0) { // Save callee-saved registers.
1063 int register_save_area_size = 0;
1064 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1065 if (!((1 << i) & saves)) continue;
1066 __ push(Register::from_code(i));
1067 register_save_area_size += kPointerSize;
1069 frame()->SetRegisterSaveAreaSize(register_save_area_size);
1071 } else if (descriptor->IsJSFunctionCall()) {
1072 // TODO(turbofan): this prologue is redundant with OSR, but needed for
1074 CompilationInfo* info = this->info();
1075 __ Prologue(info->IsCodePreAgingActive());
1076 frame()->SetRegisterSaveAreaSize(
1077 StandardFrameConstants::kFixedFrameSizeFromFp);
1078 } else if (stack_slots > 0) {
1080 frame()->SetRegisterSaveAreaSize(
1081 StandardFrameConstants::kFixedFrameSizeFromFp);
1084 if (info()->is_osr()) {
1085 // TurboFan OSR-compiled functions cannot be entered directly.
1086 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1088 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1089 // frame is still on the stack. Optimized code uses OSR values directly from
1090 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1091 // remaining stack slots.
1092 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1093 osr_pc_offset_ = __ pc_offset();
1094 // TODO(titzer): cannot address target function == local #-1
1095 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1096 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
1097 stack_slots -= frame()->GetOsrStackSlotCount();
1100 if (stack_slots > 0) {
1101 // Allocate the stack slots used by this frame.
1102 __ sub(esp, Immediate(stack_slots * kPointerSize));
1107 void CodeGenerator::AssembleReturn() {
1108 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1109 int stack_slots = frame()->GetSpillSlotCount();
1110 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1111 const RegList saves = descriptor->CalleeSavedRegisters();
1112 if (frame()->GetRegisterSaveAreaSize() > 0) {
1113 // Remove this frame's spill slots first.
1114 if (stack_slots > 0) {
1115 __ add(esp, Immediate(stack_slots * kPointerSize));
1117 // Restore registers.
1119 for (int i = 0; i < Register::kNumRegisters; i++) {
1120 if (!((1 << i) & saves)) continue;
1121 __ pop(Register::from_code(i));
1124 __ pop(ebp); // Pop caller's frame pointer.
1127 // No saved registers.
1128 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1129 __ pop(ebp); // Pop caller's frame pointer.
1132 } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
1133 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1134 __ pop(ebp); // Pop caller's frame pointer.
1135 int pop_count = descriptor->IsJSFunctionCall()
1136 ? static_cast<int>(descriptor->JSParameterCount())
1138 __ ret(pop_count * kPointerSize);
1145 void CodeGenerator::AssembleMove(InstructionOperand* source,
1146 InstructionOperand* destination) {
1147 IA32OperandConverter g(this, NULL);
1148 // Dispatch on the source and destination operand kinds. Not all
1149 // combinations are possible.
1150 if (source->IsRegister()) {
1151 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1152 Register src = g.ToRegister(source);
1153 Operand dst = g.ToOperand(destination);
1155 } else if (source->IsStackSlot()) {
1156 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1157 Operand src = g.ToOperand(source);
1158 if (destination->IsRegister()) {
1159 Register dst = g.ToRegister(destination);
1162 Operand dst = g.ToOperand(destination);
1166 } else if (source->IsConstant()) {
1167 Constant src_constant = g.ToConstant(source);
1168 if (src_constant.type() == Constant::kHeapObject) {
1169 Handle<HeapObject> src = src_constant.ToHeapObject();
1170 if (info()->IsOptimizing() && src.is_identical_to(info()->context())) {
1171 // Loading the context from the frame is way cheaper than materializing
1172 // the actual context heap object address.
1173 if (destination->IsRegister()) {
1174 Register dst = g.ToRegister(destination);
1175 __ mov(dst, Operand(ebp, StandardFrameConstants::kContextOffset));
1177 DCHECK(destination->IsStackSlot());
1178 Operand dst = g.ToOperand(destination);
1179 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
1182 } else if (destination->IsRegister()) {
1183 Register dst = g.ToRegister(destination);
1184 __ LoadHeapObject(dst, src);
1186 DCHECK(destination->IsStackSlot());
1187 Operand dst = g.ToOperand(destination);
1188 AllowDeferredHandleDereference embedding_raw_address;
1189 if (isolate()->heap()->InNewSpace(*src)) {
1190 __ PushHeapObject(src);
1196 } else if (destination->IsRegister()) {
1197 Register dst = g.ToRegister(destination);
1198 __ Move(dst, g.ToImmediate(source));
1199 } else if (destination->IsStackSlot()) {
1200 Operand dst = g.ToOperand(destination);
1201 __ Move(dst, g.ToImmediate(source));
1202 } else if (src_constant.type() == Constant::kFloat32) {
1203 // TODO(turbofan): Can we do better here?
1204 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
1205 if (destination->IsDoubleRegister()) {
1206 XMMRegister dst = g.ToDoubleRegister(destination);
1209 DCHECK(destination->IsDoubleStackSlot());
1210 Operand dst = g.ToOperand(destination);
1211 __ Move(dst, Immediate(src));
1214 DCHECK_EQ(Constant::kFloat64, src_constant.type());
1215 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1216 uint32_t lower = static_cast<uint32_t>(src);
1217 uint32_t upper = static_cast<uint32_t>(src >> 32);
1218 if (destination->IsDoubleRegister()) {
1219 XMMRegister dst = g.ToDoubleRegister(destination);
1222 DCHECK(destination->IsDoubleStackSlot());
1223 Operand dst0 = g.ToOperand(destination);
1224 Operand dst1 = g.HighOperand(destination);
1225 __ Move(dst0, Immediate(lower));
1226 __ Move(dst1, Immediate(upper));
1229 } else if (source->IsDoubleRegister()) {
1230 XMMRegister src = g.ToDoubleRegister(source);
1231 if (destination->IsDoubleRegister()) {
1232 XMMRegister dst = g.ToDoubleRegister(destination);
1233 __ movaps(dst, src);
1235 DCHECK(destination->IsDoubleStackSlot());
1236 Operand dst = g.ToOperand(destination);
1239 } else if (source->IsDoubleStackSlot()) {
1240 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1241 Operand src = g.ToOperand(source);
1242 if (destination->IsDoubleRegister()) {
1243 XMMRegister dst = g.ToDoubleRegister(destination);
1246 // We rely on having xmm0 available as a fixed scratch register.
1247 Operand dst = g.ToOperand(destination);
1248 __ movsd(xmm0, src);
1249 __ movsd(dst, xmm0);
1257 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1258 InstructionOperand* destination) {
1259 IA32OperandConverter g(this, NULL);
1260 // Dispatch on the source and destination operand kinds. Not all
1261 // combinations are possible.
1262 if (source->IsRegister() && destination->IsRegister()) {
1263 // Register-register.
1264 Register src = g.ToRegister(source);
1265 Register dst = g.ToRegister(destination);
1267 } else if (source->IsRegister() && destination->IsStackSlot()) {
1269 __ xchg(g.ToRegister(source), g.ToOperand(destination));
1270 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
1272 Operand src = g.ToOperand(source);
1273 Operand dst = g.ToOperand(destination);
1278 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
1279 // XMM register-register swap. We rely on having xmm0
1280 // available as a fixed scratch register.
1281 XMMRegister src = g.ToDoubleRegister(source);
1282 XMMRegister dst = g.ToDoubleRegister(destination);
1283 __ movaps(xmm0, src);
1284 __ movaps(src, dst);
1285 __ movaps(dst, xmm0);
1286 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
1287 // XMM register-memory swap. We rely on having xmm0
1288 // available as a fixed scratch register.
1289 XMMRegister reg = g.ToDoubleRegister(source);
1290 Operand other = g.ToOperand(destination);
1291 __ movsd(xmm0, other);
1292 __ movsd(other, reg);
1293 __ movaps(reg, xmm0);
1294 } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
1295 // Double-width memory-to-memory.
1296 Operand src0 = g.ToOperand(source);
1297 Operand src1 = g.HighOperand(source);
1298 Operand dst0 = g.ToOperand(destination);
1299 Operand dst1 = g.HighOperand(destination);
1300 __ movsd(xmm0, dst0); // Save destination in xmm0.
1301 __ push(src0); // Then use stack to copy source to destination.
1305 __ movsd(src0, xmm0);
1307 // No other combinations are possible.
1313 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1314 for (size_t index = 0; index < target_count; ++index) {
1315 __ dd(targets[index]);
1320 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
1323 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1324 int space_needed = Deoptimizer::patch_size();
1325 if (!info()->IsStub()) {
1326 // Ensure that we have enough space after the previous lazy-bailout
1327 // instruction for patching the code here.
1328 int current_pc = masm()->pc_offset();
1329 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1330 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1331 __ Nop(padding_size);
1334 MarkLazyDeoptSite();
1339 } // namespace compiler
1340 } // namespace internal