1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/code-generator.h"
6 
7 #include "src/compilation-info.h"
8 #include "src/compiler/code-generator-impl.h"
9 #include "src/compiler/gap-resolver.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/osr.h"
12 #include "src/frames.h"
13 #include "src/x87/assembler-x87.h"
14 #include "src/x87/frames-x87.h"
15 #include "src/x87/macro-assembler-x87.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 #define __ masm()->
22 
23 
24 // Adds X87 specific methods for decoding operands.
25 class X87OperandConverter : public InstructionOperandConverter {
26  public:
X87OperandConverter(CodeGenerator * gen,Instruction * instr)27   X87OperandConverter(CodeGenerator* gen, Instruction* instr)
28       : InstructionOperandConverter(gen, instr) {}
29 
InputOperand(size_t index,int extra=0)30   Operand InputOperand(size_t index, int extra = 0) {
31     return ToOperand(instr_->InputAt(index), extra);
32   }
33 
InputImmediate(size_t index)34   Immediate InputImmediate(size_t index) {
35     return ToImmediate(instr_->InputAt(index));
36   }
37 
OutputOperand()38   Operand OutputOperand() { return ToOperand(instr_->Output()); }
39 
ToOperand(InstructionOperand * op,int extra=0)40   Operand ToOperand(InstructionOperand* op, int extra = 0) {
41     if (op->IsRegister()) {
42       DCHECK(extra == 0);
43       return Operand(ToRegister(op));
44     }
45     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
46     return SlotToOperand(AllocatedOperand::cast(op)->index(), extra);
47   }
48 
SlotToOperand(int slot,int extra=0)49   Operand SlotToOperand(int slot, int extra = 0) {
50     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
51     return Operand(offset.from_stack_pointer() ? esp : ebp,
52                    offset.offset() + extra);
53   }
54 
HighOperand(InstructionOperand * op)55   Operand HighOperand(InstructionOperand* op) {
56     DCHECK(op->IsFPStackSlot());
57     return ToOperand(op, kPointerSize);
58   }
59 
ToImmediate(InstructionOperand * operand)60   Immediate ToImmediate(InstructionOperand* operand) {
61     Constant constant = ToConstant(operand);
62     if (constant.type() == Constant::kInt32 &&
63         (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
64          constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
65          constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) {
66       return Immediate(reinterpret_cast<Address>(constant.ToInt32()),
67                        constant.rmode());
68     }
69     switch (constant.type()) {
70       case Constant::kInt32:
71         return Immediate(constant.ToInt32());
72       case Constant::kFloat32:
73         return Immediate(
74             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
75       case Constant::kFloat64:
76         return Immediate(
77             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
78       case Constant::kExternalReference:
79         return Immediate(constant.ToExternalReference());
80       case Constant::kHeapObject:
81         return Immediate(constant.ToHeapObject());
82       case Constant::kInt64:
83         break;
84       case Constant::kRpoNumber:
85         return Immediate::CodeRelativeOffset(ToLabel(operand));
86     }
87     UNREACHABLE();
88     return Immediate(-1);
89   }
90 
NextOffset(size_t * offset)91   static size_t NextOffset(size_t* offset) {
92     size_t i = *offset;
93     (*offset)++;
94     return i;
95   }
96 
ScaleFor(AddressingMode one,AddressingMode mode)97   static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
98     STATIC_ASSERT(0 == static_cast<int>(times_1));
99     STATIC_ASSERT(1 == static_cast<int>(times_2));
100     STATIC_ASSERT(2 == static_cast<int>(times_4));
101     STATIC_ASSERT(3 == static_cast<int>(times_8));
102     int scale = static_cast<int>(mode - one);
103     DCHECK(scale >= 0 && scale < 4);
104     return static_cast<ScaleFactor>(scale);
105   }
106 
MemoryOperand(size_t * offset)107   Operand MemoryOperand(size_t* offset) {
108     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
109     switch (mode) {
110       case kMode_MR: {
111         Register base = InputRegister(NextOffset(offset));
112         int32_t disp = 0;
113         return Operand(base, disp);
114       }
115       case kMode_MRI: {
116         Register base = InputRegister(NextOffset(offset));
117         Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
118         return Operand(base, ctant.ToInt32(), ctant.rmode());
119       }
120       case kMode_MR1:
121       case kMode_MR2:
122       case kMode_MR4:
123       case kMode_MR8: {
124         Register base = InputRegister(NextOffset(offset));
125         Register index = InputRegister(NextOffset(offset));
126         ScaleFactor scale = ScaleFor(kMode_MR1, mode);
127         int32_t disp = 0;
128         return Operand(base, index, scale, disp);
129       }
130       case kMode_MR1I:
131       case kMode_MR2I:
132       case kMode_MR4I:
133       case kMode_MR8I: {
134         Register base = InputRegister(NextOffset(offset));
135         Register index = InputRegister(NextOffset(offset));
136         ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
137         Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
138         return Operand(base, index, scale, ctant.ToInt32(), ctant.rmode());
139       }
140       case kMode_M1:
141       case kMode_M2:
142       case kMode_M4:
143       case kMode_M8: {
144         Register index = InputRegister(NextOffset(offset));
145         ScaleFactor scale = ScaleFor(kMode_M1, mode);
146         int32_t disp = 0;
147         return Operand(index, scale, disp);
148       }
149       case kMode_M1I:
150       case kMode_M2I:
151       case kMode_M4I:
152       case kMode_M8I: {
153         Register index = InputRegister(NextOffset(offset));
154         ScaleFactor scale = ScaleFor(kMode_M1I, mode);
155         Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
156         return Operand(index, scale, ctant.ToInt32(), ctant.rmode());
157       }
158       case kMode_MI: {
159         Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
160         return Operand(ctant.ToInt32(), ctant.rmode());
161       }
162       case kMode_None:
163         UNREACHABLE();
164         return Operand(no_reg, 0);
165     }
166     UNREACHABLE();
167     return Operand(no_reg, 0);
168   }
169 
MemoryOperand(size_t first_input=0)170   Operand MemoryOperand(size_t first_input = 0) {
171     return MemoryOperand(&first_input);
172   }
173 };
174 
175 
176 namespace {
177 
HasImmediateInput(Instruction * instr,size_t index)178 bool HasImmediateInput(Instruction* instr, size_t index) {
179   return instr->InputAt(index)->IsImmediate();
180 }
181 
182 
183 class OutOfLineLoadInteger final : public OutOfLineCode {
184  public:
OutOfLineLoadInteger(CodeGenerator * gen,Register result)185   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
186       : OutOfLineCode(gen), result_(result) {}
187 
Generate()188   void Generate() final { __ xor_(result_, result_); }
189 
190  private:
191   Register const result_;
192 };
193 
194 class OutOfLineLoadFloat32NaN final : public OutOfLineCode {
195  public:
OutOfLineLoadFloat32NaN(CodeGenerator * gen,X87Register result)196   OutOfLineLoadFloat32NaN(CodeGenerator* gen, X87Register result)
197       : OutOfLineCode(gen), result_(result) {}
198 
Generate()199   void Generate() final {
200     DCHECK(result_.code() == 0);
201     USE(result_);
202     __ fstp(0);
203     __ push(Immediate(0xffc00000));
204     __ fld_s(MemOperand(esp, 0));
205     __ lea(esp, Operand(esp, kFloatSize));
206   }
207 
208  private:
209   X87Register const result_;
210 };
211 
212 class OutOfLineLoadFloat64NaN final : public OutOfLineCode {
213  public:
OutOfLineLoadFloat64NaN(CodeGenerator * gen,X87Register result)214   OutOfLineLoadFloat64NaN(CodeGenerator* gen, X87Register result)
215       : OutOfLineCode(gen), result_(result) {}
216 
Generate()217   void Generate() final {
218     DCHECK(result_.code() == 0);
219     USE(result_);
220     __ fstp(0);
221     __ push(Immediate(0xfff80000));
222     __ push(Immediate(0x00000000));
223     __ fld_d(MemOperand(esp, 0));
224     __ lea(esp, Operand(esp, kDoubleSize));
225   }
226 
227  private:
228   X87Register const result_;
229 };
230 
231 class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
232  public:
OutOfLineTruncateDoubleToI(CodeGenerator * gen,Register result,X87Register input)233   OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
234                              X87Register input)
235       : OutOfLineCode(gen), result_(result), input_(input) {}
236 
Generate()237   void Generate() final {
238     UNIMPLEMENTED();
239     USE(result_);
240     USE(input_);
241   }
242 
243  private:
244   Register const result_;
245   X87Register const input_;
246 };
247 
248 
249 class OutOfLineRecordWrite final : public OutOfLineCode {
250  public:
OutOfLineRecordWrite(CodeGenerator * gen,Register object,Operand operand,Register value,Register scratch0,Register scratch1,RecordWriteMode mode)251   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
252                        Register value, Register scratch0, Register scratch1,
253                        RecordWriteMode mode)
254       : OutOfLineCode(gen),
255         object_(object),
256         operand_(operand),
257         value_(value),
258         scratch0_(scratch0),
259         scratch1_(scratch1),
260         mode_(mode) {}
261 
Generate()262   void Generate() final {
263     if (mode_ > RecordWriteMode::kValueIsPointer) {
264       __ JumpIfSmi(value_, exit());
265     }
266     __ CheckPageFlag(value_, scratch0_,
267                      MemoryChunk::kPointersToHereAreInterestingMask, zero,
268                      exit());
269     RememberedSetAction const remembered_set_action =
270         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
271                                              : OMIT_REMEMBERED_SET;
272     SaveFPRegsMode const save_fp_mode =
273         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
274     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
275                          remembered_set_action, save_fp_mode);
276     __ lea(scratch1_, operand_);
277     __ CallStub(&stub);
278   }
279 
280  private:
281   Register const object_;
282   Operand const operand_;
283   Register const value_;
284   Register const scratch0_;
285   Register const scratch1_;
286   RecordWriteMode const mode_;
287 };
288 
289 }  // namespace
290 
291 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, OutOfLineLoadNaN)      \
292   do {                                                                \
293     auto result = i.OutputDoubleRegister();                           \
294     auto offset = i.InputRegister(0);                                 \
295     DCHECK(result.code() == 0);                                       \
296     if (instr->InputAt(1)->IsRegister()) {                            \
297       __ cmp(offset, i.InputRegister(1));                             \
298     } else {                                                          \
299       __ cmp(offset, i.InputImmediate(1));                            \
300     }                                                                 \
301     OutOfLineCode* ool = new (zone()) OutOfLineLoadNaN(this, result); \
302     __ j(above_equal, ool->entry());                                  \
303     __ fstp(0);                                                       \
304     __ asm_instr(i.MemoryOperand(2));                                 \
305     __ bind(ool->exit());                                             \
306   } while (false)
307 
308 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                          \
309   do {                                                                    \
310     auto result = i.OutputRegister();                                     \
311     auto offset = i.InputRegister(0);                                     \
312     if (instr->InputAt(1)->IsRegister()) {                                \
313       __ cmp(offset, i.InputRegister(1));                                 \
314     } else {                                                              \
315       __ cmp(offset, i.InputImmediate(1));                                \
316     }                                                                     \
317     OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
318     __ j(above_equal, ool->entry());                                      \
319     __ asm_instr(result, i.MemoryOperand(2));                             \
320     __ bind(ool->exit());                                                 \
321   } while (false)
322 
323 
324 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)   \
325   do {                                            \
326     auto offset = i.InputRegister(0);             \
327     if (instr->InputAt(1)->IsRegister()) {        \
328       __ cmp(offset, i.InputRegister(1));         \
329     } else {                                      \
330       __ cmp(offset, i.InputImmediate(1));        \
331     }                                             \
332     Label done;                                   \
333     DCHECK(i.InputDoubleRegister(2).code() == 0); \
334     __ j(above_equal, &done, Label::kNear);       \
335     __ asm_instr(i.MemoryOperand(3));             \
336     __ bind(&done);                               \
337   } while (false)
338 
339 
340 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)            \
341   do {                                                       \
342     auto offset = i.InputRegister(0);                        \
343     if (instr->InputAt(1)->IsRegister()) {                   \
344       __ cmp(offset, i.InputRegister(1));                    \
345     } else {                                                 \
346       __ cmp(offset, i.InputImmediate(1));                   \
347     }                                                        \
348     Label done;                                              \
349     __ j(above_equal, &done, Label::kNear);                  \
350     if (instr->InputAt(2)->IsRegister()) {                   \
351       __ asm_instr(i.MemoryOperand(3), i.InputRegister(2));  \
352     } else {                                                 \
353       __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
354     }                                                        \
355     __ bind(&done);                                          \
356   } while (false)
357 
358 #define ASSEMBLE_COMPARE(asm_instr)                                   \
359   do {                                                                \
360     if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
361       size_t index = 0;                                               \
362       Operand left = i.MemoryOperand(&index);                         \
363       if (HasImmediateInput(instr, index)) {                          \
364         __ asm_instr(left, i.InputImmediate(index));                  \
365       } else {                                                        \
366         __ asm_instr(left, i.InputRegister(index));                   \
367       }                                                               \
368     } else {                                                          \
369       if (HasImmediateInput(instr, 1)) {                              \
370         if (instr->InputAt(0)->IsRegister()) {                        \
371           __ asm_instr(i.InputRegister(0), i.InputImmediate(1));      \
372         } else {                                                      \
373           __ asm_instr(i.InputOperand(0), i.InputImmediate(1));       \
374         }                                                             \
375       } else {                                                        \
376         if (instr->InputAt(1)->IsRegister()) {                        \
377           __ asm_instr(i.InputRegister(0), i.InputRegister(1));       \
378         } else {                                                      \
379           __ asm_instr(i.InputRegister(0), i.InputOperand(1));        \
380         }                                                             \
381       }                                                               \
382     }                                                                 \
383   } while (0)
384 
385 #define ASSEMBLE_IEEE754_BINOP(name)                                          \
386   do {                                                                        \
387     /* Saves the esp into ebx */                                              \
388     __ push(ebx);                                                             \
389     __ mov(ebx, esp);                                                         \
390     /* Pass one double as argument on the stack. */                           \
391     __ PrepareCallCFunction(4, eax);                                          \
392     __ fstp(0);                                                               \
393     /* Load first operand from original stack */                              \
394     __ fld_d(MemOperand(ebx, 4 + kDoubleSize));                               \
395     /* Put first operand into stack for function call */                      \
396     __ fstp_d(Operand(esp, 0 * kDoubleSize));                                 \
397     /* Load second operand from original stack */                             \
398     __ fld_d(MemOperand(ebx, 4));                                             \
399     /* Put second operand into stack for function call */                     \
400     __ fstp_d(Operand(esp, 1 * kDoubleSize));                                 \
401     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
402                      4);                                                      \
403     /* Restore the ebx */                                                     \
404     __ pop(ebx);                                                              \
405     /* Return value is in st(0) on x87. */                                    \
406     __ lea(esp, Operand(esp, 2 * kDoubleSize));                               \
407   } while (false)
408 
409 #define ASSEMBLE_IEEE754_UNOP(name)                                           \
410   do {                                                                        \
411     /* Saves the esp into ebx */                                              \
412     __ push(ebx);                                                             \
413     __ mov(ebx, esp);                                                         \
414     /* Pass one double as argument on the stack. */                           \
415     __ PrepareCallCFunction(2, eax);                                          \
416     __ fstp(0);                                                               \
417     /* Load operand from original stack */                                    \
418     __ fld_d(MemOperand(ebx, 4));                                             \
419     /* Put operand into stack for function call */                            \
420     __ fstp_d(Operand(esp, 0));                                               \
421     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
422                      2);                                                      \
423     /* Restore the ebx */                                                     \
424     __ pop(ebx);                                                              \
425     /* Return value is in st(0) on x87. */                                    \
426     __ lea(esp, Operand(esp, kDoubleSize));                                   \
427   } while (false)
428 
AssembleDeconstructFrame()429 void CodeGenerator::AssembleDeconstructFrame() {
430   __ mov(esp, ebp);
431   __ pop(ebp);
432 }
433 
AssemblePrepareTailCall()434 void CodeGenerator::AssemblePrepareTailCall() {
435   if (frame_access_state()->has_frame()) {
436     __ mov(ebp, MemOperand(ebp, 0));
437   }
438   frame_access_state()->SetFrameAccessToSP();
439 }
440 
AssemblePopArgumentsAdaptorFrame(Register args_reg,Register,Register,Register)441 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
442                                                      Register, Register,
443                                                      Register) {
444   // There are not enough temp registers left on ia32 for a call instruction
445   // so we pick some scratch registers and save/restore them manually here.
446   int scratch_count = 3;
447   Register scratch1 = ebx;
448   Register scratch2 = ecx;
449   Register scratch3 = edx;
450   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
451   Label done;
452 
453   // Check if current frame is an arguments adaptor frame.
454   __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset),
455          Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
456   __ j(not_equal, &done, Label::kNear);
457 
458   __ push(scratch1);
459   __ push(scratch2);
460   __ push(scratch3);
461 
462   // Load arguments count from current arguments adaptor frame (note, it
463   // does not include receiver).
464   Register caller_args_count_reg = scratch1;
465   __ mov(caller_args_count_reg,
466          Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
467   __ SmiUntag(caller_args_count_reg);
468 
469   ParameterCount callee_args_count(args_reg);
470   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
471                         scratch3, ReturnAddressState::kOnStack, scratch_count);
472   __ pop(scratch3);
473   __ pop(scratch2);
474   __ pop(scratch1);
475 
476   __ bind(&done);
477 }
478 
479 namespace {
480 
AdjustStackPointerForTailCall(MacroAssembler * masm,FrameAccessState * state,int new_slot_above_sp,bool allow_shrinkage=true)481 void AdjustStackPointerForTailCall(MacroAssembler* masm,
482                                    FrameAccessState* state,
483                                    int new_slot_above_sp,
484                                    bool allow_shrinkage = true) {
485   int current_sp_offset = state->GetSPToFPSlotCount() +
486                           StandardFrameConstants::kFixedSlotCountAboveFp;
487   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
488   if (stack_slot_delta > 0) {
489     masm->sub(esp, Immediate(stack_slot_delta * kPointerSize));
490     state->IncreaseSPDelta(stack_slot_delta);
491   } else if (allow_shrinkage && stack_slot_delta < 0) {
492     masm->add(esp, Immediate(-stack_slot_delta * kPointerSize));
493     state->IncreaseSPDelta(stack_slot_delta);
494   }
495 }
496 
497 }  // namespace
498 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_stack_slot)499 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
500                                               int first_unused_stack_slot) {
501   CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
502   ZoneVector<MoveOperands*> pushes(zone());
503   GetPushCompatibleMoves(instr, flags, &pushes);
504 
505   if (!pushes.empty() &&
506       (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
507        first_unused_stack_slot)) {
508     X87OperandConverter g(this, instr);
509     for (auto move : pushes) {
510       LocationOperand destination_location(
511           LocationOperand::cast(move->destination()));
512       InstructionOperand source(move->source());
513       AdjustStackPointerForTailCall(masm(), frame_access_state(),
514                                     destination_location.index());
515       if (source.IsStackSlot()) {
516         LocationOperand source_location(LocationOperand::cast(source));
517         __ push(g.SlotToOperand(source_location.index()));
518       } else if (source.IsRegister()) {
519         LocationOperand source_location(LocationOperand::cast(source));
520         __ push(source_location.GetRegister());
521       } else if (source.IsImmediate()) {
522         __ push(Immediate(ImmediateOperand::cast(source).inline_value()));
523       } else {
524         // Pushes of non-scalar data types is not supported.
525         UNIMPLEMENTED();
526       }
527       frame_access_state()->IncreaseSPDelta(1);
528       move->Eliminate();
529     }
530   }
531   AdjustStackPointerForTailCall(masm(), frame_access_state(),
532                                 first_unused_stack_slot, false);
533 }
534 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_stack_slot)535 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
536                                              int first_unused_stack_slot) {
537   AdjustStackPointerForTailCall(masm(), frame_access_state(),
538                                 first_unused_stack_slot);
539 }
540 
541 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)542 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
543     Instruction* instr) {
544   X87OperandConverter i(this, instr);
545   InstructionCode opcode = instr->opcode();
546   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
547 
548   switch (arch_opcode) {
549     case kArchCallCodeObject: {
550       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
551         __ VerifyX87StackDepth(1);
552       }
553       __ fstp(0);
554       EnsureSpaceForLazyDeopt();
555       if (HasImmediateInput(instr, 0)) {
556         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
557         __ call(code, RelocInfo::CODE_TARGET);
558       } else {
559         Register reg = i.InputRegister(0);
560         __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
561         __ call(reg);
562       }
563       RecordCallPosition(instr);
564       bool double_result =
565           instr->HasOutput() && instr->Output()->IsFPRegister();
566       if (double_result) {
567         __ lea(esp, Operand(esp, -kDoubleSize));
568         __ fstp_d(Operand(esp, 0));
569       }
570       __ fninit();
571       if (double_result) {
572         __ fld_d(Operand(esp, 0));
573         __ lea(esp, Operand(esp, kDoubleSize));
574       } else {
575         __ fld1();
576       }
577       frame_access_state()->ClearSPDelta();
578       break;
579     }
580     case kArchTailCallCodeObjectFromJSFunction:
581     case kArchTailCallCodeObject: {
582       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
583         __ VerifyX87StackDepth(1);
584       }
585       __ fstp(0);
586       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
587         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
588                                          no_reg, no_reg, no_reg);
589       }
590       if (HasImmediateInput(instr, 0)) {
591         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
592         __ jmp(code, RelocInfo::CODE_TARGET);
593       } else {
594         Register reg = i.InputRegister(0);
595         __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
596         __ jmp(reg);
597       }
598       frame_access_state()->ClearSPDelta();
599       frame_access_state()->SetFrameAccessToDefault();
600       break;
601     }
602     case kArchTailCallAddress: {
603       CHECK(!HasImmediateInput(instr, 0));
604       Register reg = i.InputRegister(0);
605       __ jmp(reg);
606       frame_access_state()->ClearSPDelta();
607       frame_access_state()->SetFrameAccessToDefault();
608       break;
609     }
610     case kArchCallJSFunction: {
611       EnsureSpaceForLazyDeopt();
612       Register func = i.InputRegister(0);
613       if (FLAG_debug_code) {
614         // Check the function's context matches the context argument.
615         __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
616         __ Assert(equal, kWrongFunctionContext);
617       }
618       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
619         __ VerifyX87StackDepth(1);
620       }
621       __ fstp(0);
622       __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
623       RecordCallPosition(instr);
624       bool double_result =
625           instr->HasOutput() && instr->Output()->IsFPRegister();
626       if (double_result) {
627         __ lea(esp, Operand(esp, -kDoubleSize));
628         __ fstp_d(Operand(esp, 0));
629       }
630       __ fninit();
631       if (double_result) {
632         __ fld_d(Operand(esp, 0));
633         __ lea(esp, Operand(esp, kDoubleSize));
634       } else {
635         __ fld1();
636       }
637       frame_access_state()->ClearSPDelta();
638       break;
639     }
640     case kArchTailCallJSFunctionFromJSFunction: {
641       Register func = i.InputRegister(0);
642       if (FLAG_debug_code) {
643         // Check the function's context matches the context argument.
644         __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
645         __ Assert(equal, kWrongFunctionContext);
646       }
647       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
648         __ VerifyX87StackDepth(1);
649       }
650       __ fstp(0);
651       AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, no_reg,
652                                        no_reg, no_reg);
653       __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
654       frame_access_state()->ClearSPDelta();
655       frame_access_state()->SetFrameAccessToDefault();
656       break;
657     }
658     case kArchPrepareCallCFunction: {
659       // Frame alignment requires using FP-relative frame addressing.
660       frame_access_state()->SetFrameAccessToFP();
661       int const num_parameters = MiscField::decode(instr->opcode());
662       __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
663       break;
664     }
665     case kArchPrepareTailCall:
666       AssemblePrepareTailCall();
667       break;
668     case kArchCallCFunction: {
669       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
670         __ VerifyX87StackDepth(1);
671       }
672       __ fstp(0);
673       int const num_parameters = MiscField::decode(instr->opcode());
674       if (HasImmediateInput(instr, 0)) {
675         ExternalReference ref = i.InputExternalReference(0);
676         __ CallCFunction(ref, num_parameters);
677       } else {
678         Register func = i.InputRegister(0);
679         __ CallCFunction(func, num_parameters);
680       }
681       bool double_result =
682           instr->HasOutput() && instr->Output()->IsFPRegister();
683       if (double_result) {
684         __ lea(esp, Operand(esp, -kDoubleSize));
685         __ fstp_d(Operand(esp, 0));
686       }
687       __ fninit();
688       if (double_result) {
689         __ fld_d(Operand(esp, 0));
690         __ lea(esp, Operand(esp, kDoubleSize));
691       } else {
692         __ fld1();
693       }
694       frame_access_state()->SetFrameAccessToDefault();
695       frame_access_state()->ClearSPDelta();
696       break;
697     }
698     case kArchJmp:
699       AssembleArchJump(i.InputRpo(0));
700       break;
701     case kArchLookupSwitch:
702       AssembleArchLookupSwitch(instr);
703       break;
704     case kArchTableSwitch:
705       AssembleArchTableSwitch(instr);
706       break;
707     case kArchComment: {
708       Address comment_string = i.InputExternalReference(0).address();
709       __ RecordComment(reinterpret_cast<const char*>(comment_string));
710       break;
711     }
712     case kArchDebugBreak:
713       __ int3();
714       break;
715     case kArchNop:
716     case kArchThrowTerminator:
717       // don't emit code for nops.
718       break;
719     case kArchDeoptimize: {
720       int deopt_state_id =
721           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
722       int double_register_param_count = 0;
723       int x87_layout = 0;
724       for (size_t i = 0; i < instr->InputCount(); i++) {
725         if (instr->InputAt(i)->IsFPRegister()) {
726           double_register_param_count++;
727         }
728       }
729       // Currently we use only one X87 register. If double_register_param_count
730       // is bigger than 1, it means duplicated double register is added to input
731       // of this instruction.
732       if (double_register_param_count > 0) {
733         x87_layout = (0 << 3) | 1;
734       }
735       // The layout of x87 register stack is loaded on the top of FPU register
736       // stack for deoptimization.
737       __ push(Immediate(x87_layout));
738       __ fild_s(MemOperand(esp, 0));
739       __ lea(esp, Operand(esp, kPointerSize));
740 
741       Deoptimizer::BailoutType bailout_type =
742           Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
743       CodeGenResult result = AssembleDeoptimizerCall(
744           deopt_state_id, bailout_type, current_source_position_);
745       if (result != kSuccess) return result;
746       break;
747     }
748     case kArchRet:
749       AssembleReturn(instr->InputAt(0));
750       break;
751     case kArchFramePointer:
752       __ mov(i.OutputRegister(), ebp);
753       break;
754     case kArchStackPointer:
755       __ mov(i.OutputRegister(), esp);
756       break;
757     case kArchParentFramePointer:
758       if (frame_access_state()->has_frame()) {
759         __ mov(i.OutputRegister(), Operand(ebp, 0));
760       } else {
761         __ mov(i.OutputRegister(), ebp);
762       }
763       break;
764     case kArchTruncateDoubleToI: {
765       if (!instr->InputAt(0)->IsFPRegister()) {
766         __ fld_d(i.InputOperand(0));
767       }
768       __ TruncateX87TOSToI(i.OutputRegister());
769       if (!instr->InputAt(0)->IsFPRegister()) {
770         __ fstp(0);
771       }
772       break;
773     }
774     case kArchStoreWithWriteBarrier: {
775       RecordWriteMode mode =
776           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
777       Register object = i.InputRegister(0);
778       size_t index = 0;
779       Operand operand = i.MemoryOperand(&index);
780       Register value = i.InputRegister(index);
781       Register scratch0 = i.TempRegister(0);
782       Register scratch1 = i.TempRegister(1);
783       auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
784                                                    scratch0, scratch1, mode);
785       __ mov(operand, value);
786       __ CheckPageFlag(object, scratch0,
787                        MemoryChunk::kPointersFromHereAreInterestingMask,
788                        not_zero, ool->entry());
789       __ bind(ool->exit());
790       break;
791     }
792     case kArchStackSlot: {
793       FrameOffset offset =
794           frame_access_state()->GetFrameOffset(i.InputInt32(0));
795       Register base;
796       if (offset.from_stack_pointer()) {
797         base = esp;
798       } else {
799         base = ebp;
800       }
801       __ lea(i.OutputRegister(), Operand(base, offset.offset()));
802       break;
803     }
804     case kIeee754Float64Acos:
805       ASSEMBLE_IEEE754_UNOP(acos);
806       break;
807     case kIeee754Float64Acosh:
808       ASSEMBLE_IEEE754_UNOP(acosh);
809       break;
810     case kIeee754Float64Asin:
811       ASSEMBLE_IEEE754_UNOP(asin);
812       break;
813     case kIeee754Float64Asinh:
814       ASSEMBLE_IEEE754_UNOP(asinh);
815       break;
816     case kIeee754Float64Atan:
817       ASSEMBLE_IEEE754_UNOP(atan);
818       break;
819     case kIeee754Float64Atanh:
820       ASSEMBLE_IEEE754_UNOP(atanh);
821       break;
822     case kIeee754Float64Atan2:
823       ASSEMBLE_IEEE754_BINOP(atan2);
824       break;
825     case kIeee754Float64Cbrt:
826       ASSEMBLE_IEEE754_UNOP(cbrt);
827       break;
828     case kIeee754Float64Cos:
829       __ X87SetFPUCW(0x027F);
830       ASSEMBLE_IEEE754_UNOP(cos);
831       __ X87SetFPUCW(0x037F);
832       break;
833     case kIeee754Float64Cosh:
834       ASSEMBLE_IEEE754_UNOP(cosh);
835       break;
836     case kIeee754Float64Expm1:
837       __ X87SetFPUCW(0x027F);
838       ASSEMBLE_IEEE754_UNOP(expm1);
839       __ X87SetFPUCW(0x037F);
840       break;
841     case kIeee754Float64Exp:
842       ASSEMBLE_IEEE754_UNOP(exp);
843       break;
844     case kIeee754Float64Log:
845       ASSEMBLE_IEEE754_UNOP(log);
846       break;
847     case kIeee754Float64Log1p:
848       ASSEMBLE_IEEE754_UNOP(log1p);
849       break;
850     case kIeee754Float64Log2:
851       ASSEMBLE_IEEE754_UNOP(log2);
852       break;
853     case kIeee754Float64Log10:
854       ASSEMBLE_IEEE754_UNOP(log10);
855       break;
856     case kIeee754Float64Pow: {
857       // Keep the x87 FPU stack empty before calling stub code
858       __ fstp(0);
859       // Call the MathStub and put return value in stX_0
860       MathPowStub stub(isolate(), MathPowStub::DOUBLE);
861       __ CallStub(&stub);
862       /* Return value is in st(0) on x87. */
863       __ lea(esp, Operand(esp, 2 * kDoubleSize));
864       break;
865     }
866     case kIeee754Float64Sin:
867       __ X87SetFPUCW(0x027F);
868       ASSEMBLE_IEEE754_UNOP(sin);
869       __ X87SetFPUCW(0x037F);
870       break;
871     case kIeee754Float64Sinh:
872       ASSEMBLE_IEEE754_UNOP(sinh);
873       break;
874     case kIeee754Float64Tan:
875       __ X87SetFPUCW(0x027F);
876       ASSEMBLE_IEEE754_UNOP(tan);
877       __ X87SetFPUCW(0x037F);
878       break;
879     case kIeee754Float64Tanh:
880       ASSEMBLE_IEEE754_UNOP(tanh);
881       break;
882     case kX87Add:
883       if (HasImmediateInput(instr, 1)) {
884         __ add(i.InputOperand(0), i.InputImmediate(1));
885       } else {
886         __ add(i.InputRegister(0), i.InputOperand(1));
887       }
888       break;
889     case kX87And:
890       if (HasImmediateInput(instr, 1)) {
891         __ and_(i.InputOperand(0), i.InputImmediate(1));
892       } else {
893         __ and_(i.InputRegister(0), i.InputOperand(1));
894       }
895       break;
896     case kX87Cmp:
897       ASSEMBLE_COMPARE(cmp);
898       break;
899     case kX87Cmp16:
900       ASSEMBLE_COMPARE(cmpw);
901       break;
902     case kX87Cmp8:
903       ASSEMBLE_COMPARE(cmpb);
904       break;
905     case kX87Test:
906       ASSEMBLE_COMPARE(test);
907       break;
908     case kX87Test16:
909       ASSEMBLE_COMPARE(test_w);
910       break;
911     case kX87Test8:
912       ASSEMBLE_COMPARE(test_b);
913       break;
914     case kX87Imul:
915       if (HasImmediateInput(instr, 1)) {
916         __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
917       } else {
918         __ imul(i.OutputRegister(), i.InputOperand(1));
919       }
920       break;
921     case kX87ImulHigh:
922       __ imul(i.InputRegister(1));
923       break;
924     case kX87UmulHigh:
925       __ mul(i.InputRegister(1));
926       break;
927     case kX87Idiv:
928       __ cdq();
929       __ idiv(i.InputOperand(1));
930       break;
931     case kX87Udiv:
932       __ Move(edx, Immediate(0));
933       __ div(i.InputOperand(1));
934       break;
935     case kX87Not:
936       __ not_(i.OutputOperand());
937       break;
938     case kX87Neg:
939       __ neg(i.OutputOperand());
940       break;
941     case kX87Or:
942       if (HasImmediateInput(instr, 1)) {
943         __ or_(i.InputOperand(0), i.InputImmediate(1));
944       } else {
945         __ or_(i.InputRegister(0), i.InputOperand(1));
946       }
947       break;
948     case kX87Xor:
949       if (HasImmediateInput(instr, 1)) {
950         __ xor_(i.InputOperand(0), i.InputImmediate(1));
951       } else {
952         __ xor_(i.InputRegister(0), i.InputOperand(1));
953       }
954       break;
955     case kX87Sub:
956       if (HasImmediateInput(instr, 1)) {
957         __ sub(i.InputOperand(0), i.InputImmediate(1));
958       } else {
959         __ sub(i.InputRegister(0), i.InputOperand(1));
960       }
961       break;
962     case kX87Shl:
963       if (HasImmediateInput(instr, 1)) {
964         __ shl(i.OutputOperand(), i.InputInt5(1));
965       } else {
966         __ shl_cl(i.OutputOperand());
967       }
968       break;
969     case kX87Shr:
970       if (HasImmediateInput(instr, 1)) {
971         __ shr(i.OutputOperand(), i.InputInt5(1));
972       } else {
973         __ shr_cl(i.OutputOperand());
974       }
975       break;
976     case kX87Sar:
977       if (HasImmediateInput(instr, 1)) {
978         __ sar(i.OutputOperand(), i.InputInt5(1));
979       } else {
980         __ sar_cl(i.OutputOperand());
981       }
982       break;
983     case kX87AddPair: {
984       // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
985       // i.InputRegister(1) ... left high word.
986       // i.InputRegister(2) ... right low word.
987       // i.InputRegister(3) ... right high word.
988       bool use_temp = false;
989       if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
990           i.OutputRegister(0).code() == i.InputRegister(3).code()) {
991         // We cannot write to the output register directly, because it would
992         // overwrite an input for adc. We have to use the temp register.
993         use_temp = true;
994         __ Move(i.TempRegister(0), i.InputRegister(0));
995         __ add(i.TempRegister(0), i.InputRegister(2));
996       } else {
997         __ add(i.OutputRegister(0), i.InputRegister(2));
998       }
999       __ adc(i.InputRegister(1), Operand(i.InputRegister(3)));
1000       if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
1001         __ Move(i.OutputRegister(1), i.InputRegister(1));
1002       }
1003       if (use_temp) {
1004         __ Move(i.OutputRegister(0), i.TempRegister(0));
1005       }
1006       break;
1007     }
1008     case kX87SubPair: {
1009       // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
1010       // i.InputRegister(1) ... left high word.
1011       // i.InputRegister(2) ... right low word.
1012       // i.InputRegister(3) ... right high word.
1013       bool use_temp = false;
1014       if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
1015           i.OutputRegister(0).code() == i.InputRegister(3).code()) {
1016         // We cannot write to the output register directly, because it would
1017         // overwrite an input for adc. We have to use the temp register.
1018         use_temp = true;
1019         __ Move(i.TempRegister(0), i.InputRegister(0));
1020         __ sub(i.TempRegister(0), i.InputRegister(2));
1021       } else {
1022         __ sub(i.OutputRegister(0), i.InputRegister(2));
1023       }
1024       __ sbb(i.InputRegister(1), Operand(i.InputRegister(3)));
1025       if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
1026         __ Move(i.OutputRegister(1), i.InputRegister(1));
1027       }
1028       if (use_temp) {
1029         __ Move(i.OutputRegister(0), i.TempRegister(0));
1030       }
1031       break;
1032     }
1033     case kX87MulPair: {
1034       __ imul(i.OutputRegister(1), i.InputOperand(0));
1035       __ mov(i.TempRegister(0), i.InputOperand(1));
1036       __ imul(i.TempRegister(0), i.InputOperand(2));
1037       __ add(i.OutputRegister(1), i.TempRegister(0));
1038       __ mov(i.OutputRegister(0), i.InputOperand(0));
1039       // Multiplies the low words and stores them in eax and edx.
1040       __ mul(i.InputRegister(2));
1041       __ add(i.OutputRegister(1), i.TempRegister(0));
1042 
1043       break;
1044     }
1045     case kX87ShlPair:
1046       if (HasImmediateInput(instr, 2)) {
1047         __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
1048       } else {
1049         // Shift has been loaded into CL by the register allocator.
1050         __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0));
1051       }
1052       break;
1053     case kX87ShrPair:
1054       if (HasImmediateInput(instr, 2)) {
1055         __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
1056       } else {
1057         // Shift has been loaded into CL by the register allocator.
1058         __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0));
1059       }
1060       break;
1061     case kX87SarPair:
1062       if (HasImmediateInput(instr, 2)) {
1063         __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
1064       } else {
1065         // Shift has been loaded into CL by the register allocator.
1066         __ SarPair_cl(i.InputRegister(1), i.InputRegister(0));
1067       }
1068       break;
1069     case kX87Ror:
1070       if (HasImmediateInput(instr, 1)) {
1071         __ ror(i.OutputOperand(), i.InputInt5(1));
1072       } else {
1073         __ ror_cl(i.OutputOperand());
1074       }
1075       break;
1076     case kX87Lzcnt:
1077       __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
1078       break;
1079     case kX87Popcnt:
1080       __ Popcnt(i.OutputRegister(), i.InputOperand(0));
1081       break;
1082     case kX87LoadFloat64Constant: {
1083       InstructionOperand* source = instr->InputAt(0);
1084       InstructionOperand* destination = instr->Output();
1085       DCHECK(source->IsConstant());
1086       X87OperandConverter g(this, nullptr);
1087       Constant src_constant = g.ToConstant(source);
1088 
1089       DCHECK_EQ(Constant::kFloat64, src_constant.type());
1090       uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1091       uint32_t lower = static_cast<uint32_t>(src);
1092       uint32_t upper = static_cast<uint32_t>(src >> 32);
1093       if (destination->IsFPRegister()) {
1094         __ sub(esp, Immediate(kDoubleSize));
1095         __ mov(MemOperand(esp, 0), Immediate(lower));
1096         __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
1097         __ fstp(0);
1098         __ fld_d(MemOperand(esp, 0));
1099         __ add(esp, Immediate(kDoubleSize));
1100       } else {
1101         UNREACHABLE();
1102       }
1103       break;
1104     }
1105     case kX87Float32Cmp: {
1106       __ fld_s(MemOperand(esp, kFloatSize));
1107       __ fld_s(MemOperand(esp, 0));
1108       __ FCmp();
1109       __ lea(esp, Operand(esp, 2 * kFloatSize));
1110       break;
1111     }
1112     case kX87Float32Add: {
1113       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1114         __ VerifyX87StackDepth(1);
1115       }
1116       __ X87SetFPUCW(0x027F);
1117       __ fstp(0);
1118       __ fld_s(MemOperand(esp, 0));
1119       __ fld_s(MemOperand(esp, kFloatSize));
1120       __ faddp();
1121       // Clear stack.
1122       __ lea(esp, Operand(esp, 2 * kFloatSize));
1123       // Restore the default value of control word.
1124       __ X87SetFPUCW(0x037F);
1125       break;
1126     }
1127     case kX87Float32Sub: {
1128       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1129         __ VerifyX87StackDepth(1);
1130       }
1131       __ X87SetFPUCW(0x027F);
1132       __ fstp(0);
1133       __ fld_s(MemOperand(esp, kFloatSize));
1134       __ fld_s(MemOperand(esp, 0));
1135       __ fsubp();
1136       // Clear stack.
1137       __ lea(esp, Operand(esp, 2 * kFloatSize));
1138       // Restore the default value of control word.
1139       __ X87SetFPUCW(0x037F);
1140       break;
1141     }
1142     case kX87Float32Mul: {
1143       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1144         __ VerifyX87StackDepth(1);
1145       }
1146       __ X87SetFPUCW(0x027F);
1147       __ fstp(0);
1148       __ fld_s(MemOperand(esp, kFloatSize));
1149       __ fld_s(MemOperand(esp, 0));
1150       __ fmulp();
1151       // Clear stack.
1152       __ lea(esp, Operand(esp, 2 * kFloatSize));
1153       // Restore the default value of control word.
1154       __ X87SetFPUCW(0x037F);
1155       break;
1156     }
1157     case kX87Float32Div: {
1158       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1159         __ VerifyX87StackDepth(1);
1160       }
1161       __ X87SetFPUCW(0x027F);
1162       __ fstp(0);
1163       __ fld_s(MemOperand(esp, kFloatSize));
1164       __ fld_s(MemOperand(esp, 0));
1165       __ fdivp();
1166       // Clear stack.
1167       __ lea(esp, Operand(esp, 2 * kFloatSize));
1168       // Restore the default value of control word.
1169       __ X87SetFPUCW(0x037F);
1170       break;
1171     }
1172 
1173     case kX87Float32Sqrt: {
1174       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1175         __ VerifyX87StackDepth(1);
1176       }
1177       __ fstp(0);
1178       __ fld_s(MemOperand(esp, 0));
1179       __ fsqrt();
1180       __ lea(esp, Operand(esp, kFloatSize));
1181       break;
1182     }
1183     case kX87Float32Abs: {
1184       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1185         __ VerifyX87StackDepth(1);
1186       }
1187       __ fstp(0);
1188       __ fld_s(MemOperand(esp, 0));
1189       __ fabs();
1190       __ lea(esp, Operand(esp, kFloatSize));
1191       break;
1192     }
1193     case kX87Float32Neg: {
1194       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1195         __ VerifyX87StackDepth(1);
1196       }
1197       __ fstp(0);
1198       __ fld_s(MemOperand(esp, 0));
1199       __ fchs();
1200       __ lea(esp, Operand(esp, kFloatSize));
1201       break;
1202     }
1203     case kX87Float32Round: {
1204       RoundingMode mode =
1205           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
1206       // Set the correct round mode in x87 control register
1207       __ X87SetRC((mode << 10));
1208 
1209       if (!instr->InputAt(0)->IsFPRegister()) {
1210         InstructionOperand* input = instr->InputAt(0);
1211         USE(input);
1212         DCHECK(input->IsFPStackSlot());
1213         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1214           __ VerifyX87StackDepth(1);
1215         }
1216         __ fstp(0);
1217         __ fld_s(i.InputOperand(0));
1218       }
1219       __ frndint();
1220       __ X87SetRC(0x0000);
1221       break;
1222     }
1223     case kX87Float64Add: {
1224       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1225         __ VerifyX87StackDepth(1);
1226       }
1227       __ X87SetFPUCW(0x027F);
1228       __ fstp(0);
1229       __ fld_d(MemOperand(esp, 0));
1230       __ fld_d(MemOperand(esp, kDoubleSize));
1231       __ faddp();
1232       // Clear stack.
1233       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1234       // Restore the default value of control word.
1235       __ X87SetFPUCW(0x037F);
1236       break;
1237     }
1238     case kX87Float64Sub: {
1239       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1240         __ VerifyX87StackDepth(1);
1241       }
1242       __ X87SetFPUCW(0x027F);
1243       __ fstp(0);
1244       __ fld_d(MemOperand(esp, kDoubleSize));
1245       __ fsub_d(MemOperand(esp, 0));
1246       // Clear stack.
1247       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1248       // Restore the default value of control word.
1249       __ X87SetFPUCW(0x037F);
1250       break;
1251     }
1252     case kX87Float64Mul: {
1253       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1254         __ VerifyX87StackDepth(1);
1255       }
1256       __ X87SetFPUCW(0x027F);
1257       __ fstp(0);
1258       __ fld_d(MemOperand(esp, kDoubleSize));
1259       __ fmul_d(MemOperand(esp, 0));
1260       // Clear stack.
1261       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1262       // Restore the default value of control word.
1263       __ X87SetFPUCW(0x037F);
1264       break;
1265     }
1266     case kX87Float64Div: {
1267       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1268         __ VerifyX87StackDepth(1);
1269       }
1270       __ X87SetFPUCW(0x027F);
1271       __ fstp(0);
1272       __ fld_d(MemOperand(esp, kDoubleSize));
1273       __ fdiv_d(MemOperand(esp, 0));
1274       // Clear stack.
1275       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1276       // Restore the default value of control word.
1277       __ X87SetFPUCW(0x037F);
1278       break;
1279     }
1280     case kX87Float64Mod: {
1281       FrameScope frame_scope(&masm_, StackFrame::MANUAL);
1282       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1283         __ VerifyX87StackDepth(1);
1284       }
1285       __ mov(eax, esp);
1286       __ PrepareCallCFunction(4, eax);
1287       __ fstp(0);
1288       __ fld_d(MemOperand(eax, 0));
1289       __ fstp_d(Operand(esp, 1 * kDoubleSize));
1290       __ fld_d(MemOperand(eax, kDoubleSize));
1291       __ fstp_d(Operand(esp, 0));
1292       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1293                        4);
1294       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1295       break;
1296     }
1297     case kX87Float32Max: {
1298       Label compare_swap, done_compare;
1299       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1300         __ VerifyX87StackDepth(1);
1301       }
1302       __ fstp(0);
1303       __ fld_s(MemOperand(esp, kFloatSize));
1304       __ fld_s(MemOperand(esp, 0));
1305       __ fld(1);
1306       __ fld(1);
1307       __ FCmp();
1308 
1309       auto ool =
1310           new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister());
1311       __ j(parity_even, ool->entry());
1312       __ j(below, &done_compare, Label::kNear);
1313       __ j(above, &compare_swap, Label::kNear);
1314       __ push(eax);
1315       __ lea(esp, Operand(esp, -kFloatSize));
1316       __ fld(1);
1317       __ fstp_s(Operand(esp, 0));
1318       __ mov(eax, MemOperand(esp, 0));
1319       __ and_(eax, Immediate(0x80000000));
1320       __ lea(esp, Operand(esp, kFloatSize));
1321       __ pop(eax);
1322       __ j(zero, &done_compare, Label::kNear);
1323 
1324       __ bind(&compare_swap);
1325       __ bind(ool->exit());
1326       __ fxch(1);
1327 
1328       __ bind(&done_compare);
1329       __ fstp(0);
1330       __ lea(esp, Operand(esp, 2 * kFloatSize));
1331       break;
1332     }
1333     case kX87Float64Max: {
1334       Label compare_swap, done_compare;
1335       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1336         __ VerifyX87StackDepth(1);
1337       }
1338       __ fstp(0);
1339       __ fld_d(MemOperand(esp, kDoubleSize));
1340       __ fld_d(MemOperand(esp, 0));
1341       __ fld(1);
1342       __ fld(1);
1343       __ FCmp();
1344 
1345       auto ool =
1346           new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister());
1347       __ j(parity_even, ool->entry());
1348       __ j(below, &done_compare, Label::kNear);
1349       __ j(above, &compare_swap, Label::kNear);
1350       __ push(eax);
1351       __ lea(esp, Operand(esp, -kDoubleSize));
1352       __ fld(1);
1353       __ fstp_d(Operand(esp, 0));
1354       __ mov(eax, MemOperand(esp, 4));
1355       __ and_(eax, Immediate(0x80000000));
1356       __ lea(esp, Operand(esp, kDoubleSize));
1357       __ pop(eax);
1358       __ j(zero, &done_compare, Label::kNear);
1359 
1360       __ bind(&compare_swap);
1361       __ bind(ool->exit());
1362       __ fxch(1);
1363 
1364       __ bind(&done_compare);
1365       __ fstp(0);
1366       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1367       break;
1368     }
1369     case kX87Float32Min: {
1370       Label compare_swap, done_compare;
1371       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1372         __ VerifyX87StackDepth(1);
1373       }
1374       __ fstp(0);
1375       __ fld_s(MemOperand(esp, kFloatSize));
1376       __ fld_s(MemOperand(esp, 0));
1377       __ fld(1);
1378       __ fld(1);
1379       __ FCmp();
1380 
1381       auto ool =
1382           new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister());
1383       __ j(parity_even, ool->entry());
1384       __ j(above, &done_compare, Label::kNear);
1385       __ j(below, &compare_swap, Label::kNear);
1386       __ push(eax);
1387       __ lea(esp, Operand(esp, -kFloatSize));
1388       __ fld(0);
1389       __ fstp_s(Operand(esp, 0));
1390       __ mov(eax, MemOperand(esp, 0));
1391       __ and_(eax, Immediate(0x80000000));
1392       __ lea(esp, Operand(esp, kFloatSize));
1393       __ pop(eax);
1394       __ j(zero, &done_compare, Label::kNear);
1395 
1396       __ bind(&compare_swap);
1397       __ bind(ool->exit());
1398       __ fxch(1);
1399 
1400       __ bind(&done_compare);
1401       __ fstp(0);
1402       __ lea(esp, Operand(esp, 2 * kFloatSize));
1403       break;
1404     }
1405     case kX87Float64Min: {
1406       Label compare_swap, done_compare;
1407       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1408         __ VerifyX87StackDepth(1);
1409       }
1410       __ fstp(0);
1411       __ fld_d(MemOperand(esp, kDoubleSize));
1412       __ fld_d(MemOperand(esp, 0));
1413       __ fld(1);
1414       __ fld(1);
1415       __ FCmp();
1416 
1417       auto ool =
1418           new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister());
1419       __ j(parity_even, ool->entry());
1420       __ j(above, &done_compare, Label::kNear);
1421       __ j(below, &compare_swap, Label::kNear);
1422       __ push(eax);
1423       __ lea(esp, Operand(esp, -kDoubleSize));
1424       __ fld(0);
1425       __ fstp_d(Operand(esp, 0));
1426       __ mov(eax, MemOperand(esp, 4));
1427       __ and_(eax, Immediate(0x80000000));
1428       __ lea(esp, Operand(esp, kDoubleSize));
1429       __ pop(eax);
1430       __ j(zero, &done_compare, Label::kNear);
1431 
1432       __ bind(&compare_swap);
1433       __ bind(ool->exit());
1434       __ fxch(1);
1435 
1436       __ bind(&done_compare);
1437       __ fstp(0);
1438       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1439       break;
1440     }
1441     case kX87Float64Abs: {
1442       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1443         __ VerifyX87StackDepth(1);
1444       }
1445       __ fstp(0);
1446       __ fld_d(MemOperand(esp, 0));
1447       __ fabs();
1448       __ lea(esp, Operand(esp, kDoubleSize));
1449       break;
1450     }
1451     case kX87Float64Neg: {
1452       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1453         __ VerifyX87StackDepth(1);
1454       }
1455       __ fstp(0);
1456       __ fld_d(MemOperand(esp, 0));
1457       __ fchs();
1458       __ lea(esp, Operand(esp, kDoubleSize));
1459       break;
1460     }
1461     case kX87Int32ToFloat32: {
1462       InstructionOperand* input = instr->InputAt(0);
1463       DCHECK(input->IsRegister() || input->IsStackSlot());
1464       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1465         __ VerifyX87StackDepth(1);
1466       }
1467       __ fstp(0);
1468       if (input->IsRegister()) {
1469         Register input_reg = i.InputRegister(0);
1470         __ push(input_reg);
1471         __ fild_s(Operand(esp, 0));
1472         __ pop(input_reg);
1473       } else {
1474         __ fild_s(i.InputOperand(0));
1475       }
1476       break;
1477     }
1478     case kX87Uint32ToFloat32: {
1479       InstructionOperand* input = instr->InputAt(0);
1480       DCHECK(input->IsRegister() || input->IsStackSlot());
1481       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1482         __ VerifyX87StackDepth(1);
1483       }
1484       __ fstp(0);
1485       Label msb_set_src;
1486       Label jmp_return;
1487       // Put input integer into eax(tmporarilly)
1488       __ push(eax);
1489       if (input->IsRegister())
1490         __ mov(eax, i.InputRegister(0));
1491       else
1492         __ mov(eax, i.InputOperand(0));
1493 
1494       __ test(eax, eax);
1495       __ j(sign, &msb_set_src, Label::kNear);
1496       __ push(eax);
1497       __ fild_s(Operand(esp, 0));
1498       __ pop(eax);
1499 
1500       __ jmp(&jmp_return, Label::kNear);
1501       __ bind(&msb_set_src);
1502       // Need another temp reg
1503       __ push(ebx);
1504       __ mov(ebx, eax);
1505       __ shr(eax, 1);
1506       // Recover the least significant bit to avoid rounding errors.
1507       __ and_(ebx, Immediate(1));
1508       __ or_(eax, ebx);
1509       __ push(eax);
1510       __ fild_s(Operand(esp, 0));
1511       __ pop(eax);
1512       __ fld(0);
1513       __ faddp();
1514       // Restore the ebx
1515       __ pop(ebx);
1516       __ bind(&jmp_return);
1517       // Restore the eax
1518       __ pop(eax);
1519       break;
1520     }
1521     case kX87Int32ToFloat64: {
1522       InstructionOperand* input = instr->InputAt(0);
1523       DCHECK(input->IsRegister() || input->IsStackSlot());
1524       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1525         __ VerifyX87StackDepth(1);
1526       }
1527       __ fstp(0);
1528       if (input->IsRegister()) {
1529         Register input_reg = i.InputRegister(0);
1530         __ push(input_reg);
1531         __ fild_s(Operand(esp, 0));
1532         __ pop(input_reg);
1533       } else {
1534         __ fild_s(i.InputOperand(0));
1535       }
1536       break;
1537     }
1538     case kX87Float32ToFloat64: {
1539       InstructionOperand* input = instr->InputAt(0);
1540       if (input->IsFPRegister()) {
1541         __ sub(esp, Immediate(kDoubleSize));
1542         __ fstp_s(MemOperand(esp, 0));
1543         __ fld_s(MemOperand(esp, 0));
1544         __ add(esp, Immediate(kDoubleSize));
1545       } else {
1546         DCHECK(input->IsFPStackSlot());
1547         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1548           __ VerifyX87StackDepth(1);
1549         }
1550         __ fstp(0);
1551         __ fld_s(i.InputOperand(0));
1552       }
1553       break;
1554     }
1555     case kX87Uint32ToFloat64: {
1556       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1557         __ VerifyX87StackDepth(1);
1558       }
1559       __ fstp(0);
1560       __ LoadUint32NoSSE2(i.InputRegister(0));
1561       break;
1562     }
1563     case kX87Float32ToInt32: {
1564       if (!instr->InputAt(0)->IsFPRegister()) {
1565         __ fld_s(i.InputOperand(0));
1566       }
1567       __ TruncateX87TOSToI(i.OutputRegister(0));
1568       if (!instr->InputAt(0)->IsFPRegister()) {
1569         __ fstp(0);
1570       }
1571       break;
1572     }
1573     case kX87Float32ToUint32: {
1574       if (!instr->InputAt(0)->IsFPRegister()) {
1575         __ fld_s(i.InputOperand(0));
1576       }
1577       Label success;
1578       __ TruncateX87TOSToI(i.OutputRegister(0));
1579       __ test(i.OutputRegister(0), i.OutputRegister(0));
1580       __ j(positive, &success);
1581       // Need to reserve the input float32 data.
1582       __ fld(0);
1583       __ push(Immediate(INT32_MIN));
1584       __ fild_s(Operand(esp, 0));
1585       __ lea(esp, Operand(esp, kPointerSize));
1586       __ faddp();
1587       __ TruncateX87TOSToI(i.OutputRegister(0));
1588       __ or_(i.OutputRegister(0), Immediate(0x80000000));
1589       // Only keep input float32 data in x87 stack when return.
1590       __ fstp(0);
1591       __ bind(&success);
1592       if (!instr->InputAt(0)->IsFPRegister()) {
1593         __ fstp(0);
1594       }
1595       break;
1596     }
1597     case kX87Float64ToInt32: {
1598       if (!instr->InputAt(0)->IsFPRegister()) {
1599         __ fld_d(i.InputOperand(0));
1600       }
1601       __ TruncateX87TOSToI(i.OutputRegister(0));
1602       if (!instr->InputAt(0)->IsFPRegister()) {
1603         __ fstp(0);
1604       }
1605       break;
1606     }
1607     case kX87Float64ToFloat32: {
1608       InstructionOperand* input = instr->InputAt(0);
1609       if (input->IsFPRegister()) {
1610         __ sub(esp, Immediate(kDoubleSize));
1611         __ fstp_s(MemOperand(esp, 0));
1612         __ fld_s(MemOperand(esp, 0));
1613         __ add(esp, Immediate(kDoubleSize));
1614       } else {
1615         DCHECK(input->IsFPStackSlot());
1616         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1617           __ VerifyX87StackDepth(1);
1618         }
1619         __ fstp(0);
1620         __ fld_d(i.InputOperand(0));
1621         __ sub(esp, Immediate(kDoubleSize));
1622         __ fstp_s(MemOperand(esp, 0));
1623         __ fld_s(MemOperand(esp, 0));
1624         __ add(esp, Immediate(kDoubleSize));
1625       }
1626       break;
1627     }
1628     case kX87Float64ToUint32: {
1629       __ push_imm32(-2147483648);
1630       if (!instr->InputAt(0)->IsFPRegister()) {
1631         __ fld_d(i.InputOperand(0));
1632       }
1633       __ fild_s(Operand(esp, 0));
1634       __ fld(1);
1635       __ faddp();
1636       __ TruncateX87TOSToI(i.OutputRegister(0));
1637       __ add(esp, Immediate(kInt32Size));
1638       __ add(i.OutputRegister(), Immediate(0x80000000));
1639       __ fstp(0);
1640       if (!instr->InputAt(0)->IsFPRegister()) {
1641         __ fstp(0);
1642       }
1643       break;
1644     }
1645     case kX87Float64ExtractHighWord32: {
1646       if (instr->InputAt(0)->IsFPRegister()) {
1647         __ sub(esp, Immediate(kDoubleSize));
1648         __ fst_d(MemOperand(esp, 0));
1649         __ mov(i.OutputRegister(), MemOperand(esp, kDoubleSize / 2));
1650         __ add(esp, Immediate(kDoubleSize));
1651       } else {
1652         InstructionOperand* input = instr->InputAt(0);
1653         USE(input);
1654         DCHECK(input->IsFPStackSlot());
1655         __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
1656       }
1657       break;
1658     }
1659     case kX87Float64ExtractLowWord32: {
1660       if (instr->InputAt(0)->IsFPRegister()) {
1661         __ sub(esp, Immediate(kDoubleSize));
1662         __ fst_d(MemOperand(esp, 0));
1663         __ mov(i.OutputRegister(), MemOperand(esp, 0));
1664         __ add(esp, Immediate(kDoubleSize));
1665       } else {
1666         InstructionOperand* input = instr->InputAt(0);
1667         USE(input);
1668         DCHECK(input->IsFPStackSlot());
1669         __ mov(i.OutputRegister(), i.InputOperand(0));
1670       }
1671       break;
1672     }
1673     case kX87Float64InsertHighWord32: {
1674       __ sub(esp, Immediate(kDoubleSize));
1675       __ fstp_d(MemOperand(esp, 0));
1676       __ mov(MemOperand(esp, kDoubleSize / 2), i.InputRegister(1));
1677       __ fld_d(MemOperand(esp, 0));
1678       __ add(esp, Immediate(kDoubleSize));
1679       break;
1680     }
1681     case kX87Float64InsertLowWord32: {
1682       __ sub(esp, Immediate(kDoubleSize));
1683       __ fstp_d(MemOperand(esp, 0));
1684       __ mov(MemOperand(esp, 0), i.InputRegister(1));
1685       __ fld_d(MemOperand(esp, 0));
1686       __ add(esp, Immediate(kDoubleSize));
1687       break;
1688     }
1689     case kX87Float64Sqrt: {
1690       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1691         __ VerifyX87StackDepth(1);
1692       }
1693       __ X87SetFPUCW(0x027F);
1694       __ fstp(0);
1695       __ fld_d(MemOperand(esp, 0));
1696       __ fsqrt();
1697       __ lea(esp, Operand(esp, kDoubleSize));
1698       __ X87SetFPUCW(0x037F);
1699       break;
1700     }
1701     case kX87Float64Round: {
1702       RoundingMode mode =
1703           static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
1704       // Set the correct round mode in x87 control register
1705       __ X87SetRC((mode << 10));
1706 
1707       if (!instr->InputAt(0)->IsFPRegister()) {
1708         InstructionOperand* input = instr->InputAt(0);
1709         USE(input);
1710         DCHECK(input->IsFPStackSlot());
1711         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1712           __ VerifyX87StackDepth(1);
1713         }
1714         __ fstp(0);
1715         __ fld_d(i.InputOperand(0));
1716       }
1717       __ frndint();
1718       __ X87SetRC(0x0000);
1719       break;
1720     }
1721     case kX87Float64Cmp: {
1722       __ fld_d(MemOperand(esp, kDoubleSize));
1723       __ fld_d(MemOperand(esp, 0));
1724       __ FCmp();
1725       __ lea(esp, Operand(esp, 2 * kDoubleSize));
1726       break;
1727     }
1728     case kX87Float64SilenceNaN: {
1729       Label end, return_qnan;
1730       __ fstp(0);
1731       __ push(ebx);
1732       // Load Half word of HoleNan(SNaN) into ebx
1733       __ mov(ebx, MemOperand(esp, 2 * kInt32Size));
1734       __ cmp(ebx, Immediate(kHoleNanUpper32));
1735       // Check input is HoleNaN(SNaN)?
1736       __ j(equal, &return_qnan, Label::kNear);
1737       // If input isn't HoleNaN(SNaN), just load it and return
1738       __ fld_d(MemOperand(esp, 1 * kInt32Size));
1739       __ jmp(&end);
1740       __ bind(&return_qnan);
1741       // If input is HoleNaN(SNaN), Return QNaN
1742       __ push(Immediate(0xffffffff));
1743       __ push(Immediate(0xfff7ffff));
1744       __ fld_d(MemOperand(esp, 0));
1745       __ lea(esp, Operand(esp, kDoubleSize));
1746       __ bind(&end);
1747       __ pop(ebx);
1748       // Clear stack.
1749       __ lea(esp, Operand(esp, 1 * kDoubleSize));
1750       break;
1751     }
1752     case kX87Movsxbl:
1753       __ movsx_b(i.OutputRegister(), i.MemoryOperand());
1754       break;
1755     case kX87Movzxbl:
1756       __ movzx_b(i.OutputRegister(), i.MemoryOperand());
1757       break;
1758     case kX87Movb: {
1759       size_t index = 0;
1760       Operand operand = i.MemoryOperand(&index);
1761       if (HasImmediateInput(instr, index)) {
1762         __ mov_b(operand, i.InputInt8(index));
1763       } else {
1764         __ mov_b(operand, i.InputRegister(index));
1765       }
1766       break;
1767     }
1768     case kX87Movsxwl:
1769       __ movsx_w(i.OutputRegister(), i.MemoryOperand());
1770       break;
1771     case kX87Movzxwl:
1772       __ movzx_w(i.OutputRegister(), i.MemoryOperand());
1773       break;
1774     case kX87Movw: {
1775       size_t index = 0;
1776       Operand operand = i.MemoryOperand(&index);
1777       if (HasImmediateInput(instr, index)) {
1778         __ mov_w(operand, i.InputInt16(index));
1779       } else {
1780         __ mov_w(operand, i.InputRegister(index));
1781       }
1782       break;
1783     }
1784     case kX87Movl:
1785       if (instr->HasOutput()) {
1786         __ mov(i.OutputRegister(), i.MemoryOperand());
1787       } else {
1788         size_t index = 0;
1789         Operand operand = i.MemoryOperand(&index);
1790         if (HasImmediateInput(instr, index)) {
1791           __ mov(operand, i.InputImmediate(index));
1792         } else {
1793           __ mov(operand, i.InputRegister(index));
1794         }
1795       }
1796       break;
1797     case kX87Movsd: {
1798       if (instr->HasOutput()) {
1799         X87Register output = i.OutputDoubleRegister();
1800         USE(output);
1801         DCHECK(output.code() == 0);
1802         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1803           __ VerifyX87StackDepth(1);
1804         }
1805         __ fstp(0);
1806         __ fld_d(i.MemoryOperand());
1807       } else {
1808         size_t index = 0;
1809         Operand operand = i.MemoryOperand(&index);
1810         __ fst_d(operand);
1811       }
1812       break;
1813     }
1814     case kX87Movss: {
1815       if (instr->HasOutput()) {
1816         X87Register output = i.OutputDoubleRegister();
1817         USE(output);
1818         DCHECK(output.code() == 0);
1819         if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1820           __ VerifyX87StackDepth(1);
1821         }
1822         __ fstp(0);
1823         __ fld_s(i.MemoryOperand());
1824       } else {
1825         size_t index = 0;
1826         Operand operand = i.MemoryOperand(&index);
1827         __ fst_s(operand);
1828       }
1829       break;
1830     }
1831     case kX87BitcastFI: {
1832       __ mov(i.OutputRegister(), MemOperand(esp, 0));
1833       __ lea(esp, Operand(esp, kFloatSize));
1834       break;
1835     }
1836     case kX87BitcastIF: {
1837       if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1838         __ VerifyX87StackDepth(1);
1839       }
1840       __ fstp(0);
1841       if (instr->InputAt(0)->IsRegister()) {
1842         __ lea(esp, Operand(esp, -kFloatSize));
1843         __ mov(MemOperand(esp, 0), i.InputRegister(0));
1844         __ fld_s(MemOperand(esp, 0));
1845         __ lea(esp, Operand(esp, kFloatSize));
1846       } else {
1847         __ fld_s(i.InputOperand(0));
1848       }
1849       break;
1850     }
1851     case kX87Lea: {
1852       AddressingMode mode = AddressingModeField::decode(instr->opcode());
1853       // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1854       // and addressing mode just happens to work out. The "addl"/"subl" forms
1855       // in these cases are faster based on measurements.
1856       if (mode == kMode_MI) {
1857         __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
1858       } else if (i.InputRegister(0).is(i.OutputRegister())) {
1859         if (mode == kMode_MRI) {
1860           int32_t constant_summand = i.InputInt32(1);
1861           if (constant_summand > 0) {
1862             __ add(i.OutputRegister(), Immediate(constant_summand));
1863           } else if (constant_summand < 0) {
1864             __ sub(i.OutputRegister(), Immediate(-constant_summand));
1865           }
1866         } else if (mode == kMode_MR1) {
1867           if (i.InputRegister(1).is(i.OutputRegister())) {
1868             __ shl(i.OutputRegister(), 1);
1869           } else {
1870             __ add(i.OutputRegister(), i.InputRegister(1));
1871           }
1872         } else if (mode == kMode_M2) {
1873           __ shl(i.OutputRegister(), 1);
1874         } else if (mode == kMode_M4) {
1875           __ shl(i.OutputRegister(), 2);
1876         } else if (mode == kMode_M8) {
1877           __ shl(i.OutputRegister(), 3);
1878         } else {
1879           __ lea(i.OutputRegister(), i.MemoryOperand());
1880         }
1881       } else if (mode == kMode_MR1 &&
1882                  i.InputRegister(1).is(i.OutputRegister())) {
1883         __ add(i.OutputRegister(), i.InputRegister(0));
1884       } else {
1885         __ lea(i.OutputRegister(), i.MemoryOperand());
1886       }
1887       break;
1888     }
1889     case kX87Push:
1890       if (instr->InputAt(0)->IsFPRegister()) {
1891         auto allocated = AllocatedOperand::cast(*instr->InputAt(0));
1892         if (allocated.representation() == MachineRepresentation::kFloat32) {
1893           __ sub(esp, Immediate(kFloatSize));
1894           __ fst_s(Operand(esp, 0));
1895           frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
1896         } else {
1897           DCHECK(allocated.representation() == MachineRepresentation::kFloat64);
1898           __ sub(esp, Immediate(kDoubleSize));
1899           __ fst_d(Operand(esp, 0));
1900         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1901         }
1902       } else if (instr->InputAt(0)->IsFPStackSlot()) {
1903         auto allocated = AllocatedOperand::cast(*instr->InputAt(0));
1904         if (allocated.representation() == MachineRepresentation::kFloat32) {
1905           __ sub(esp, Immediate(kFloatSize));
1906           __ fld_s(i.InputOperand(0));
1907           __ fstp_s(MemOperand(esp, 0));
1908           frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
1909         } else {
1910           DCHECK(allocated.representation() == MachineRepresentation::kFloat64);
1911           __ sub(esp, Immediate(kDoubleSize));
1912           __ fld_d(i.InputOperand(0));
1913           __ fstp_d(MemOperand(esp, 0));
1914         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1915         }
1916       } else if (HasImmediateInput(instr, 0)) {
1917         __ push(i.InputImmediate(0));
1918         frame_access_state()->IncreaseSPDelta(1);
1919       } else {
1920         __ push(i.InputOperand(0));
1921         frame_access_state()->IncreaseSPDelta(1);
1922       }
1923       break;
1924     case kX87Poke: {
1925       int const slot = MiscField::decode(instr->opcode());
1926       if (HasImmediateInput(instr, 0)) {
1927         __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
1928       } else {
1929         __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0));
1930       }
1931       break;
1932     }
1933     case kX87Xchgb: {
1934       size_t index = 0;
1935       Operand operand = i.MemoryOperand(&index);
1936       __ xchg_b(i.InputRegister(index), operand);
1937       break;
1938     }
1939     case kX87Xchgw: {
1940       size_t index = 0;
1941       Operand operand = i.MemoryOperand(&index);
1942       __ xchg_w(i.InputRegister(index), operand);
1943       break;
1944     }
1945     case kX87Xchgl: {
1946       size_t index = 0;
1947       Operand operand = i.MemoryOperand(&index);
1948       __ xchg(i.InputRegister(index), operand);
1949       break;
1950     }
1951     case kX87PushFloat32:
1952       __ lea(esp, Operand(esp, -kFloatSize));
1953       if (instr->InputAt(0)->IsFPStackSlot()) {
1954         __ fld_s(i.InputOperand(0));
1955         __ fstp_s(MemOperand(esp, 0));
1956       } else if (instr->InputAt(0)->IsFPRegister()) {
1957         __ fst_s(MemOperand(esp, 0));
1958       } else {
1959         UNREACHABLE();
1960       }
1961       break;
1962     case kX87PushFloat64:
1963       __ lea(esp, Operand(esp, -kDoubleSize));
1964       if (instr->InputAt(0)->IsFPStackSlot()) {
1965         __ fld_d(i.InputOperand(0));
1966         __ fstp_d(MemOperand(esp, 0));
1967       } else if (instr->InputAt(0)->IsFPRegister()) {
1968         __ fst_d(MemOperand(esp, 0));
1969       } else {
1970         UNREACHABLE();
1971       }
1972       break;
1973     case kCheckedLoadInt8:
1974       ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
1975       break;
1976     case kCheckedLoadUint8:
1977       ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
1978       break;
1979     case kCheckedLoadInt16:
1980       ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
1981       break;
1982     case kCheckedLoadUint16:
1983       ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
1984       break;
1985     case kCheckedLoadWord32:
1986       ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
1987       break;
1988     case kCheckedLoadFloat32:
1989       ASSEMBLE_CHECKED_LOAD_FLOAT(fld_s, OutOfLineLoadFloat32NaN);
1990       break;
1991     case kCheckedLoadFloat64:
1992       ASSEMBLE_CHECKED_LOAD_FLOAT(fld_d, OutOfLineLoadFloat64NaN);
1993       break;
1994     case kCheckedStoreWord8:
1995       ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
1996       break;
1997     case kCheckedStoreWord16:
1998       ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
1999       break;
2000     case kCheckedStoreWord32:
2001       ASSEMBLE_CHECKED_STORE_INTEGER(mov);
2002       break;
2003     case kCheckedStoreFloat32:
2004       ASSEMBLE_CHECKED_STORE_FLOAT(fst_s);
2005       break;
2006     case kCheckedStoreFloat64:
2007       ASSEMBLE_CHECKED_STORE_FLOAT(fst_d);
2008       break;
2009     case kX87StackCheck: {
2010       ExternalReference const stack_limit =
2011           ExternalReference::address_of_stack_limit(isolate());
2012       __ cmp(esp, Operand::StaticVariable(stack_limit));
2013       break;
2014     }
2015     case kCheckedLoadWord64:
2016     case kCheckedStoreWord64:
2017       UNREACHABLE();  // currently unsupported checked int64 load/store.
2018       break;
2019     case kAtomicLoadInt8:
2020     case kAtomicLoadUint8:
2021     case kAtomicLoadInt16:
2022     case kAtomicLoadUint16:
2023     case kAtomicLoadWord32:
2024     case kAtomicStoreWord8:
2025     case kAtomicStoreWord16:
2026     case kAtomicStoreWord32:
2027       UNREACHABLE();  // Won't be generated by instruction selector.
2028       break;
2029   }
2030   return kSuccess;
2031 }  // NOLINT(readability/fn_size)
2032 
2033 
2034 // Assembles a branch after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)2035 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
2036   X87OperandConverter i(this, instr);
2037   Label::Distance flabel_distance =
2038       branch->fallthru ? Label::kNear : Label::kFar;
2039 
2040   Label done;
2041   Label tlabel_tmp;
2042   Label flabel_tmp;
2043   Label* tlabel = &tlabel_tmp;
2044   Label* flabel = &flabel_tmp;
2045 
2046   Label* tlabel_dst = branch->true_label;
2047   Label* flabel_dst = branch->false_label;
2048 
2049   switch (branch->condition) {
2050     case kUnorderedEqual:
2051       __ j(parity_even, flabel, flabel_distance);
2052     // Fall through.
2053     case kEqual:
2054       __ j(equal, tlabel);
2055       break;
2056     case kUnorderedNotEqual:
2057       __ j(parity_even, tlabel);
2058     // Fall through.
2059     case kNotEqual:
2060       __ j(not_equal, tlabel);
2061       break;
2062     case kSignedLessThan:
2063       __ j(less, tlabel);
2064       break;
2065     case kSignedGreaterThanOrEqual:
2066       __ j(greater_equal, tlabel);
2067       break;
2068     case kSignedLessThanOrEqual:
2069       __ j(less_equal, tlabel);
2070       break;
2071     case kSignedGreaterThan:
2072       __ j(greater, tlabel);
2073       break;
2074     case kUnsignedLessThan:
2075       __ j(below, tlabel);
2076       break;
2077     case kUnsignedGreaterThanOrEqual:
2078       __ j(above_equal, tlabel);
2079       break;
2080     case kUnsignedLessThanOrEqual:
2081       __ j(below_equal, tlabel);
2082       break;
2083     case kUnsignedGreaterThan:
2084       __ j(above, tlabel);
2085       break;
2086     case kOverflow:
2087       __ j(overflow, tlabel);
2088       break;
2089     case kNotOverflow:
2090       __ j(no_overflow, tlabel);
2091       break;
2092     default:
2093       UNREACHABLE();
2094       break;
2095   }
2096   // Add a jump if not falling through to the next block.
2097   if (!branch->fallthru) __ jmp(flabel);
2098 
2099   __ jmp(&done);
2100   __ bind(&tlabel_tmp);
2101   FlagsMode mode = FlagsModeField::decode(instr->opcode());
2102   if (mode == kFlags_deoptimize) {
2103     int double_register_param_count = 0;
2104     int x87_layout = 0;
2105     for (size_t i = 0; i < instr->InputCount(); i++) {
2106       if (instr->InputAt(i)->IsFPRegister()) {
2107         double_register_param_count++;
2108       }
2109     }
2110     // Currently we use only one X87 register. If double_register_param_count
2111     // is bigger than 1, it means duplicated double register is added to input
2112     // of this instruction.
2113     if (double_register_param_count > 0) {
2114       x87_layout = (0 << 3) | 1;
2115     }
2116     // The layout of x87 register stack is loaded on the top of FPU register
2117     // stack for deoptimization.
2118     __ push(Immediate(x87_layout));
2119     __ fild_s(MemOperand(esp, 0));
2120     __ lea(esp, Operand(esp, kPointerSize));
2121   }
2122   __ jmp(tlabel_dst);
2123   __ bind(&flabel_tmp);
2124   __ jmp(flabel_dst);
2125   __ bind(&done);
2126 }
2127 
2128 
AssembleArchJump(RpoNumber target)2129 void CodeGenerator::AssembleArchJump(RpoNumber target) {
2130   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
2131 }
2132 
2133 
2134 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)2135 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2136                                         FlagsCondition condition) {
2137   X87OperandConverter i(this, instr);
2138   Label done;
2139 
2140   // Materialize a full 32-bit 1 or 0 value. The result register is always the
2141   // last output of the instruction.
2142   Label check;
2143   DCHECK_NE(0u, instr->OutputCount());
2144   Register reg = i.OutputRegister(instr->OutputCount() - 1);
2145   Condition cc = no_condition;
2146   switch (condition) {
2147     case kUnorderedEqual:
2148       __ j(parity_odd, &check, Label::kNear);
2149       __ Move(reg, Immediate(0));
2150       __ jmp(&done, Label::kNear);
2151     // Fall through.
2152     case kEqual:
2153       cc = equal;
2154       break;
2155     case kUnorderedNotEqual:
2156       __ j(parity_odd, &check, Label::kNear);
2157       __ mov(reg, Immediate(1));
2158       __ jmp(&done, Label::kNear);
2159     // Fall through.
2160     case kNotEqual:
2161       cc = not_equal;
2162       break;
2163     case kSignedLessThan:
2164       cc = less;
2165       break;
2166     case kSignedGreaterThanOrEqual:
2167       cc = greater_equal;
2168       break;
2169     case kSignedLessThanOrEqual:
2170       cc = less_equal;
2171       break;
2172     case kSignedGreaterThan:
2173       cc = greater;
2174       break;
2175     case kUnsignedLessThan:
2176       cc = below;
2177       break;
2178     case kUnsignedGreaterThanOrEqual:
2179       cc = above_equal;
2180       break;
2181     case kUnsignedLessThanOrEqual:
2182       cc = below_equal;
2183       break;
2184     case kUnsignedGreaterThan:
2185       cc = above;
2186       break;
2187     case kOverflow:
2188       cc = overflow;
2189       break;
2190     case kNotOverflow:
2191       cc = no_overflow;
2192       break;
2193     default:
2194       UNREACHABLE();
2195       break;
2196   }
2197   __ bind(&check);
2198   if (reg.is_byte_register()) {
2199     // setcc for byte registers (al, bl, cl, dl).
2200     __ setcc(cc, reg);
2201     __ movzx_b(reg, reg);
2202   } else {
2203     // Emit a branch to set a register to either 1 or 0.
2204     Label set;
2205     __ j(cc, &set, Label::kNear);
2206     __ Move(reg, Immediate(0));
2207     __ jmp(&done, Label::kNear);
2208     __ bind(&set);
2209     __ mov(reg, Immediate(1));
2210   }
2211   __ bind(&done);
2212 }
2213 
2214 
AssembleArchLookupSwitch(Instruction * instr)2215 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
2216   X87OperandConverter i(this, instr);
2217   Register input = i.InputRegister(0);
2218   for (size_t index = 2; index < instr->InputCount(); index += 2) {
2219     __ cmp(input, Immediate(i.InputInt32(index + 0)));
2220     __ j(equal, GetLabel(i.InputRpo(index + 1)));
2221   }
2222   AssembleArchJump(i.InputRpo(1));
2223 }
2224 
2225 
AssembleArchTableSwitch(Instruction * instr)2226 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2227   X87OperandConverter i(this, instr);
2228   Register input = i.InputRegister(0);
2229   size_t const case_count = instr->InputCount() - 2;
2230   Label** cases = zone()->NewArray<Label*>(case_count);
2231   for (size_t index = 0; index < case_count; ++index) {
2232     cases[index] = GetLabel(i.InputRpo(index + 2));
2233   }
2234   Label* const table = AddJumpTable(cases, case_count);
2235   __ cmp(input, Immediate(case_count));
2236   __ j(above_equal, GetLabel(i.InputRpo(1)));
2237   __ jmp(Operand::JumpTable(input, times_4, table));
2238 }
2239 
AssembleDeoptimizerCall(int deoptimization_id,Deoptimizer::BailoutType bailout_type,SourcePosition pos)2240 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
2241     int deoptimization_id, Deoptimizer::BailoutType bailout_type,
2242     SourcePosition pos) {
2243   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
2244       isolate(), deoptimization_id, bailout_type);
2245   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
2246   DeoptimizeReason deoptimization_reason =
2247       GetDeoptimizationReason(deoptimization_id);
2248   __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
2249   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
2250   return kSuccess;
2251 }
2252 
2253 
2254 // The calling convention for JSFunctions on X87 passes arguments on the
2255 // stack and the JSFunction and context in EDI and ESI, respectively, thus
2256 // the steps of the call look as follows:
2257 
2258 // --{ before the call instruction }--------------------------------------------
2259 //                                                         |  caller frame |
2260 //                                                         ^ esp           ^ ebp
2261 
2262 // --{ push arguments and setup ESI, EDI }--------------------------------------
2263 //                                       | args + receiver |  caller frame |
2264 //                                       ^ esp                             ^ ebp
2265 //                 [edi = JSFunction, esi = context]
2266 
2267 // --{ call [edi + kCodeEntryOffset] }------------------------------------------
2268 //                                 | RET | args + receiver |  caller frame |
2269 //                                 ^ esp                                   ^ ebp
2270 
2271 // =={ prologue of called function }============================================
2272 // --{ push ebp }---------------------------------------------------------------
2273 //                            | FP | RET | args + receiver |  caller frame |
2274 //                            ^ esp                                        ^ ebp
2275 
2276 // --{ mov ebp, esp }-----------------------------------------------------------
2277 //                            | FP | RET | args + receiver |  caller frame |
2278 //                            ^ ebp,esp
2279 
2280 // --{ push esi }---------------------------------------------------------------
2281 //                      | CTX | FP | RET | args + receiver |  caller frame |
2282 //                      ^esp  ^ ebp
2283 
2284 // --{ push edi }---------------------------------------------------------------
2285 //                | FNC | CTX | FP | RET | args + receiver |  caller frame |
2286 //                ^esp        ^ ebp
2287 
2288 // --{ subi esp, #N }-----------------------------------------------------------
2289 // | callee frame | FNC | CTX | FP | RET | args + receiver |  caller frame |
2290 // ^esp                       ^ ebp
2291 
2292 // =={ body of called function }================================================
2293 
2294 // =={ epilogue of called function }============================================
2295 // --{ mov esp, ebp }-----------------------------------------------------------
2296 //                            | FP | RET | args + receiver |  caller frame |
2297 //                            ^ esp,ebp
2298 
2299 // --{ pop ebp }-----------------------------------------------------------
2300 // |                               | RET | args + receiver |  caller frame |
2301 //                                 ^ esp                                   ^ ebp
2302 
2303 // --{ ret #A+1 }-----------------------------------------------------------
2304 // |                                                       |  caller frame |
2305 //                                                         ^ esp           ^ ebp
2306 
2307 
2308 // Runtime function calls are accomplished by doing a stub call to the
2309 // CEntryStub (a real code object). On X87 passes arguments on the
2310 // stack, the number of arguments in EAX, the address of the runtime function
2311 // in EBX, and the context in ESI.
2312 
2313 // --{ before the call instruction }--------------------------------------------
2314 //                                                         |  caller frame |
2315 //                                                         ^ esp           ^ ebp
2316 
2317 // --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
2318 //                                       | args + receiver |  caller frame |
2319 //                                       ^ esp                             ^ ebp
2320 //              [eax = #args, ebx = runtime function, esi = context]
2321 
2322 // --{ call #CEntryStub }-------------------------------------------------------
2323 //                                 | RET | args + receiver |  caller frame |
2324 //                                 ^ esp                                   ^ ebp
2325 
2326 // =={ body of runtime function }===============================================
2327 
2328 // --{ runtime returns }--------------------------------------------------------
2329 //                                                         |  caller frame |
2330 //                                                         ^ esp           ^ ebp
2331 
2332 // Other custom linkages (e.g. for calling directly into and out of C++) may
2333 // need to save callee-saved registers on the stack, which is done in the
2334 // function prologue of generated code.
2335 
2336 // --{ before the call instruction }--------------------------------------------
2337 //                                                         |  caller frame |
2338 //                                                         ^ esp           ^ ebp
2339 
2340 // --{ set up arguments in registers on stack }---------------------------------
2341 //                                                  | args |  caller frame |
2342 //                                                  ^ esp                  ^ ebp
2343 //                  [r0 = arg0, r1 = arg1, ...]
2344 
2345 // --{ call code }--------------------------------------------------------------
2346 //                                            | RET | args |  caller frame |
2347 //                                            ^ esp                        ^ ebp
2348 
2349 // =={ prologue of called function }============================================
2350 // --{ push ebp }---------------------------------------------------------------
2351 //                                       | FP | RET | args |  caller frame |
2352 //                                       ^ esp                             ^ ebp
2353 
2354 // --{ mov ebp, esp }-----------------------------------------------------------
2355 //                                       | FP | RET | args |  caller frame |
2356 //                                       ^ ebp,esp
2357 
2358 // --{ save registers }---------------------------------------------------------
2359 //                                | regs | FP | RET | args |  caller frame |
2360 //                                ^ esp  ^ ebp
2361 
2362 // --{ subi esp, #N }-----------------------------------------------------------
2363 //                 | callee frame | regs | FP | RET | args |  caller frame |
2364 //                 ^esp                  ^ ebp
2365 
2366 // =={ body of called function }================================================
2367 
2368 // =={ epilogue of called function }============================================
2369 // --{ restore registers }------------------------------------------------------
2370 //                                | regs | FP | RET | args |  caller frame |
2371 //                                ^ esp  ^ ebp
2372 
2373 // --{ mov esp, ebp }-----------------------------------------------------------
2374 //                                       | FP | RET | args |  caller frame |
2375 //                                       ^ esp,ebp
2376 
2377 // --{ pop ebp }----------------------------------------------------------------
2378 //                                            | RET | args |  caller frame |
2379 //                                            ^ esp                        ^ ebp
2380 
FinishFrame(Frame * frame)2381 void CodeGenerator::FinishFrame(Frame* frame) {
2382   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2383   const RegList saves = descriptor->CalleeSavedRegisters();
2384   if (saves != 0) {  // Save callee-saved registers.
2385     DCHECK(!info()->is_osr());
2386     int pushed = 0;
2387     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
2388       if (!((1 << i) & saves)) continue;
2389       ++pushed;
2390     }
2391     frame->AllocateSavedCalleeRegisterSlots(pushed);
2392   }
2393 
2394   // Initailize FPU state.
2395   __ fninit();
2396   __ fld1();
2397 }
2398 
AssembleConstructFrame()2399 void CodeGenerator::AssembleConstructFrame() {
2400   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2401   if (frame_access_state()->has_frame()) {
2402     if (descriptor->IsCFunctionCall()) {
2403       __ push(ebp);
2404       __ mov(ebp, esp);
2405     } else if (descriptor->IsJSFunctionCall()) {
2406       __ Prologue(this->info()->GeneratePreagedPrologue());
2407       if (descriptor->PushArgumentCount()) {
2408         __ push(kJavaScriptCallArgCountRegister);
2409       }
2410     } else {
2411       __ StubPrologue(info()->GetOutputStackFrameType());
2412     }
2413   }
2414 
2415   int shrink_slots =
2416       frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
2417 
2418   if (info()->is_osr()) {
2419     // TurboFan OSR-compiled functions cannot be entered directly.
2420     __ Abort(kShouldNotDirectlyEnterOsrFunction);
2421 
2422     // Unoptimized code jumps directly to this entrypoint while the unoptimized
2423     // frame is still on the stack. Optimized code uses OSR values directly from
2424     // the unoptimized frame. Thus, all that needs to be done is to allocate the
2425     // remaining stack slots.
2426     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2427     osr_pc_offset_ = __ pc_offset();
2428     shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
2429 
2430     // Initailize FPU state.
2431     __ fninit();
2432     __ fld1();
2433   }
2434 
2435   const RegList saves = descriptor->CalleeSavedRegisters();
2436   if (shrink_slots > 0) {
2437     __ sub(esp, Immediate(shrink_slots * kPointerSize));
2438   }
2439 
2440   if (saves != 0) {  // Save callee-saved registers.
2441     DCHECK(!info()->is_osr());
2442     int pushed = 0;
2443     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
2444       if (!((1 << i) & saves)) continue;
2445       __ push(Register::from_code(i));
2446       ++pushed;
2447     }
2448   }
2449 }
2450 
AssembleReturn(InstructionOperand * pop)2451 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
2452   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2453 
2454   // Clear the FPU stack only if there is no return value in the stack.
2455   if (FLAG_debug_code && FLAG_enable_slow_asserts) {
2456     __ VerifyX87StackDepth(1);
2457   }
2458   bool clear_stack = true;
2459   for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
2460     MachineRepresentation rep = descriptor->GetReturnType(i).representation();
2461     LinkageLocation loc = descriptor->GetReturnLocation(i);
2462     if (IsFloatingPoint(rep) && loc == LinkageLocation::ForRegister(0)) {
2463       clear_stack = false;
2464       break;
2465     }
2466   }
2467   if (clear_stack) __ fstp(0);
2468 
2469   const RegList saves = descriptor->CalleeSavedRegisters();
2470   // Restore registers.
2471   if (saves != 0) {
2472     for (int i = 0; i < Register::kNumRegisters; i++) {
2473       if (!((1 << i) & saves)) continue;
2474       __ pop(Register::from_code(i));
2475     }
2476   }
2477 
2478   // Might need ecx for scratch if pop_size is too big or if there is a variable
2479   // pop count.
2480   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
2481   size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
2482   X87OperandConverter g(this, nullptr);
2483   if (descriptor->IsCFunctionCall()) {
2484     AssembleDeconstructFrame();
2485   } else if (frame_access_state()->has_frame()) {
2486     // Canonicalize JSFunction return sites for now if they always have the same
2487     // number of return args.
2488     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
2489       if (return_label_.is_bound()) {
2490         __ jmp(&return_label_);
2491         return;
2492       } else {
2493         __ bind(&return_label_);
2494         AssembleDeconstructFrame();
2495       }
2496     } else {
2497       AssembleDeconstructFrame();
2498     }
2499   }
2500   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & edx.bit());
2501   DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
2502   if (pop->IsImmediate()) {
2503     DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
2504     pop_size += g.ToConstant(pop).ToInt32() * kPointerSize;
2505     __ Ret(static_cast<int>(pop_size), ecx);
2506   } else {
2507     Register pop_reg = g.ToRegister(pop);
2508     Register scratch_reg = pop_reg.is(ecx) ? edx : ecx;
2509     __ pop(scratch_reg);
2510     __ lea(esp, Operand(esp, pop_reg, times_4, static_cast<int>(pop_size)));
2511     __ jmp(scratch_reg);
2512   }
2513 }
2514 
2515 
AssembleMove(InstructionOperand * source,InstructionOperand * destination)2516 void CodeGenerator::AssembleMove(InstructionOperand* source,
2517                                  InstructionOperand* destination) {
2518   X87OperandConverter g(this, nullptr);
2519   // Dispatch on the source and destination operand kinds.  Not all
2520   // combinations are possible.
2521   if (source->IsRegister()) {
2522     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2523     Register src = g.ToRegister(source);
2524     Operand dst = g.ToOperand(destination);
2525     __ mov(dst, src);
2526   } else if (source->IsStackSlot()) {
2527     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2528     Operand src = g.ToOperand(source);
2529     if (destination->IsRegister()) {
2530       Register dst = g.ToRegister(destination);
2531       __ mov(dst, src);
2532     } else {
2533       Operand dst = g.ToOperand(destination);
2534       __ push(src);
2535       __ pop(dst);
2536     }
2537   } else if (source->IsConstant()) {
2538     Constant src_constant = g.ToConstant(source);
2539     if (src_constant.type() == Constant::kHeapObject) {
2540       Handle<HeapObject> src = src_constant.ToHeapObject();
2541       if (destination->IsRegister()) {
2542         Register dst = g.ToRegister(destination);
2543         __ LoadHeapObject(dst, src);
2544       } else {
2545         DCHECK(destination->IsStackSlot());
2546         Operand dst = g.ToOperand(destination);
2547         AllowDeferredHandleDereference embedding_raw_address;
2548         if (isolate()->heap()->InNewSpace(*src)) {
2549           __ PushHeapObject(src);
2550           __ pop(dst);
2551         } else {
2552           __ mov(dst, src);
2553         }
2554       }
2555     } else if (destination->IsRegister()) {
2556       Register dst = g.ToRegister(destination);
2557       __ Move(dst, g.ToImmediate(source));
2558     } else if (destination->IsStackSlot()) {
2559       Operand dst = g.ToOperand(destination);
2560       __ Move(dst, g.ToImmediate(source));
2561     } else if (src_constant.type() == Constant::kFloat32) {
2562       // TODO(turbofan): Can we do better here?
2563       uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
2564       if (destination->IsFPRegister()) {
2565         __ sub(esp, Immediate(kInt32Size));
2566         __ mov(MemOperand(esp, 0), Immediate(src));
2567         // always only push one value into the x87 stack.
2568         __ fstp(0);
2569         __ fld_s(MemOperand(esp, 0));
2570         __ add(esp, Immediate(kInt32Size));
2571       } else {
2572         DCHECK(destination->IsFPStackSlot());
2573         Operand dst = g.ToOperand(destination);
2574         __ Move(dst, Immediate(src));
2575       }
2576     } else {
2577       DCHECK_EQ(Constant::kFloat64, src_constant.type());
2578       uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
2579       uint32_t lower = static_cast<uint32_t>(src);
2580       uint32_t upper = static_cast<uint32_t>(src >> 32);
2581       if (destination->IsFPRegister()) {
2582         __ sub(esp, Immediate(kDoubleSize));
2583         __ mov(MemOperand(esp, 0), Immediate(lower));
2584         __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
2585         // always only push one value into the x87 stack.
2586         __ fstp(0);
2587         __ fld_d(MemOperand(esp, 0));
2588         __ add(esp, Immediate(kDoubleSize));
2589       } else {
2590         DCHECK(destination->IsFPStackSlot());
2591         Operand dst0 = g.ToOperand(destination);
2592         Operand dst1 = g.HighOperand(destination);
2593         __ Move(dst0, Immediate(lower));
2594         __ Move(dst1, Immediate(upper));
2595       }
2596     }
2597   } else if (source->IsFPRegister()) {
2598     DCHECK(destination->IsFPStackSlot());
2599     Operand dst = g.ToOperand(destination);
2600     auto allocated = AllocatedOperand::cast(*source);
2601     switch (allocated.representation()) {
2602       case MachineRepresentation::kFloat32:
2603         __ fst_s(dst);
2604         break;
2605       case MachineRepresentation::kFloat64:
2606         __ fst_d(dst);
2607         break;
2608       default:
2609         UNREACHABLE();
2610     }
2611   } else if (source->IsFPStackSlot()) {
2612     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
2613     Operand src = g.ToOperand(source);
2614     auto allocated = AllocatedOperand::cast(*source);
2615     if (destination->IsFPRegister()) {
2616       // always only push one value into the x87 stack.
2617       __ fstp(0);
2618       switch (allocated.representation()) {
2619         case MachineRepresentation::kFloat32:
2620           __ fld_s(src);
2621           break;
2622         case MachineRepresentation::kFloat64:
2623           __ fld_d(src);
2624           break;
2625         default:
2626           UNREACHABLE();
2627       }
2628     } else {
2629       Operand dst = g.ToOperand(destination);
2630       switch (allocated.representation()) {
2631         case MachineRepresentation::kFloat32:
2632           __ fld_s(src);
2633           __ fstp_s(dst);
2634           break;
2635         case MachineRepresentation::kFloat64:
2636           __ fld_d(src);
2637           __ fstp_d(dst);
2638           break;
2639         default:
2640           UNREACHABLE();
2641       }
2642     }
2643   } else {
2644     UNREACHABLE();
2645   }
2646 }
2647 
2648 
AssembleSwap(InstructionOperand * source,InstructionOperand * destination)2649 void CodeGenerator::AssembleSwap(InstructionOperand* source,
2650                                  InstructionOperand* destination) {
2651   X87OperandConverter g(this, nullptr);
2652   // Dispatch on the source and destination operand kinds.  Not all
2653   // combinations are possible.
2654   if (source->IsRegister() && destination->IsRegister()) {
2655     // Register-register.
2656     Register src = g.ToRegister(source);
2657     Register dst = g.ToRegister(destination);
2658     __ xchg(dst, src);
2659   } else if (source->IsRegister() && destination->IsStackSlot()) {
2660     // Register-memory.
2661     __ xchg(g.ToRegister(source), g.ToOperand(destination));
2662   } else if (source->IsStackSlot() && destination->IsStackSlot()) {
2663     // Memory-memory.
2664     Operand dst1 = g.ToOperand(destination);
2665     __ push(dst1);
2666     frame_access_state()->IncreaseSPDelta(1);
2667     Operand src1 = g.ToOperand(source);
2668     __ push(src1);
2669     Operand dst2 = g.ToOperand(destination);
2670     __ pop(dst2);
2671     frame_access_state()->IncreaseSPDelta(-1);
2672     Operand src2 = g.ToOperand(source);
2673     __ pop(src2);
2674   } else if (source->IsFPRegister() && destination->IsFPRegister()) {
2675     UNREACHABLE();
2676   } else if (source->IsFPRegister() && destination->IsFPStackSlot()) {
2677     auto allocated = AllocatedOperand::cast(*source);
2678     switch (allocated.representation()) {
2679       case MachineRepresentation::kFloat32:
2680         __ fld_s(g.ToOperand(destination));
2681         __ fxch();
2682         __ fstp_s(g.ToOperand(destination));
2683         break;
2684       case MachineRepresentation::kFloat64:
2685         __ fld_d(g.ToOperand(destination));
2686         __ fxch();
2687         __ fstp_d(g.ToOperand(destination));
2688         break;
2689       default:
2690         UNREACHABLE();
2691     }
2692   } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) {
2693     auto allocated = AllocatedOperand::cast(*source);
2694     switch (allocated.representation()) {
2695       case MachineRepresentation::kFloat32:
2696         __ fld_s(g.ToOperand(source));
2697         __ fld_s(g.ToOperand(destination));
2698         __ fstp_s(g.ToOperand(source));
2699         __ fstp_s(g.ToOperand(destination));
2700         break;
2701       case MachineRepresentation::kFloat64:
2702         __ fld_d(g.ToOperand(source));
2703         __ fld_d(g.ToOperand(destination));
2704         __ fstp_d(g.ToOperand(source));
2705         __ fstp_d(g.ToOperand(destination));
2706         break;
2707       default:
2708         UNREACHABLE();
2709     }
2710   } else {
2711     // No other combinations are possible.
2712     UNREACHABLE();
2713   }
2714 }
2715 
2716 
AssembleJumpTable(Label ** targets,size_t target_count)2717 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2718   for (size_t index = 0; index < target_count; ++index) {
2719     __ dd(targets[index]);
2720   }
2721 }
2722 
2723 
EnsureSpaceForLazyDeopt()2724 void CodeGenerator::EnsureSpaceForLazyDeopt() {
2725   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2726     return;
2727   }
2728 
2729   int space_needed = Deoptimizer::patch_size();
2730   // Ensure that we have enough space after the previous lazy-bailout
2731   // instruction for patching the code here.
2732   int current_pc = masm()->pc_offset();
2733   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2734     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2735     __ Nop(padding_size);
2736   }
2737 }
2738 
2739 #undef __
2740 
2741 }  // namespace compiler
2742 }  // namespace internal
2743 }  // namespace v8
2744