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