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