Home | History | Annotate | Download | only in mips64
      1 // Copyright 2014 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/ast/scopes.h"
      6 #include "src/compiler/code-generator.h"
      7 #include "src/compiler/code-generator-impl.h"
      8 #include "src/compiler/gap-resolver.h"
      9 #include "src/compiler/node-matchers.h"
     10 #include "src/compiler/osr.h"
     11 #include "src/mips/macro-assembler-mips.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 namespace compiler {
     16 
     17 #define __ masm()->
     18 
     19 
     20 // TODO(plind): Possibly avoid using these lithium names.
     21 #define kScratchReg kLithiumScratchReg
     22 #define kScratchReg2 kLithiumScratchReg2
     23 #define kScratchDoubleReg kLithiumScratchDouble
     24 
     25 
     26 // TODO(plind): consider renaming these macros.
     27 #define TRACE_MSG(msg)                                                      \
     28   PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
     29          __LINE__)
     30 
     31 #define TRACE_UNIMPL()                                                       \
     32   PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
     33          __LINE__)
     34 
     35 
     36 // Adds Mips-specific methods to convert InstructionOperands.
     37 class MipsOperandConverter final : public InstructionOperandConverter {
     38  public:
     39   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
     40       : InstructionOperandConverter(gen, instr) {}
     41 
     42   FloatRegister OutputSingleRegister(size_t index = 0) {
     43     return ToSingleRegister(instr_->OutputAt(index));
     44   }
     45 
     46   FloatRegister InputSingleRegister(size_t index) {
     47     return ToSingleRegister(instr_->InputAt(index));
     48   }
     49 
     50   FloatRegister ToSingleRegister(InstructionOperand* op) {
     51     // Single (Float) and Double register namespace is same on MIPS,
     52     // both are typedefs of FPURegister.
     53     return ToDoubleRegister(op);
     54   }
     55 
     56   DoubleRegister InputOrZeroDoubleRegister(size_t index) {
     57     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
     58 
     59     return InputDoubleRegister(index);
     60   }
     61 
     62   DoubleRegister InputOrZeroSingleRegister(size_t index) {
     63     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
     64 
     65     return InputSingleRegister(index);
     66   }
     67 
     68   Operand InputImmediate(size_t index) {
     69     Constant constant = ToConstant(instr_->InputAt(index));
     70     switch (constant.type()) {
     71       case Constant::kInt32:
     72         return Operand(constant.ToInt32());
     73       case Constant::kInt64:
     74         return Operand(constant.ToInt64());
     75       case Constant::kFloat32:
     76         return Operand(
     77             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
     78       case Constant::kFloat64:
     79         return Operand(
     80             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
     81       case Constant::kExternalReference:
     82       case Constant::kHeapObject:
     83         // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
     84         //    maybe not done on arm due to const pool ??
     85         break;
     86       case Constant::kRpoNumber:
     87         UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
     88         break;
     89     }
     90     UNREACHABLE();
     91     return Operand(zero_reg);
     92   }
     93 
     94   Operand InputOperand(size_t index) {
     95     InstructionOperand* op = instr_->InputAt(index);
     96     if (op->IsRegister()) {
     97       return Operand(ToRegister(op));
     98     }
     99     return InputImmediate(index);
    100   }
    101 
    102   MemOperand MemoryOperand(size_t* first_index) {
    103     const size_t index = *first_index;
    104     switch (AddressingModeField::decode(instr_->opcode())) {
    105       case kMode_None:
    106         break;
    107       case kMode_MRI:
    108         *first_index += 2;
    109         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
    110       case kMode_MRR:
    111         // TODO(plind): r6 address mode, to be implemented ...
    112         UNREACHABLE();
    113     }
    114     UNREACHABLE();
    115     return MemOperand(no_reg);
    116   }
    117 
    118   MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
    119 
    120   MemOperand ToMemOperand(InstructionOperand* op) const {
    121     DCHECK_NOT_NULL(op);
    122     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
    123     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
    124   }
    125 
    126   MemOperand SlotToMemOperand(int slot) const {
    127     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
    128     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
    129   }
    130 };
    131 
    132 
    133 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
    134   return instr->InputAt(index)->IsRegister();
    135 }
    136 
    137 
    138 namespace {
    139 
    140 class OutOfLineLoadSingle final : public OutOfLineCode {
    141  public:
    142   OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
    143       : OutOfLineCode(gen), result_(result) {}
    144 
    145   void Generate() final {
    146     __ Move(result_, std::numeric_limits<float>::quiet_NaN());
    147   }
    148 
    149  private:
    150   FloatRegister const result_;
    151 };
    152 
    153 
    154 class OutOfLineLoadDouble final : public OutOfLineCode {
    155  public:
    156   OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
    157       : OutOfLineCode(gen), result_(result) {}
    158 
    159   void Generate() final {
    160     __ Move(result_, std::numeric_limits<double>::quiet_NaN());
    161   }
    162 
    163  private:
    164   DoubleRegister const result_;
    165 };
    166 
    167 
    168 class OutOfLineLoadInteger final : public OutOfLineCode {
    169  public:
    170   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
    171       : OutOfLineCode(gen), result_(result) {}
    172 
    173   void Generate() final { __ mov(result_, zero_reg); }
    174 
    175  private:
    176   Register const result_;
    177 };
    178 
    179 
    180 class OutOfLineRound : public OutOfLineCode {
    181  public:
    182   OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
    183       : OutOfLineCode(gen), result_(result) {}
    184 
    185   void Generate() final {
    186     // Handle rounding to zero case where sign has to be preserved.
    187     // High bits of double input already in kScratchReg.
    188     __ dsrl(at, kScratchReg, 31);
    189     __ dsll(at, at, 31);
    190     __ mthc1(at, result_);
    191   }
    192 
    193  private:
    194   DoubleRegister const result_;
    195 };
    196 
    197 
    198 class OutOfLineRound32 : public OutOfLineCode {
    199  public:
    200   OutOfLineRound32(CodeGenerator* gen, DoubleRegister result)
    201       : OutOfLineCode(gen), result_(result) {}
    202 
    203   void Generate() final {
    204     // Handle rounding to zero case where sign has to be preserved.
    205     // High bits of float input already in kScratchReg.
    206     __ srl(at, kScratchReg, 31);
    207     __ sll(at, at, 31);
    208     __ mtc1(at, result_);
    209   }
    210 
    211  private:
    212   DoubleRegister const result_;
    213 };
    214 
    215 
    216 class OutOfLineRecordWrite final : public OutOfLineCode {
    217  public:
    218   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
    219                        Register value, Register scratch0, Register scratch1,
    220                        RecordWriteMode mode)
    221       : OutOfLineCode(gen),
    222         object_(object),
    223         index_(index),
    224         value_(value),
    225         scratch0_(scratch0),
    226         scratch1_(scratch1),
    227         mode_(mode),
    228         must_save_lr_(!gen->frame_access_state()->has_frame()) {}
    229 
    230   void Generate() final {
    231     if (mode_ > RecordWriteMode::kValueIsPointer) {
    232       __ JumpIfSmi(value_, exit());
    233     }
    234     __ CheckPageFlag(value_, scratch0_,
    235                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
    236                      exit());
    237     RememberedSetAction const remembered_set_action =
    238         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
    239                                              : OMIT_REMEMBERED_SET;
    240     SaveFPRegsMode const save_fp_mode =
    241         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    242     if (must_save_lr_) {
    243       // We need to save and restore ra if the frame was elided.
    244       __ Push(ra);
    245     }
    246     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    247                          remembered_set_action, save_fp_mode);
    248     __ Daddu(scratch1_, object_, index_);
    249     __ CallStub(&stub);
    250     if (must_save_lr_) {
    251       __ Pop(ra);
    252     }
    253   }
    254 
    255  private:
    256   Register const object_;
    257   Register const index_;
    258   Register const value_;
    259   Register const scratch0_;
    260   Register const scratch1_;
    261   RecordWriteMode const mode_;
    262   bool must_save_lr_;
    263 };
    264 
    265 
    266 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
    267   switch (condition) {
    268     case kEqual:
    269       return eq;
    270     case kNotEqual:
    271       return ne;
    272     case kSignedLessThan:
    273       return lt;
    274     case kSignedGreaterThanOrEqual:
    275       return ge;
    276     case kSignedLessThanOrEqual:
    277       return le;
    278     case kSignedGreaterThan:
    279       return gt;
    280     case kUnsignedLessThan:
    281       return lo;
    282     case kUnsignedGreaterThanOrEqual:
    283       return hs;
    284     case kUnsignedLessThanOrEqual:
    285       return ls;
    286     case kUnsignedGreaterThan:
    287       return hi;
    288     case kUnorderedEqual:
    289     case kUnorderedNotEqual:
    290       break;
    291     default:
    292       break;
    293   }
    294   UNREACHABLE();
    295   return kNoCondition;
    296 }
    297 
    298 
    299 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
    300   switch (condition) {
    301     case kNotEqual:
    302       return ne;
    303     case kEqual:
    304       return eq;
    305     default:
    306       break;
    307   }
    308   UNREACHABLE();
    309   return kNoCondition;
    310 }
    311 
    312 
    313 Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
    314   switch (condition) {
    315     case kOverflow:
    316       return ne;
    317     case kNotOverflow:
    318       return eq;
    319     default:
    320       break;
    321   }
    322   UNREACHABLE();
    323   return kNoCondition;
    324 }
    325 
    326 
    327 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
    328                                              FlagsCondition condition) {
    329   switch (condition) {
    330     case kEqual:
    331       predicate = true;
    332       return EQ;
    333     case kNotEqual:
    334       predicate = false;
    335       return EQ;
    336     case kUnsignedLessThan:
    337       predicate = true;
    338       return OLT;
    339     case kUnsignedGreaterThanOrEqual:
    340       predicate = false;
    341       return ULT;
    342     case kUnsignedLessThanOrEqual:
    343       predicate = true;
    344       return OLE;
    345     case kUnsignedGreaterThan:
    346       predicate = false;
    347       return ULE;
    348     case kUnorderedEqual:
    349     case kUnorderedNotEqual:
    350       predicate = true;
    351       break;
    352     default:
    353       predicate = true;
    354       break;
    355   }
    356   UNREACHABLE();
    357   return kNoFPUCondition;
    358 }
    359 
    360 }  // namespace
    361 
    362 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
    363   do {                                                                        \
    364     auto result = i.Output##width##Register();                                \
    365     auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
    366     if (instr->InputAt(0)->IsRegister()) {                                    \
    367       auto offset = i.InputRegister(0);                                       \
    368       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
    369       __ And(kScratchReg, offset, Operand(0xffffffff));                       \
    370       __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg);                 \
    371       __ asm_instr(result, MemOperand(kScratchReg, 0));                       \
    372     } else {                                                                  \
    373       int offset = static_cast<int>(i.InputOperand(0).immediate());           \
    374       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
    375       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
    376     }                                                                         \
    377     __ bind(ool->exit());                                                     \
    378   } while (0)
    379 
    380 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
    381   do {                                                                        \
    382     auto result = i.OutputRegister();                                         \
    383     auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
    384     if (instr->InputAt(0)->IsRegister()) {                                    \
    385       auto offset = i.InputRegister(0);                                       \
    386       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
    387       __ And(kScratchReg, offset, Operand(0xffffffff));                       \
    388       __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg);                 \
    389       __ asm_instr(result, MemOperand(kScratchReg, 0));                       \
    390     } else {                                                                  \
    391       int offset = static_cast<int>(i.InputOperand(0).immediate());           \
    392       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
    393       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
    394     }                                                                         \
    395     __ bind(ool->exit());                                                     \
    396   } while (0)
    397 
    398 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
    399   do {                                                                 \
    400     Label done;                                                        \
    401     if (instr->InputAt(0)->IsRegister()) {                             \
    402       auto offset = i.InputRegister(0);                                \
    403       auto value = i.Input##width##Register(2);                        \
    404       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
    405       __ And(kScratchReg, offset, Operand(0xffffffff));                \
    406       __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg);          \
    407       __ asm_instr(value, MemOperand(kScratchReg, 0));                 \
    408     } else {                                                           \
    409       int offset = static_cast<int>(i.InputOperand(0).immediate());    \
    410       auto value = i.Input##width##Register(2);                        \
    411       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
    412       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
    413     }                                                                  \
    414     __ bind(&done);                                                    \
    415   } while (0)
    416 
    417 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
    418   do {                                                                 \
    419     Label done;                                                        \
    420     if (instr->InputAt(0)->IsRegister()) {                             \
    421       auto offset = i.InputRegister(0);                                \
    422       auto value = i.InputRegister(2);                                 \
    423       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
    424       __ And(kScratchReg, offset, Operand(0xffffffff));                \
    425       __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg);          \
    426       __ asm_instr(value, MemOperand(kScratchReg, 0));                 \
    427     } else {                                                           \
    428       int offset = static_cast<int>(i.InputOperand(0).immediate());    \
    429       auto value = i.InputRegister(2);                                 \
    430       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
    431       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
    432     }                                                                  \
    433     __ bind(&done);                                                    \
    434   } while (0)
    435 
    436 #define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode)                                  \
    437   if (kArchVariant == kMips64r6) {                                             \
    438     __ cfc1(kScratchReg, FCSR);                                                \
    439     __ li(at, Operand(mode_##mode));                                           \
    440     __ ctc1(at, FCSR);                                                         \
    441     __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
    442     __ ctc1(kScratchReg, FCSR);                                                \
    443   } else {                                                                     \
    444     auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister());    \
    445     Label done;                                                                \
    446     __ mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
    447     __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
    448            HeapNumber::kExponentBits);                                         \
    449     __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
    450               Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
    451     __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
    452     __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));         \
    453     __ dmfc1(at, i.OutputDoubleRegister());                                    \
    454     __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
    455     __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
    456     __ bind(ool->exit());                                                      \
    457     __ bind(&done);                                                            \
    458   }
    459 
    460 #define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode)                                   \
    461   if (kArchVariant == kMips64r6) {                                            \
    462     __ cfc1(kScratchReg, FCSR);                                               \
    463     __ li(at, Operand(mode_##mode));                                          \
    464     __ ctc1(at, FCSR);                                                        \
    465     __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));            \
    466     __ ctc1(kScratchReg, FCSR);                                               \
    467   } else {                                                                    \
    468     int32_t kFloat32ExponentBias = 127;                                       \
    469     int32_t kFloat32MantissaBits = 23;                                        \
    470     int32_t kFloat32ExponentBits = 8;                                         \
    471     auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
    472     Label done;                                                               \
    473     __ mfc1(kScratchReg, i.InputDoubleRegister(0));                           \
    474     __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits);      \
    475     __ Branch(USE_DELAY_SLOT, &done, hs, at,                                  \
    476               Operand(kFloat32ExponentBias + kFloat32MantissaBits));          \
    477     __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
    478     __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));        \
    479     __ mfc1(at, i.OutputDoubleRegister());                                    \
    480     __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));       \
    481     __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister());           \
    482     __ bind(ool->exit());                                                     \
    483     __ bind(&done);                                                           \
    484   }
    485 
    486 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
    487   do {                                                   \
    488     __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
    489     __ sync();                                           \
    490   } while (0)
    491 
    492 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)         \
    493   do {                                                   \
    494     __ sync();                                           \
    495     __ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
    496     __ sync();                                           \
    497   } while (0)
    498 
    499 #define ASSEMBLE_IEEE754_BINOP(name)                                          \
    500   do {                                                                        \
    501     FrameScope scope(masm(), StackFrame::MANUAL);                             \
    502     __ PrepareCallCFunction(0, 2, kScratchReg);                               \
    503     __ MovToFloatParameters(i.InputDoubleRegister(0),                         \
    504                             i.InputDoubleRegister(1));                        \
    505     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    506                      0, 2);                                                   \
    507     /* Move the result in the double result register. */                      \
    508     __ MovFromFloatResult(i.OutputDoubleRegister());                          \
    509   } while (0)
    510 
    511 #define ASSEMBLE_IEEE754_UNOP(name)                                           \
    512   do {                                                                        \
    513     FrameScope scope(masm(), StackFrame::MANUAL);                             \
    514     __ PrepareCallCFunction(0, 1, kScratchReg);                               \
    515     __ MovToFloatParameter(i.InputDoubleRegister(0));                         \
    516     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
    517                      0, 1);                                                   \
    518     /* Move the result in the double result register. */                      \
    519     __ MovFromFloatResult(i.OutputDoubleRegister());                          \
    520   } while (0)
    521 
    522 void CodeGenerator::AssembleDeconstructFrame() {
    523   __ mov(sp, fp);
    524   __ Pop(ra, fp);
    525 }
    526 
    527 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
    528   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    529   if (sp_slot_delta > 0) {
    530     __ daddiu(sp, sp, sp_slot_delta * kPointerSize);
    531   }
    532   frame_access_state()->SetFrameAccessToDefault();
    533 }
    534 
    535 
    536 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
    537   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    538   if (sp_slot_delta < 0) {
    539     __ Dsubu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
    540     frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
    541   }
    542   if (frame_access_state()->has_frame()) {
    543     __ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    544     __ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    545   }
    546   frame_access_state()->SetFrameAccessToSP();
    547 }
    548 
    549 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
    550                                                      Register scratch1,
    551                                                      Register scratch2,
    552                                                      Register scratch3) {
    553   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
    554   Label done;
    555 
    556   // Check if current frame is an arguments adaptor frame.
    557   __ ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset));
    558   __ Branch(&done, ne, scratch3,
    559             Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
    560 
    561   // Load arguments count from current arguments adaptor frame (note, it
    562   // does not include receiver).
    563   Register caller_args_count_reg = scratch1;
    564   __ ld(caller_args_count_reg,
    565         MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
    566   __ SmiUntag(caller_args_count_reg);
    567 
    568   ParameterCount callee_args_count(args_reg);
    569   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
    570                         scratch3);
    571   __ bind(&done);
    572 }
    573 
    574 // Assembles an instruction after register allocation, producing machine code.
    575 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    576     Instruction* instr) {
    577   MipsOperandConverter i(this, instr);
    578   InstructionCode opcode = instr->opcode();
    579   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
    580   switch (arch_opcode) {
    581     case kArchCallCodeObject: {
    582       EnsureSpaceForLazyDeopt();
    583       if (instr->InputAt(0)->IsImmediate()) {
    584         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
    585                 RelocInfo::CODE_TARGET);
    586       } else {
    587         __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
    588         __ Call(at);
    589       }
    590       RecordCallPosition(instr);
    591       frame_access_state()->ClearSPDelta();
    592       break;
    593     }
    594     case kArchTailCallCodeObjectFromJSFunction:
    595     case kArchTailCallCodeObject: {
    596       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    597       AssembleDeconstructActivationRecord(stack_param_delta);
    598       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
    599         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    600                                          i.TempRegister(0), i.TempRegister(1),
    601                                          i.TempRegister(2));
    602       }
    603       if (instr->InputAt(0)->IsImmediate()) {
    604         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
    605                 RelocInfo::CODE_TARGET);
    606       } else {
    607         __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
    608         __ Jump(at);
    609       }
    610       frame_access_state()->ClearSPDelta();
    611       break;
    612     }
    613     case kArchTailCallAddress: {
    614       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    615       AssembleDeconstructActivationRecord(stack_param_delta);
    616       CHECK(!instr->InputAt(0)->IsImmediate());
    617       __ Jump(i.InputRegister(0));
    618       frame_access_state()->ClearSPDelta();
    619       break;
    620     }
    621     case kArchCallJSFunction: {
    622       EnsureSpaceForLazyDeopt();
    623       Register func = i.InputRegister(0);
    624       if (FLAG_debug_code) {
    625         // Check the function's context matches the context argument.
    626         __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    627         __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
    628       }
    629       __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    630       __ Call(at);
    631       RecordCallPosition(instr);
    632       frame_access_state()->ClearSPDelta();
    633       break;
    634     }
    635     case kArchTailCallJSFunctionFromJSFunction:
    636     case kArchTailCallJSFunction: {
    637       Register func = i.InputRegister(0);
    638       if (FLAG_debug_code) {
    639         // Check the function's context matches the context argument.
    640         __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
    641         __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
    642       }
    643       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    644       AssembleDeconstructActivationRecord(stack_param_delta);
    645       if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
    646         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
    647                                          i.TempRegister(0), i.TempRegister(1),
    648                                          i.TempRegister(2));
    649       }
    650       __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    651       __ Jump(at);
    652       frame_access_state()->ClearSPDelta();
    653       break;
    654     }
    655     case kArchPrepareCallCFunction: {
    656       int const num_parameters = MiscField::decode(instr->opcode());
    657       __ PrepareCallCFunction(num_parameters, kScratchReg);
    658       // Frame alignment requires using FP-relative frame addressing.
    659       frame_access_state()->SetFrameAccessToFP();
    660       break;
    661     }
    662     case kArchPrepareTailCall:
    663       AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
    664       break;
    665     case kArchCallCFunction: {
    666       int const num_parameters = MiscField::decode(instr->opcode());
    667       if (instr->InputAt(0)->IsImmediate()) {
    668         ExternalReference ref = i.InputExternalReference(0);
    669         __ CallCFunction(ref, num_parameters);
    670       } else {
    671         Register func = i.InputRegister(0);
    672         __ CallCFunction(func, num_parameters);
    673       }
    674       frame_access_state()->SetFrameAccessToDefault();
    675       frame_access_state()->ClearSPDelta();
    676       break;
    677     }
    678     case kArchJmp:
    679       AssembleArchJump(i.InputRpo(0));
    680       break;
    681     case kArchLookupSwitch:
    682       AssembleArchLookupSwitch(instr);
    683       break;
    684     case kArchTableSwitch:
    685       AssembleArchTableSwitch(instr);
    686       break;
    687     case kArchDebugBreak:
    688       __ stop("kArchDebugBreak");
    689       break;
    690     case kArchComment: {
    691       Address comment_string = i.InputExternalReference(0).address();
    692       __ RecordComment(reinterpret_cast<const char*>(comment_string));
    693       break;
    694     }
    695     case kArchNop:
    696     case kArchThrowTerminator:
    697       // don't emit code for nops.
    698       break;
    699     case kArchDeoptimize: {
    700       int deopt_state_id =
    701           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    702       Deoptimizer::BailoutType bailout_type =
    703           Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
    704       CodeGenResult result =
    705           AssembleDeoptimizerCall(deopt_state_id, bailout_type);
    706       if (result != kSuccess) return result;
    707       break;
    708     }
    709     case kArchRet:
    710       AssembleReturn();
    711       break;
    712     case kArchStackPointer:
    713       __ mov(i.OutputRegister(), sp);
    714       break;
    715     case kArchFramePointer:
    716       __ mov(i.OutputRegister(), fp);
    717       break;
    718     case kArchParentFramePointer:
    719       if (frame_access_state()->has_frame()) {
    720         __ ld(i.OutputRegister(), MemOperand(fp, 0));
    721       } else {
    722         __ mov(i.OutputRegister(), fp);
    723       }
    724       break;
    725     case kArchTruncateDoubleToI:
    726       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
    727       break;
    728     case kArchStoreWithWriteBarrier: {
    729       RecordWriteMode mode =
    730           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    731       Register object = i.InputRegister(0);
    732       Register index = i.InputRegister(1);
    733       Register value = i.InputRegister(2);
    734       Register scratch0 = i.TempRegister(0);
    735       Register scratch1 = i.TempRegister(1);
    736       auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
    737                                                    scratch0, scratch1, mode);
    738       __ Daddu(at, object, index);
    739       __ sd(value, MemOperand(at));
    740       __ CheckPageFlag(object, scratch0,
    741                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
    742                        ool->entry());
    743       __ bind(ool->exit());
    744       break;
    745     }
    746     case kArchStackSlot: {
    747       FrameOffset offset =
    748           frame_access_state()->GetFrameOffset(i.InputInt32(0));
    749       __ Daddu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
    750                Operand(offset.offset()));
    751       break;
    752     }
    753     case kIeee754Float64Atan:
    754       ASSEMBLE_IEEE754_UNOP(atan);
    755       break;
    756     case kIeee754Float64Atan2:
    757       ASSEMBLE_IEEE754_BINOP(atan2);
    758       break;
    759     case kIeee754Float64Atanh:
    760       ASSEMBLE_IEEE754_UNOP(atanh);
    761       break;
    762     case kIeee754Float64Cos:
    763       ASSEMBLE_IEEE754_UNOP(cos);
    764       break;
    765     case kIeee754Float64Cbrt:
    766       ASSEMBLE_IEEE754_UNOP(cbrt);
    767       break;
    768     case kIeee754Float64Exp:
    769       ASSEMBLE_IEEE754_UNOP(exp);
    770       break;
    771     case kIeee754Float64Expm1:
    772       ASSEMBLE_IEEE754_UNOP(expm1);
    773       break;
    774     case kIeee754Float64Log:
    775       ASSEMBLE_IEEE754_UNOP(log);
    776       break;
    777     case kIeee754Float64Log1p:
    778       ASSEMBLE_IEEE754_UNOP(log1p);
    779       break;
    780     case kIeee754Float64Log2:
    781       ASSEMBLE_IEEE754_UNOP(log2);
    782       break;
    783     case kIeee754Float64Log10:
    784       ASSEMBLE_IEEE754_UNOP(log10);
    785       break;
    786     case kIeee754Float64Sin:
    787       ASSEMBLE_IEEE754_UNOP(sin);
    788       break;
    789     case kIeee754Float64Tan:
    790       ASSEMBLE_IEEE754_UNOP(tan);
    791       break;
    792     case kMips64Add:
    793       __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    794       break;
    795     case kMips64Dadd:
    796       __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    797       break;
    798     case kMips64DaddOvf:
    799       // Pseudo-instruction used for overflow/branch. No opcode emitted here.
    800       break;
    801     case kMips64Sub:
    802       __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    803       break;
    804     case kMips64Dsub:
    805       __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    806       break;
    807     case kMips64DsubOvf:
    808       // Pseudo-instruction used for overflow/branch. No opcode emitted here.
    809       break;
    810     case kMips64Mul:
    811       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    812       break;
    813     case kMips64MulHigh:
    814       __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    815       break;
    816     case kMips64MulHighU:
    817       __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    818       break;
    819     case kMips64DMulHigh:
    820       __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    821       break;
    822     case kMips64Div:
    823       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    824       if (kArchVariant == kMips64r6) {
    825         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    826       } else {
    827         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
    828       }
    829       break;
    830     case kMips64DivU:
    831       __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    832       if (kArchVariant == kMips64r6) {
    833         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    834       } else {
    835         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
    836       }
    837       break;
    838     case kMips64Mod:
    839       __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    840       break;
    841     case kMips64ModU:
    842       __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    843       break;
    844     case kMips64Dmul:
    845       __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    846       break;
    847     case kMips64Ddiv:
    848       __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    849       if (kArchVariant == kMips64r6) {
    850         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    851       } else {
    852         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
    853       }
    854       break;
    855     case kMips64DdivU:
    856       __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    857       if (kArchVariant == kMips64r6) {
    858         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
    859       } else {
    860         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
    861       }
    862       break;
    863     case kMips64Dmod:
    864       __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    865       break;
    866     case kMips64DmodU:
    867       __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    868       break;
    869     case kMips64Dlsa:
    870       DCHECK(instr->InputAt(2)->IsImmediate());
    871       __ Dlsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    872               i.InputInt8(2));
    873       break;
    874     case kMips64Lsa:
    875       DCHECK(instr->InputAt(2)->IsImmediate());
    876       __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    877              i.InputInt8(2));
    878       break;
    879     case kMips64And:
    880       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    881       break;
    882     case kMips64Or:
    883       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    884       break;
    885     case kMips64Nor:
    886       if (instr->InputAt(1)->IsRegister()) {
    887         __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    888       } else {
    889         DCHECK(i.InputOperand(1).immediate() == 0);
    890         __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
    891       }
    892       break;
    893     case kMips64Xor:
    894       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
    895       break;
    896     case kMips64Clz:
    897       __ Clz(i.OutputRegister(), i.InputRegister(0));
    898       break;
    899     case kMips64Dclz:
    900       __ dclz(i.OutputRegister(), i.InputRegister(0));
    901       break;
    902     case kMips64Ctz: {
    903       Register reg1 = kScratchReg;
    904       Register reg2 = kScratchReg2;
    905       Label skip_for_zero;
    906       Label end;
    907       // Branch if the operand is zero
    908       __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
    909       // Find the number of bits before the last bit set to 1.
    910       __ Subu(reg2, zero_reg, i.InputRegister(0));
    911       __ And(reg2, reg2, i.InputRegister(0));
    912       __ clz(reg2, reg2);
    913       // Get the number of bits after the last bit set to 1.
    914       __ li(reg1, 0x1F);
    915       __ Subu(i.OutputRegister(), reg1, reg2);
    916       __ Branch(&end);
    917       __ bind(&skip_for_zero);
    918       // If the operand is zero, return word length as the result.
    919       __ li(i.OutputRegister(), 0x20);
    920       __ bind(&end);
    921     } break;
    922     case kMips64Dctz: {
    923       Register reg1 = kScratchReg;
    924       Register reg2 = kScratchReg2;
    925       Label skip_for_zero;
    926       Label end;
    927       // Branch if the operand is zero
    928       __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
    929       // Find the number of bits before the last bit set to 1.
    930       __ Dsubu(reg2, zero_reg, i.InputRegister(0));
    931       __ And(reg2, reg2, i.InputRegister(0));
    932       __ dclz(reg2, reg2);
    933       // Get the number of bits after the last bit set to 1.
    934       __ li(reg1, 0x3F);
    935       __ Subu(i.OutputRegister(), reg1, reg2);
    936       __ Branch(&end);
    937       __ bind(&skip_for_zero);
    938       // If the operand is zero, return word length as the result.
    939       __ li(i.OutputRegister(), 0x40);
    940       __ bind(&end);
    941     } break;
    942     case kMips64Popcnt: {
    943       Register reg1 = kScratchReg;
    944       Register reg2 = kScratchReg2;
    945       uint32_t m1 = 0x55555555;
    946       uint32_t m2 = 0x33333333;
    947       uint32_t m4 = 0x0f0f0f0f;
    948       uint32_t m8 = 0x00ff00ff;
    949       uint32_t m16 = 0x0000ffff;
    950 
    951       // Put count of ones in every 2 bits into those 2 bits.
    952       __ li(at, m1);
    953       __ dsrl(reg1, i.InputRegister(0), 1);
    954       __ And(reg2, i.InputRegister(0), at);
    955       __ And(reg1, reg1, at);
    956       __ Daddu(reg1, reg1, reg2);
    957 
    958       // Put count of ones in every 4 bits into those 4 bits.
    959       __ li(at, m2);
    960       __ dsrl(reg2, reg1, 2);
    961       __ And(reg2, reg2, at);
    962       __ And(reg1, reg1, at);
    963       __ Daddu(reg1, reg1, reg2);
    964 
    965       // Put count of ones in every 8 bits into those 8 bits.
    966       __ li(at, m4);
    967       __ dsrl(reg2, reg1, 4);
    968       __ And(reg2, reg2, at);
    969       __ And(reg1, reg1, at);
    970       __ Daddu(reg1, reg1, reg2);
    971 
    972       // Put count of ones in every 16 bits into those 16 bits.
    973       __ li(at, m8);
    974       __ dsrl(reg2, reg1, 8);
    975       __ And(reg2, reg2, at);
    976       __ And(reg1, reg1, at);
    977       __ Daddu(reg1, reg1, reg2);
    978 
    979       // Calculate total number of ones.
    980       __ li(at, m16);
    981       __ dsrl(reg2, reg1, 16);
    982       __ And(reg2, reg2, at);
    983       __ And(reg1, reg1, at);
    984       __ Daddu(i.OutputRegister(), reg1, reg2);
    985     } break;
    986     case kMips64Dpopcnt: {
    987       Register reg1 = kScratchReg;
    988       Register reg2 = kScratchReg2;
    989       uint64_t m1 = 0x5555555555555555;
    990       uint64_t m2 = 0x3333333333333333;
    991       uint64_t m4 = 0x0f0f0f0f0f0f0f0f;
    992       uint64_t m8 = 0x00ff00ff00ff00ff;
    993       uint64_t m16 = 0x0000ffff0000ffff;
    994       uint64_t m32 = 0x00000000ffffffff;
    995 
    996       // Put count of ones in every 2 bits into those 2 bits.
    997       __ li(at, m1);
    998       __ dsrl(reg1, i.InputRegister(0), 1);
    999       __ and_(reg2, i.InputRegister(0), at);
   1000       __ and_(reg1, reg1, at);
   1001       __ Daddu(reg1, reg1, reg2);
   1002 
   1003       // Put count of ones in every 4 bits into those 4 bits.
   1004       __ li(at, m2);
   1005       __ dsrl(reg2, reg1, 2);
   1006       __ and_(reg2, reg2, at);
   1007       __ and_(reg1, reg1, at);
   1008       __ Daddu(reg1, reg1, reg2);
   1009 
   1010       // Put count of ones in every 8 bits into those 8 bits.
   1011       __ li(at, m4);
   1012       __ dsrl(reg2, reg1, 4);
   1013       __ and_(reg2, reg2, at);
   1014       __ and_(reg1, reg1, at);
   1015       __ Daddu(reg1, reg1, reg2);
   1016 
   1017       // Put count of ones in every 16 bits into those 16 bits.
   1018       __ li(at, m8);
   1019       __ dsrl(reg2, reg1, 8);
   1020       __ and_(reg2, reg2, at);
   1021       __ and_(reg1, reg1, at);
   1022       __ Daddu(reg1, reg1, reg2);
   1023 
   1024       // Put count of ones in every 32 bits into those 32 bits.
   1025       __ li(at, m16);
   1026       __ dsrl(reg2, reg1, 16);
   1027       __ and_(reg2, reg2, at);
   1028       __ and_(reg1, reg1, at);
   1029       __ Daddu(reg1, reg1, reg2);
   1030 
   1031       // Calculate total number of ones.
   1032       __ li(at, m32);
   1033       __ dsrl32(reg2, reg1, 0);
   1034       __ and_(reg2, reg2, at);
   1035       __ and_(reg1, reg1, at);
   1036       __ Daddu(i.OutputRegister(), reg1, reg2);
   1037     } break;
   1038     case kMips64Shl:
   1039       if (instr->InputAt(1)->IsRegister()) {
   1040         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1041       } else {
   1042         int64_t imm = i.InputOperand(1).immediate();
   1043         __ sll(i.OutputRegister(), i.InputRegister(0),
   1044                static_cast<uint16_t>(imm));
   1045       }
   1046       break;
   1047     case kMips64Shr:
   1048       if (instr->InputAt(1)->IsRegister()) {
   1049         __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1050       } else {
   1051         int64_t imm = i.InputOperand(1).immediate();
   1052         __ srl(i.OutputRegister(), i.InputRegister(0),
   1053                static_cast<uint16_t>(imm));
   1054       }
   1055       break;
   1056     case kMips64Sar:
   1057       if (instr->InputAt(1)->IsRegister()) {
   1058         __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1059       } else {
   1060         int64_t imm = i.InputOperand(1).immediate();
   1061         __ sra(i.OutputRegister(), i.InputRegister(0),
   1062                static_cast<uint16_t>(imm));
   1063       }
   1064       break;
   1065     case kMips64Ext:
   1066       __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1067              i.InputInt8(2));
   1068       break;
   1069     case kMips64Ins:
   1070       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
   1071         __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
   1072       } else {
   1073         __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1074                i.InputInt8(2));
   1075       }
   1076       break;
   1077     case kMips64Dext: {
   1078       int16_t pos = i.InputInt8(1);
   1079       int16_t size = i.InputInt8(2);
   1080       if (size > 0 && size <= 32 && pos >= 0 && pos < 32) {
   1081         __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1082                 i.InputInt8(2));
   1083       } else if (size > 32 && size <= 64 && pos > 0 && pos < 32) {
   1084         __ Dextm(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1085                  i.InputInt8(2));
   1086       } else {
   1087         DCHECK(size > 0 && size <= 32 && pos >= 32 && pos < 64);
   1088         __ Dextu(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1089                  i.InputInt8(2));
   1090       }
   1091       break;
   1092     }
   1093     case kMips64Dins:
   1094       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
   1095         __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
   1096       } else {
   1097         __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
   1098                 i.InputInt8(2));
   1099       }
   1100       break;
   1101     case kMips64Dshl:
   1102       if (instr->InputAt(1)->IsRegister()) {
   1103         __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1104       } else {
   1105         int64_t imm = i.InputOperand(1).immediate();
   1106         if (imm < 32) {
   1107           __ dsll(i.OutputRegister(), i.InputRegister(0),
   1108                   static_cast<uint16_t>(imm));
   1109         } else {
   1110           __ dsll32(i.OutputRegister(), i.InputRegister(0),
   1111                     static_cast<uint16_t>(imm - 32));
   1112         }
   1113       }
   1114       break;
   1115     case kMips64Dshr:
   1116       if (instr->InputAt(1)->IsRegister()) {
   1117         __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1118       } else {
   1119         int64_t imm = i.InputOperand(1).immediate();
   1120         if (imm < 32) {
   1121           __ dsrl(i.OutputRegister(), i.InputRegister(0),
   1122                   static_cast<uint16_t>(imm));
   1123         } else {
   1124           __ dsrl32(i.OutputRegister(), i.InputRegister(0),
   1125                     static_cast<uint16_t>(imm - 32));
   1126         }
   1127       }
   1128       break;
   1129     case kMips64Dsar:
   1130       if (instr->InputAt(1)->IsRegister()) {
   1131         __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1132       } else {
   1133         int64_t imm = i.InputOperand(1).immediate();
   1134         if (imm < 32) {
   1135           __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
   1136         } else {
   1137           __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
   1138         }
   1139       }
   1140       break;
   1141     case kMips64Ror:
   1142       __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
   1143       break;
   1144     case kMips64Dror:
   1145       __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
   1146       break;
   1147     case kMips64Tst:
   1148       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
   1149       break;
   1150     case kMips64Cmp:
   1151       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
   1152       break;
   1153     case kMips64Mov:
   1154       // TODO(plind): Should we combine mov/li like this, or use separate instr?
   1155       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
   1156       if (HasRegisterInput(instr, 0)) {
   1157         __ mov(i.OutputRegister(), i.InputRegister(0));
   1158       } else {
   1159         __ li(i.OutputRegister(), i.InputOperand(0));
   1160       }
   1161       break;
   1162 
   1163     case kMips64CmpS:
   1164       // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
   1165       break;
   1166     case kMips64AddS:
   1167       // TODO(plind): add special case: combine mult & add.
   1168       __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1169                i.InputDoubleRegister(1));
   1170       break;
   1171     case kMips64SubS:
   1172       __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1173                i.InputDoubleRegister(1));
   1174       break;
   1175     case kMips64SubPreserveNanS:
   1176       __ SubNanPreservePayloadAndSign_s(i.OutputDoubleRegister(),
   1177                                         i.InputDoubleRegister(0),
   1178                                         i.InputDoubleRegister(1));
   1179       break;
   1180     case kMips64MulS:
   1181       // TODO(plind): add special case: right op is -1.0, see arm port.
   1182       __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1183                i.InputDoubleRegister(1));
   1184       break;
   1185     case kMips64DivS:
   1186       __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1187                i.InputDoubleRegister(1));
   1188       break;
   1189     case kMips64ModS: {
   1190       // TODO(bmeurer): We should really get rid of this special instruction,
   1191       // and generate a CallAddress instruction instead.
   1192       FrameScope scope(masm(), StackFrame::MANUAL);
   1193       __ PrepareCallCFunction(0, 2, kScratchReg);
   1194       __ MovToFloatParameters(i.InputDoubleRegister(0),
   1195                               i.InputDoubleRegister(1));
   1196       // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
   1197       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
   1198                        0, 2);
   1199       // Move the result in the double result register.
   1200       __ MovFromFloatResult(i.OutputSingleRegister());
   1201       break;
   1202     }
   1203     case kMips64AbsS:
   1204       __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
   1205       break;
   1206     case kMips64SqrtS: {
   1207       __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1208       break;
   1209     }
   1210     case kMips64MaxS:
   1211       __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1212                i.InputDoubleRegister(1));
   1213       break;
   1214     case kMips64MinS:
   1215       __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1216                i.InputDoubleRegister(1));
   1217       break;
   1218     case kMips64CmpD:
   1219       // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
   1220       break;
   1221     case kMips64AddD:
   1222       // TODO(plind): add special case: combine mult & add.
   1223       __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1224                i.InputDoubleRegister(1));
   1225       break;
   1226     case kMips64SubD:
   1227       __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1228                i.InputDoubleRegister(1));
   1229       break;
   1230     case kMips64SubPreserveNanD:
   1231       __ SubNanPreservePayloadAndSign_d(i.OutputDoubleRegister(),
   1232                                         i.InputDoubleRegister(0),
   1233                                         i.InputDoubleRegister(1));
   1234       break;
   1235     case kMips64MulD:
   1236       // TODO(plind): add special case: right op is -1.0, see arm port.
   1237       __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1238                i.InputDoubleRegister(1));
   1239       break;
   1240     case kMips64DivD:
   1241       __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1242                i.InputDoubleRegister(1));
   1243       break;
   1244     case kMips64ModD: {
   1245       // TODO(bmeurer): We should really get rid of this special instruction,
   1246       // and generate a CallAddress instruction instead.
   1247       FrameScope scope(masm(), StackFrame::MANUAL);
   1248       __ PrepareCallCFunction(0, 2, kScratchReg);
   1249       __ MovToFloatParameters(i.InputDoubleRegister(0),
   1250                               i.InputDoubleRegister(1));
   1251       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
   1252                        0, 2);
   1253       // Move the result in the double result register.
   1254       __ MovFromFloatResult(i.OutputDoubleRegister());
   1255       break;
   1256     }
   1257     case kMips64AbsD:
   1258       __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1259       break;
   1260     case kMips64SqrtD: {
   1261       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1262       break;
   1263     }
   1264     case kMips64MaxD:
   1265       __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1266                i.InputDoubleRegister(1));
   1267       break;
   1268     case kMips64MinD:
   1269       __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1270                i.InputDoubleRegister(1));
   1271       break;
   1272     case kMips64Float64RoundDown: {
   1273       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
   1274       break;
   1275     }
   1276     case kMips64Float32RoundDown: {
   1277       ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
   1278       break;
   1279     }
   1280     case kMips64Float64RoundTruncate: {
   1281       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
   1282       break;
   1283     }
   1284     case kMips64Float32RoundTruncate: {
   1285       ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
   1286       break;
   1287     }
   1288     case kMips64Float64RoundUp: {
   1289       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
   1290       break;
   1291     }
   1292     case kMips64Float32RoundUp: {
   1293       ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
   1294       break;
   1295     }
   1296     case kMips64Float64RoundTiesEven: {
   1297       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
   1298       break;
   1299     }
   1300     case kMips64Float32RoundTiesEven: {
   1301       ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
   1302       break;
   1303     }
   1304     case kMips64Float64Max: {
   1305       // (b < a) ? a : b
   1306       if (kArchVariant == kMips64r6) {
   1307         __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1308                  i.InputDoubleRegister(0));
   1309         __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1310                  i.InputDoubleRegister(0));
   1311       } else {
   1312         __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1313         // Left operand is result, passthrough if false.
   1314         __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
   1315       }
   1316       break;
   1317     }
   1318     case kMips64Float64Min: {
   1319       // (a < b) ? a : b
   1320       if (kArchVariant == kMips64r6) {
   1321         __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1322                  i.InputDoubleRegister(1));
   1323         __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1324                  i.InputDoubleRegister(0));
   1325       } else {
   1326         __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
   1327         // Right operand is result, passthrough if false.
   1328         __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
   1329       }
   1330       break;
   1331     }
   1332     case kMips64Float64SilenceNaN:
   1333       __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1334       break;
   1335     case kMips64Float32Max: {
   1336       // (b < a) ? a : b
   1337       if (kArchVariant == kMips64r6) {
   1338         __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1339                  i.InputDoubleRegister(0));
   1340         __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1341                  i.InputDoubleRegister(0));
   1342       } else {
   1343         __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
   1344         // Left operand is result, passthrough if false.
   1345         __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
   1346       }
   1347       break;
   1348     }
   1349     case kMips64Float32Min: {
   1350       // (a < b) ? a : b
   1351       if (kArchVariant == kMips64r6) {
   1352         __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
   1353                  i.InputDoubleRegister(1));
   1354         __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
   1355                  i.InputDoubleRegister(0));
   1356       } else {
   1357         __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
   1358         // Right operand is result, passthrough if false.
   1359         __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
   1360       }
   1361       break;
   1362     }
   1363     case kMips64CvtSD:
   1364       __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
   1365       break;
   1366     case kMips64CvtDS:
   1367       __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
   1368       break;
   1369     case kMips64CvtDW: {
   1370       FPURegister scratch = kScratchDoubleReg;
   1371       __ mtc1(i.InputRegister(0), scratch);
   1372       __ cvt_d_w(i.OutputDoubleRegister(), scratch);
   1373       break;
   1374     }
   1375     case kMips64CvtSW: {
   1376       FPURegister scratch = kScratchDoubleReg;
   1377       __ mtc1(i.InputRegister(0), scratch);
   1378       __ cvt_s_w(i.OutputDoubleRegister(), scratch);
   1379       break;
   1380     }
   1381     case kMips64CvtSUw: {
   1382       __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
   1383       break;
   1384     }
   1385     case kMips64CvtSL: {
   1386       FPURegister scratch = kScratchDoubleReg;
   1387       __ dmtc1(i.InputRegister(0), scratch);
   1388       __ cvt_s_l(i.OutputDoubleRegister(), scratch);
   1389       break;
   1390     }
   1391     case kMips64CvtDL: {
   1392       FPURegister scratch = kScratchDoubleReg;
   1393       __ dmtc1(i.InputRegister(0), scratch);
   1394       __ cvt_d_l(i.OutputDoubleRegister(), scratch);
   1395       break;
   1396     }
   1397     case kMips64CvtDUw: {
   1398       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
   1399       break;
   1400     }
   1401     case kMips64CvtDUl: {
   1402       __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
   1403       break;
   1404     }
   1405     case kMips64CvtSUl: {
   1406       __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
   1407       break;
   1408     }
   1409     case kMips64FloorWD: {
   1410       FPURegister scratch = kScratchDoubleReg;
   1411       __ floor_w_d(scratch, i.InputDoubleRegister(0));
   1412       __ mfc1(i.OutputRegister(), scratch);
   1413       break;
   1414     }
   1415     case kMips64CeilWD: {
   1416       FPURegister scratch = kScratchDoubleReg;
   1417       __ ceil_w_d(scratch, i.InputDoubleRegister(0));
   1418       __ mfc1(i.OutputRegister(), scratch);
   1419       break;
   1420     }
   1421     case kMips64RoundWD: {
   1422       FPURegister scratch = kScratchDoubleReg;
   1423       __ round_w_d(scratch, i.InputDoubleRegister(0));
   1424       __ mfc1(i.OutputRegister(), scratch);
   1425       break;
   1426     }
   1427     case kMips64TruncWD: {
   1428       FPURegister scratch = kScratchDoubleReg;
   1429       // Other arches use round to zero here, so we follow.
   1430       __ trunc_w_d(scratch, i.InputDoubleRegister(0));
   1431       __ mfc1(i.OutputRegister(), scratch);
   1432       break;
   1433     }
   1434     case kMips64FloorWS: {
   1435       FPURegister scratch = kScratchDoubleReg;
   1436       __ floor_w_s(scratch, i.InputDoubleRegister(0));
   1437       __ mfc1(i.OutputRegister(), scratch);
   1438       break;
   1439     }
   1440     case kMips64CeilWS: {
   1441       FPURegister scratch = kScratchDoubleReg;
   1442       __ ceil_w_s(scratch, i.InputDoubleRegister(0));
   1443       __ mfc1(i.OutputRegister(), scratch);
   1444       break;
   1445     }
   1446     case kMips64RoundWS: {
   1447       FPURegister scratch = kScratchDoubleReg;
   1448       __ round_w_s(scratch, i.InputDoubleRegister(0));
   1449       __ mfc1(i.OutputRegister(), scratch);
   1450       break;
   1451     }
   1452     case kMips64TruncWS: {
   1453       FPURegister scratch = kScratchDoubleReg;
   1454       __ trunc_w_s(scratch, i.InputDoubleRegister(0));
   1455       __ mfc1(i.OutputRegister(), scratch);
   1456       break;
   1457     }
   1458     case kMips64TruncLS: {
   1459       FPURegister scratch = kScratchDoubleReg;
   1460       Register tmp_fcsr = kScratchReg;
   1461       Register result = kScratchReg2;
   1462 
   1463       bool load_status = instr->OutputCount() > 1;
   1464       if (load_status) {
   1465         // Save FCSR.
   1466         __ cfc1(tmp_fcsr, FCSR);
   1467         // Clear FPU flags.
   1468         __ ctc1(zero_reg, FCSR);
   1469       }
   1470       // Other arches use round to zero here, so we follow.
   1471       __ trunc_l_s(scratch, i.InputDoubleRegister(0));
   1472       __ dmfc1(i.OutputRegister(), scratch);
   1473       if (load_status) {
   1474         __ cfc1(result, FCSR);
   1475         // Check for overflow and NaNs.
   1476         __ andi(result, result,
   1477                 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
   1478         __ Slt(result, zero_reg, result);
   1479         __ xori(result, result, 1);
   1480         __ mov(i.OutputRegister(1), result);
   1481         // Restore FCSR
   1482         __ ctc1(tmp_fcsr, FCSR);
   1483       }
   1484       break;
   1485     }
   1486     case kMips64TruncLD: {
   1487       FPURegister scratch = kScratchDoubleReg;
   1488       Register tmp_fcsr = kScratchReg;
   1489       Register result = kScratchReg2;
   1490 
   1491       bool load_status = instr->OutputCount() > 1;
   1492       if (load_status) {
   1493         // Save FCSR.
   1494         __ cfc1(tmp_fcsr, FCSR);
   1495         // Clear FPU flags.
   1496         __ ctc1(zero_reg, FCSR);
   1497       }
   1498       // Other arches use round to zero here, so we follow.
   1499       __ trunc_l_d(scratch, i.InputDoubleRegister(0));
   1500       __ dmfc1(i.OutputRegister(0), scratch);
   1501       if (load_status) {
   1502         __ cfc1(result, FCSR);
   1503         // Check for overflow and NaNs.
   1504         __ andi(result, result,
   1505                 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
   1506         __ Slt(result, zero_reg, result);
   1507         __ xori(result, result, 1);
   1508         __ mov(i.OutputRegister(1), result);
   1509         // Restore FCSR
   1510         __ ctc1(tmp_fcsr, FCSR);
   1511       }
   1512       break;
   1513     }
   1514     case kMips64TruncUwD: {
   1515       FPURegister scratch = kScratchDoubleReg;
   1516       // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
   1517       __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
   1518       break;
   1519     }
   1520     case kMips64TruncUwS: {
   1521       FPURegister scratch = kScratchDoubleReg;
   1522       // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
   1523       __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
   1524       break;
   1525     }
   1526     case kMips64TruncUlS: {
   1527       FPURegister scratch = kScratchDoubleReg;
   1528       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
   1529       // TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function.
   1530       __ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch,
   1531                     result);
   1532       break;
   1533     }
   1534     case kMips64TruncUlD: {
   1535       FPURegister scratch = kScratchDoubleReg;
   1536       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
   1537       // TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
   1538       __ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
   1539                     result);
   1540       break;
   1541     }
   1542     case kMips64BitcastDL:
   1543       __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0));
   1544       break;
   1545     case kMips64BitcastLD:
   1546       __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister());
   1547       break;
   1548     case kMips64Float64ExtractLowWord32:
   1549       __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
   1550       break;
   1551     case kMips64Float64ExtractHighWord32:
   1552       __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
   1553       break;
   1554     case kMips64Float64InsertLowWord32:
   1555       __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
   1556       break;
   1557     case kMips64Float64InsertHighWord32:
   1558       __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
   1559       break;
   1560     // ... more basic instructions ...
   1561 
   1562     case kMips64Lbu:
   1563       __ lbu(i.OutputRegister(), i.MemoryOperand());
   1564       break;
   1565     case kMips64Lb:
   1566       __ lb(i.OutputRegister(), i.MemoryOperand());
   1567       break;
   1568     case kMips64Sb:
   1569       __ sb(i.InputRegister(2), i.MemoryOperand());
   1570       break;
   1571     case kMips64Lhu:
   1572       __ lhu(i.OutputRegister(), i.MemoryOperand());
   1573       break;
   1574     case kMips64Lh:
   1575       __ lh(i.OutputRegister(), i.MemoryOperand());
   1576       break;
   1577     case kMips64Sh:
   1578       __ sh(i.InputRegister(2), i.MemoryOperand());
   1579       break;
   1580     case kMips64Lw:
   1581       __ lw(i.OutputRegister(), i.MemoryOperand());
   1582       break;
   1583     case kMips64Lwu:
   1584       __ lwu(i.OutputRegister(), i.MemoryOperand());
   1585       break;
   1586     case kMips64Ld:
   1587       __ ld(i.OutputRegister(), i.MemoryOperand());
   1588       break;
   1589     case kMips64Sw:
   1590       __ sw(i.InputRegister(2), i.MemoryOperand());
   1591       break;
   1592     case kMips64Sd:
   1593       __ sd(i.InputRegister(2), i.MemoryOperand());
   1594       break;
   1595     case kMips64Lwc1: {
   1596       __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
   1597       break;
   1598     }
   1599     case kMips64Swc1: {
   1600       size_t index = 0;
   1601       MemOperand operand = i.MemoryOperand(&index);
   1602       __ swc1(i.InputSingleRegister(index), operand);
   1603       break;
   1604     }
   1605     case kMips64Ldc1:
   1606       __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
   1607       break;
   1608     case kMips64Sdc1:
   1609       __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
   1610       break;
   1611     case kMips64Push:
   1612       if (instr->InputAt(0)->IsFPRegister()) {
   1613         __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
   1614         __ Subu(sp, sp, Operand(kDoubleSize));
   1615         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   1616       } else {
   1617         __ Push(i.InputRegister(0));
   1618         frame_access_state()->IncreaseSPDelta(1);
   1619       }
   1620       break;
   1621     case kMips64StackClaim: {
   1622       __ Dsubu(sp, sp, Operand(i.InputInt32(0)));
   1623       frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
   1624       break;
   1625     }
   1626     case kMips64StoreToStackSlot: {
   1627       if (instr->InputAt(0)->IsFPRegister()) {
   1628         __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
   1629       } else {
   1630         __ sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
   1631       }
   1632       break;
   1633     }
   1634     case kCheckedLoadInt8:
   1635       ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
   1636       break;
   1637     case kCheckedLoadUint8:
   1638       ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
   1639       break;
   1640     case kCheckedLoadInt16:
   1641       ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
   1642       break;
   1643     case kCheckedLoadUint16:
   1644       ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
   1645       break;
   1646     case kCheckedLoadWord32:
   1647       ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
   1648       break;
   1649     case kCheckedLoadWord64:
   1650       ASSEMBLE_CHECKED_LOAD_INTEGER(ld);
   1651       break;
   1652     case kCheckedLoadFloat32:
   1653       ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
   1654       break;
   1655     case kCheckedLoadFloat64:
   1656       ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
   1657       break;
   1658     case kCheckedStoreWord8:
   1659       ASSEMBLE_CHECKED_STORE_INTEGER(sb);
   1660       break;
   1661     case kCheckedStoreWord16:
   1662       ASSEMBLE_CHECKED_STORE_INTEGER(sh);
   1663       break;
   1664     case kCheckedStoreWord32:
   1665       ASSEMBLE_CHECKED_STORE_INTEGER(sw);
   1666       break;
   1667     case kCheckedStoreWord64:
   1668       ASSEMBLE_CHECKED_STORE_INTEGER(sd);
   1669       break;
   1670     case kCheckedStoreFloat32:
   1671       ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
   1672       break;
   1673     case kCheckedStoreFloat64:
   1674       ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
   1675       break;
   1676     case kAtomicLoadInt8:
   1677       ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
   1678       break;
   1679     case kAtomicLoadUint8:
   1680       ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
   1681       break;
   1682     case kAtomicLoadInt16:
   1683       ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
   1684       break;
   1685     case kAtomicLoadUint16:
   1686       ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
   1687       break;
   1688     case kAtomicLoadWord32:
   1689       ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
   1690       break;
   1691     case kAtomicStoreWord8:
   1692       ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
   1693       break;
   1694     case kAtomicStoreWord16:
   1695       ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
   1696       break;
   1697     case kAtomicStoreWord32:
   1698       ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
   1699       break;
   1700   }
   1701   return kSuccess;
   1702 }  // NOLINT(readability/fn_size)
   1703 
   1704 
   1705 #define UNSUPPORTED_COND(opcode, condition)                                  \
   1706   OFStream out(stdout);                                                      \
   1707   out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
   1708   UNIMPLEMENTED();
   1709 
   1710 static bool convertCondition(FlagsCondition condition, Condition& cc) {
   1711   switch (condition) {
   1712     case kEqual:
   1713       cc = eq;
   1714       return true;
   1715     case kNotEqual:
   1716       cc = ne;
   1717       return true;
   1718     case kUnsignedLessThan:
   1719       cc = lt;
   1720       return true;
   1721     case kUnsignedGreaterThanOrEqual:
   1722       cc = uge;
   1723       return true;
   1724     case kUnsignedLessThanOrEqual:
   1725       cc = le;
   1726       return true;
   1727     case kUnsignedGreaterThan:
   1728       cc = ugt;
   1729       return true;
   1730     default:
   1731       break;
   1732   }
   1733   return false;
   1734 }
   1735 
   1736 
   1737 // Assembles branches after an instruction.
   1738 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   1739   MipsOperandConverter i(this, instr);
   1740   Label* tlabel = branch->true_label;
   1741   Label* flabel = branch->false_label;
   1742   Condition cc = kNoCondition;
   1743   // MIPS does not have condition code flags, so compare and branch are
   1744   // implemented differently than on the other arch's. The compare operations
   1745   // emit mips psuedo-instructions, which are handled here by branch
   1746   // instructions that do the actual comparison. Essential that the input
   1747   // registers to compare pseudo-op are not modified before this branch op, as
   1748   // they are tested here.
   1749 
   1750   if (instr->arch_opcode() == kMips64Tst) {
   1751     cc = FlagsConditionToConditionTst(branch->condition);
   1752     __ And(at, i.InputRegister(0), i.InputOperand(1));
   1753     __ Branch(tlabel, cc, at, Operand(zero_reg));
   1754   } else if (instr->arch_opcode() == kMips64Dadd ||
   1755              instr->arch_opcode() == kMips64Dsub) {
   1756     cc = FlagsConditionToConditionOvf(branch->condition);
   1757     __ dsra32(kScratchReg, i.OutputRegister(), 0);
   1758     __ sra(at, i.OutputRegister(), 31);
   1759     __ Branch(tlabel, cc, at, Operand(kScratchReg));
   1760   } else if (instr->arch_opcode() == kMips64DaddOvf) {
   1761     switch (branch->condition) {
   1762       case kOverflow:
   1763         __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
   1764                          i.InputOperand(1), tlabel, flabel);
   1765         break;
   1766       case kNotOverflow:
   1767         __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
   1768                          i.InputOperand(1), flabel, tlabel);
   1769         break;
   1770       default:
   1771         UNSUPPORTED_COND(kMips64DaddOvf, branch->condition);
   1772         break;
   1773     }
   1774   } else if (instr->arch_opcode() == kMips64DsubOvf) {
   1775     switch (branch->condition) {
   1776       case kOverflow:
   1777         __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
   1778                          i.InputOperand(1), tlabel, flabel);
   1779         break;
   1780       case kNotOverflow:
   1781         __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
   1782                          i.InputOperand(1), flabel, tlabel);
   1783         break;
   1784       default:
   1785         UNSUPPORTED_COND(kMips64DsubOvf, branch->condition);
   1786         break;
   1787     }
   1788   } else if (instr->arch_opcode() == kMips64Cmp) {
   1789     cc = FlagsConditionToConditionCmp(branch->condition);
   1790     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
   1791   } else if (instr->arch_opcode() == kMips64CmpS) {
   1792     if (!convertCondition(branch->condition, cc)) {
   1793       UNSUPPORTED_COND(kMips64CmpS, branch->condition);
   1794     }
   1795     FPURegister left = i.InputOrZeroSingleRegister(0);
   1796     FPURegister right = i.InputOrZeroSingleRegister(1);
   1797     if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
   1798         !__ IsDoubleZeroRegSet()) {
   1799       __ Move(kDoubleRegZero, 0.0);
   1800     }
   1801     __ BranchF32(tlabel, nullptr, cc, left, right);
   1802   } else if (instr->arch_opcode() == kMips64CmpD) {
   1803     if (!convertCondition(branch->condition, cc)) {
   1804       UNSUPPORTED_COND(kMips64CmpD, branch->condition);
   1805     }
   1806     FPURegister left = i.InputOrZeroDoubleRegister(0);
   1807     FPURegister right = i.InputOrZeroDoubleRegister(1);
   1808     if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
   1809         !__ IsDoubleZeroRegSet()) {
   1810       __ Move(kDoubleRegZero, 0.0);
   1811     }
   1812     __ BranchF64(tlabel, nullptr, cc, left, right);
   1813   } else {
   1814     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
   1815            instr->arch_opcode());
   1816     UNIMPLEMENTED();
   1817   }
   1818   if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
   1819 }
   1820 
   1821 
   1822 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   1823   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
   1824 }
   1825 
   1826 
   1827 // Assembles boolean materializations after an instruction.
   1828 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   1829                                         FlagsCondition condition) {
   1830   MipsOperandConverter i(this, instr);
   1831   Label done;
   1832 
   1833   // Materialize a full 32-bit 1 or 0 value. The result register is always the
   1834   // last output of the instruction.
   1835   Label false_value;
   1836   DCHECK_NE(0u, instr->OutputCount());
   1837   Register result = i.OutputRegister(instr->OutputCount() - 1);
   1838   Condition cc = kNoCondition;
   1839   // MIPS does not have condition code flags, so compare and branch are
   1840   // implemented differently than on the other arch's. The compare operations
   1841   // emit mips pseudo-instructions, which are checked and handled here.
   1842 
   1843   if (instr->arch_opcode() == kMips64Tst) {
   1844     cc = FlagsConditionToConditionTst(condition);
   1845     __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
   1846     __ Sltu(result, zero_reg, kScratchReg);
   1847     if (cc == eq) {
   1848       // Sltu produces 0 for equality, invert the result.
   1849       __ xori(result, result, 1);
   1850     }
   1851     return;
   1852   } else if (instr->arch_opcode() == kMips64Dadd ||
   1853              instr->arch_opcode() == kMips64Dsub) {
   1854     cc = FlagsConditionToConditionOvf(condition);
   1855     // Check for overflow creates 1 or 0 for result.
   1856     __ dsrl32(kScratchReg, i.OutputRegister(), 31);
   1857     __ srl(at, i.OutputRegister(), 31);
   1858     __ xor_(result, kScratchReg, at);
   1859     if (cc == eq)  // Toggle result for not overflow.
   1860       __ xori(result, result, 1);
   1861     return;
   1862   } else if (instr->arch_opcode() == kMips64DaddOvf ||
   1863              instr->arch_opcode() == kMips64DsubOvf) {
   1864     Label flabel, tlabel;
   1865     switch (instr->arch_opcode()) {
   1866       case kMips64DaddOvf:
   1867         __ DaddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
   1868                            i.InputOperand(1), &flabel);
   1869 
   1870         break;
   1871       case kMips64DsubOvf:
   1872         __ DsubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
   1873                            i.InputOperand(1), &flabel);
   1874         break;
   1875       default:
   1876         UNREACHABLE();
   1877         break;
   1878     }
   1879     __ li(result, 1);
   1880     __ Branch(&tlabel);
   1881     __ bind(&flabel);
   1882     __ li(result, 0);
   1883     __ bind(&tlabel);
   1884   } else if (instr->arch_opcode() == kMips64Cmp) {
   1885     cc = FlagsConditionToConditionCmp(condition);
   1886     switch (cc) {
   1887       case eq:
   1888       case ne: {
   1889         Register left = i.InputRegister(0);
   1890         Operand right = i.InputOperand(1);
   1891         Register select;
   1892         if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) {
   1893           // Pass left operand if right is zero.
   1894           select = left;
   1895         } else {
   1896           __ Dsubu(kScratchReg, left, right);
   1897           select = kScratchReg;
   1898         }
   1899         __ Sltu(result, zero_reg, select);
   1900         if (cc == eq) {
   1901           // Sltu produces 0 for equality, invert the result.
   1902           __ xori(result, result, 1);
   1903         }
   1904       } break;
   1905       case lt:
   1906       case ge: {
   1907         Register left = i.InputRegister(0);
   1908         Operand right = i.InputOperand(1);
   1909         __ Slt(result, left, right);
   1910         if (cc == ge) {
   1911           __ xori(result, result, 1);
   1912         }
   1913       } break;
   1914       case gt:
   1915       case le: {
   1916         Register left = i.InputRegister(1);
   1917         Operand right = i.InputOperand(0);
   1918         __ Slt(result, left, right);
   1919         if (cc == le) {
   1920           __ xori(result, result, 1);
   1921         }
   1922       } break;
   1923       case lo:
   1924       case hs: {
   1925         Register left = i.InputRegister(0);
   1926         Operand right = i.InputOperand(1);
   1927         __ Sltu(result, left, right);
   1928         if (cc == hs) {
   1929           __ xori(result, result, 1);
   1930         }
   1931       } break;
   1932       case hi:
   1933       case ls: {
   1934         Register left = i.InputRegister(1);
   1935         Operand right = i.InputOperand(0);
   1936         __ Sltu(result, left, right);
   1937         if (cc == ls) {
   1938           __ xori(result, result, 1);
   1939         }
   1940       } break;
   1941       default:
   1942         UNREACHABLE();
   1943     }
   1944     return;
   1945   } else if (instr->arch_opcode() == kMips64CmpD ||
   1946              instr->arch_opcode() == kMips64CmpS) {
   1947     FPURegister left = i.InputOrZeroDoubleRegister(0);
   1948     FPURegister right = i.InputOrZeroDoubleRegister(1);
   1949     if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
   1950         !__ IsDoubleZeroRegSet()) {
   1951       __ Move(kDoubleRegZero, 0.0);
   1952     }
   1953     bool predicate;
   1954     FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
   1955     if (kArchVariant != kMips64r6) {
   1956       __ li(result, Operand(1));
   1957       if (instr->arch_opcode() == kMips64CmpD) {
   1958         __ c(cc, D, left, right);
   1959       } else {
   1960         DCHECK(instr->arch_opcode() == kMips64CmpS);
   1961         __ c(cc, S, left, right);
   1962       }
   1963       if (predicate) {
   1964         __ Movf(result, zero_reg);
   1965       } else {
   1966         __ Movt(result, zero_reg);
   1967       }
   1968     } else {
   1969       if (instr->arch_opcode() == kMips64CmpD) {
   1970         __ cmp(cc, L, kDoubleCompareReg, left, right);
   1971       } else {
   1972         DCHECK(instr->arch_opcode() == kMips64CmpS);
   1973         __ cmp(cc, W, kDoubleCompareReg, left, right);
   1974       }
   1975       __ dmfc1(result, kDoubleCompareReg);
   1976       __ andi(result, result, 1);  // Cmp returns all 1's/0's, use only LSB.
   1977 
   1978       if (!predicate)  // Toggle result for not equal.
   1979         __ xori(result, result, 1);
   1980     }
   1981     return;
   1982   } else {
   1983     PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
   1984            instr->arch_opcode());
   1985     TRACE_UNIMPL();
   1986     UNIMPLEMENTED();
   1987   }
   1988 }
   1989 
   1990 
   1991 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   1992   MipsOperandConverter i(this, instr);
   1993   Register input = i.InputRegister(0);
   1994   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   1995     __ li(at, Operand(i.InputInt32(index + 0)));
   1996     __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
   1997   }
   1998   __ nop();  // Branch delay slot of the last beq.
   1999   AssembleArchJump(i.InputRpo(1));
   2000 }
   2001 
   2002 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   2003   MipsOperandConverter i(this, instr);
   2004   Register input = i.InputRegister(0);
   2005   size_t const case_count = instr->InputCount() - 2;
   2006 
   2007   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
   2008   __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
   2009     return GetLabel(i.InputRpo(index + 2));
   2010   });
   2011 }
   2012 
   2013 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
   2014     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   2015   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   2016       isolate(), deoptimization_id, bailout_type);
   2017   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
   2018   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   2019   return kSuccess;
   2020 }
   2021 
   2022 void CodeGenerator::FinishFrame(Frame* frame) {
   2023   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2024 
   2025   const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
   2026   if (saves_fpu != 0) {
   2027     int count = base::bits::CountPopulation32(saves_fpu);
   2028     DCHECK(kNumCalleeSavedFPU == count);
   2029     frame->AllocateSavedCalleeRegisterSlots(count *
   2030                                             (kDoubleSize / kPointerSize));
   2031   }
   2032 
   2033   const RegList saves = descriptor->CalleeSavedRegisters();
   2034   if (saves != 0) {
   2035     int count = base::bits::CountPopulation32(saves);
   2036     DCHECK(kNumCalleeSaved == count + 1);
   2037     frame->AllocateSavedCalleeRegisterSlots(count);
   2038   }
   2039 }
   2040 
   2041 void CodeGenerator::AssembleConstructFrame() {
   2042   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2043   if (frame_access_state()->has_frame()) {
   2044     if (descriptor->IsCFunctionCall()) {
   2045       __ Push(ra, fp);
   2046       __ mov(fp, sp);
   2047     } else if (descriptor->IsJSFunctionCall()) {
   2048       __ Prologue(this->info()->GeneratePreagedPrologue());
   2049     } else {
   2050       __ StubPrologue(info()->GetOutputStackFrameType());
   2051     }
   2052   }
   2053 
   2054   int shrink_slots = frame()->GetSpillSlotCount();
   2055 
   2056   if (info()->is_osr()) {
   2057     // TurboFan OSR-compiled functions cannot be entered directly.
   2058     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   2059 
   2060     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   2061     // frame is still on the stack. Optimized code uses OSR values directly from
   2062     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   2063     // remaining stack slots.
   2064     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   2065     osr_pc_offset_ = __ pc_offset();
   2066     shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
   2067   }
   2068 
   2069   if (shrink_slots > 0) {
   2070     __ Dsubu(sp, sp, Operand(shrink_slots * kPointerSize));
   2071   }
   2072 
   2073   const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
   2074   if (saves_fpu != 0) {
   2075     // Save callee-saved FPU registers.
   2076     __ MultiPushFPU(saves_fpu);
   2077     DCHECK(kNumCalleeSavedFPU == base::bits::CountPopulation32(saves_fpu));
   2078   }
   2079 
   2080   const RegList saves = descriptor->CalleeSavedRegisters();
   2081   if (saves != 0) {
   2082     // Save callee-saved registers.
   2083     __ MultiPush(saves);
   2084     DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1);
   2085   }
   2086 }
   2087 
   2088 
   2089 void CodeGenerator::AssembleReturn() {
   2090   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   2091 
   2092   // Restore GP registers.
   2093   const RegList saves = descriptor->CalleeSavedRegisters();
   2094   if (saves != 0) {
   2095     __ MultiPop(saves);
   2096   }
   2097 
   2098   // Restore FPU registers.
   2099   const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
   2100   if (saves_fpu != 0) {
   2101     __ MultiPopFPU(saves_fpu);
   2102   }
   2103 
   2104   if (descriptor->IsCFunctionCall()) {
   2105     AssembleDeconstructFrame();
   2106   } else if (frame_access_state()->has_frame()) {
   2107     // Canonicalize JSFunction return sites for now.
   2108     if (return_label_.is_bound()) {
   2109       __ Branch(&return_label_);
   2110       return;
   2111     } else {
   2112       __ bind(&return_label_);
   2113       AssembleDeconstructFrame();
   2114     }
   2115   }
   2116   int pop_count = static_cast<int>(descriptor->StackParameterCount());
   2117   if (pop_count != 0) {
   2118     __ DropAndRet(pop_count);
   2119   } else {
   2120     __ Ret();
   2121   }
   2122 }
   2123 
   2124 
   2125 void CodeGenerator::AssembleMove(InstructionOperand* source,
   2126                                  InstructionOperand* destination) {
   2127   MipsOperandConverter g(this, nullptr);
   2128   // Dispatch on the source and destination operand kinds.  Not all
   2129   // combinations are possible.
   2130   if (source->IsRegister()) {
   2131     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2132     Register src = g.ToRegister(source);
   2133     if (destination->IsRegister()) {
   2134       __ mov(g.ToRegister(destination), src);
   2135     } else {
   2136       __ sd(src, g.ToMemOperand(destination));
   2137     }
   2138   } else if (source->IsStackSlot()) {
   2139     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   2140     MemOperand src = g.ToMemOperand(source);
   2141     if (destination->IsRegister()) {
   2142       __ ld(g.ToRegister(destination), src);
   2143     } else {
   2144       Register temp = kScratchReg;
   2145       __ ld(temp, src);
   2146       __ sd(temp, g.ToMemOperand(destination));
   2147     }
   2148   } else if (source->IsConstant()) {
   2149     Constant src = g.ToConstant(source);
   2150     if (destination->IsRegister() || destination->IsStackSlot()) {
   2151       Register dst =
   2152           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
   2153       switch (src.type()) {
   2154         case Constant::kInt32:
   2155           if (src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
   2156             __ li(dst, Operand(src.ToInt32(), src.rmode()));
   2157           } else {
   2158             __ li(dst, Operand(src.ToInt32()));
   2159           }
   2160           break;
   2161         case Constant::kFloat32:
   2162           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   2163           break;
   2164         case Constant::kInt64:
   2165           if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
   2166               src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
   2167             __ li(dst, Operand(src.ToInt64(), src.rmode()));
   2168           } else {
   2169             DCHECK(src.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
   2170             __ li(dst, Operand(src.ToInt64()));
   2171           }
   2172           break;
   2173         case Constant::kFloat64:
   2174           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   2175           break;
   2176         case Constant::kExternalReference:
   2177           __ li(dst, Operand(src.ToExternalReference()));
   2178           break;
   2179         case Constant::kHeapObject: {
   2180           Handle<HeapObject> src_object = src.ToHeapObject();
   2181           Heap::RootListIndex index;
   2182           int slot;
   2183           if (IsMaterializableFromFrame(src_object, &slot)) {
   2184             __ ld(dst, g.SlotToMemOperand(slot));
   2185           } else if (IsMaterializableFromRoot(src_object, &index)) {
   2186             __ LoadRoot(dst, index);
   2187           } else {
   2188             __ li(dst, src_object);
   2189           }
   2190           break;
   2191         }
   2192         case Constant::kRpoNumber:
   2193           UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
   2194           break;
   2195       }
   2196       if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
   2197     } else if (src.type() == Constant::kFloat32) {
   2198       if (destination->IsFPStackSlot()) {
   2199         MemOperand dst = g.ToMemOperand(destination);
   2200         __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
   2201         __ sw(at, dst);
   2202       } else {
   2203         FloatRegister dst = g.ToSingleRegister(destination);
   2204         __ Move(dst, src.ToFloat32());
   2205       }
   2206     } else {
   2207       DCHECK_EQ(Constant::kFloat64, src.type());
   2208       DoubleRegister dst = destination->IsFPRegister()
   2209                                ? g.ToDoubleRegister(destination)
   2210                                : kScratchDoubleReg;
   2211       __ Move(dst, src.ToFloat64());
   2212       if (destination->IsFPStackSlot()) {
   2213         __ sdc1(dst, g.ToMemOperand(destination));
   2214       }
   2215     }
   2216   } else if (source->IsFPRegister()) {
   2217     FPURegister src = g.ToDoubleRegister(source);
   2218     if (destination->IsFPRegister()) {
   2219       FPURegister dst = g.ToDoubleRegister(destination);
   2220       __ Move(dst, src);
   2221     } else {
   2222       DCHECK(destination->IsFPStackSlot());
   2223       __ sdc1(src, g.ToMemOperand(destination));
   2224     }
   2225   } else if (source->IsFPStackSlot()) {
   2226     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
   2227     MemOperand src = g.ToMemOperand(source);
   2228     if (destination->IsFPRegister()) {
   2229       __ ldc1(g.ToDoubleRegister(destination), src);
   2230     } else {
   2231       FPURegister temp = kScratchDoubleReg;
   2232       __ ldc1(temp, src);
   2233       __ sdc1(temp, g.ToMemOperand(destination));
   2234     }
   2235   } else {
   2236     UNREACHABLE();
   2237   }
   2238 }
   2239 
   2240 
   2241 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   2242                                  InstructionOperand* destination) {
   2243   MipsOperandConverter g(this, nullptr);
   2244   // Dispatch on the source and destination operand kinds.  Not all
   2245   // combinations are possible.
   2246   if (source->IsRegister()) {
   2247     // Register-register.
   2248     Register temp = kScratchReg;
   2249     Register src = g.ToRegister(source);
   2250     if (destination->IsRegister()) {
   2251       Register dst = g.ToRegister(destination);
   2252       __ Move(temp, src);
   2253       __ Move(src, dst);
   2254       __ Move(dst, temp);
   2255     } else {
   2256       DCHECK(destination->IsStackSlot());
   2257       MemOperand dst = g.ToMemOperand(destination);
   2258       __ mov(temp, src);
   2259       __ ld(src, dst);
   2260       __ sd(temp, dst);
   2261     }
   2262   } else if (source->IsStackSlot()) {
   2263     DCHECK(destination->IsStackSlot());
   2264     Register temp_0 = kScratchReg;
   2265     Register temp_1 = kScratchReg2;
   2266     MemOperand src = g.ToMemOperand(source);
   2267     MemOperand dst = g.ToMemOperand(destination);
   2268     __ ld(temp_0, src);
   2269     __ ld(temp_1, dst);
   2270     __ sd(temp_0, dst);
   2271     __ sd(temp_1, src);
   2272   } else if (source->IsFPRegister()) {
   2273     FPURegister temp = kScratchDoubleReg;
   2274     FPURegister src = g.ToDoubleRegister(source);
   2275     if (destination->IsFPRegister()) {
   2276       FPURegister dst = g.ToDoubleRegister(destination);
   2277       __ Move(temp, src);
   2278       __ Move(src, dst);
   2279       __ Move(dst, temp);
   2280     } else {
   2281       DCHECK(destination->IsFPStackSlot());
   2282       MemOperand dst = g.ToMemOperand(destination);
   2283       __ Move(temp, src);
   2284       __ ldc1(src, dst);
   2285       __ sdc1(temp, dst);
   2286     }
   2287   } else if (source->IsFPStackSlot()) {
   2288     DCHECK(destination->IsFPStackSlot());
   2289     Register temp_0 = kScratchReg;
   2290     FPURegister temp_1 = kScratchDoubleReg;
   2291     MemOperand src0 = g.ToMemOperand(source);
   2292     MemOperand src1(src0.rm(), src0.offset() + kIntSize);
   2293     MemOperand dst0 = g.ToMemOperand(destination);
   2294     MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
   2295     __ ldc1(temp_1, dst0);  // Save destination in temp_1.
   2296     __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
   2297     __ sw(temp_0, dst0);
   2298     __ lw(temp_0, src1);
   2299     __ sw(temp_0, dst1);
   2300     __ sdc1(temp_1, src0);
   2301   } else {
   2302     // No other combinations are possible.
   2303     UNREACHABLE();
   2304   }
   2305 }
   2306 
   2307 
   2308 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   2309   // On 64-bit MIPS we emit the jump tables inline.
   2310   UNREACHABLE();
   2311 }
   2312 
   2313 
   2314 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   2315   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   2316     return;
   2317   }
   2318 
   2319   int space_needed = Deoptimizer::patch_size();
   2320   // Ensure that we have enough space after the previous lazy-bailout
   2321   // instruction for patching the code here.
   2322   int current_pc = masm()->pc_offset();
   2323   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   2324     // Block tramoline pool emission for duration of padding.
   2325     v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
   2326         masm());
   2327     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   2328     DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
   2329     while (padding_size > 0) {
   2330       __ nop();
   2331       padding_size -= v8::internal::Assembler::kInstrSize;
   2332     }
   2333   }
   2334 }
   2335 
   2336 #undef __
   2337 
   2338 }  // namespace compiler
   2339 }  // namespace internal
   2340 }  // namespace v8
   2341