• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/assembler-inl.h"
6 #include "src/callable.h"
7 #include "src/compiler/code-generator-impl.h"
8 #include "src/compiler/code-generator.h"
9 #include "src/compiler/gap-resolver.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/osr.h"
12 #include "src/heap/heap-inl.h"
13 #include "src/mips64/constants-mips64.h"
14 #include "src/mips64/macro-assembler-mips64.h"
15 #include "src/optimized-compilation-info.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 #define __ tasm()->
22 
23 
24 // TODO(plind): consider renaming these macros.
25 #define TRACE_MSG(msg)                                                      \
26   PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
27          __LINE__)
28 
29 #define TRACE_UNIMPL()                                                       \
30   PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
31          __LINE__)
32 
33 
34 // Adds Mips-specific methods to convert InstructionOperands.
35 class MipsOperandConverter final : public InstructionOperandConverter {
36  public:
MipsOperandConverter(CodeGenerator * gen,Instruction * instr)37   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
38       : InstructionOperandConverter(gen, instr) {}
39 
OutputSingleRegister(size_t index=0)40   FloatRegister OutputSingleRegister(size_t index = 0) {
41     return ToSingleRegister(instr_->OutputAt(index));
42   }
43 
InputSingleRegister(size_t index)44   FloatRegister InputSingleRegister(size_t index) {
45     return ToSingleRegister(instr_->InputAt(index));
46   }
47 
ToSingleRegister(InstructionOperand * op)48   FloatRegister ToSingleRegister(InstructionOperand* op) {
49     // Single (Float) and Double register namespace is same on MIPS,
50     // both are typedefs of FPURegister.
51     return ToDoubleRegister(op);
52   }
53 
InputOrZeroRegister(size_t index)54   Register InputOrZeroRegister(size_t index) {
55     if (instr_->InputAt(index)->IsImmediate()) {
56       DCHECK_EQ(0, InputInt32(index));
57       return zero_reg;
58     }
59     return InputRegister(index);
60   }
61 
InputOrZeroDoubleRegister(size_t index)62   DoubleRegister InputOrZeroDoubleRegister(size_t index) {
63     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
64 
65     return InputDoubleRegister(index);
66   }
67 
InputOrZeroSingleRegister(size_t index)68   DoubleRegister InputOrZeroSingleRegister(size_t index) {
69     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
70 
71     return InputSingleRegister(index);
72   }
73 
InputImmediate(size_t index)74   Operand InputImmediate(size_t index) {
75     Constant constant = ToConstant(instr_->InputAt(index));
76     switch (constant.type()) {
77       case Constant::kInt32:
78         return Operand(constant.ToInt32());
79       case Constant::kInt64:
80         return Operand(constant.ToInt64());
81       case Constant::kFloat32:
82         return Operand::EmbeddedNumber(constant.ToFloat32());
83       case Constant::kFloat64:
84         return Operand::EmbeddedNumber(constant.ToFloat64().value());
85       case Constant::kExternalReference:
86       case Constant::kHeapObject:
87         // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
88         //    maybe not done on arm due to const pool ??
89         break;
90       case Constant::kRpoNumber:
91         UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
92         break;
93     }
94     UNREACHABLE();
95   }
96 
InputOperand(size_t index)97   Operand InputOperand(size_t index) {
98     InstructionOperand* op = instr_->InputAt(index);
99     if (op->IsRegister()) {
100       return Operand(ToRegister(op));
101     }
102     return InputImmediate(index);
103   }
104 
MemoryOperand(size_t * first_index)105   MemOperand MemoryOperand(size_t* first_index) {
106     const size_t index = *first_index;
107     switch (AddressingModeField::decode(instr_->opcode())) {
108       case kMode_None:
109         break;
110       case kMode_MRI:
111         *first_index += 2;
112         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
113       case kMode_MRR:
114         // TODO(plind): r6 address mode, to be implemented ...
115         UNREACHABLE();
116     }
117     UNREACHABLE();
118   }
119 
MemoryOperand(size_t index=0)120   MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
121 
ToMemOperand(InstructionOperand * op) const122   MemOperand ToMemOperand(InstructionOperand* op) const {
123     DCHECK_NOT_NULL(op);
124     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
125     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
126   }
127 
SlotToMemOperand(int slot) const128   MemOperand SlotToMemOperand(int slot) const {
129     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
130     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
131   }
132 };
133 
134 
HasRegisterInput(Instruction * instr,size_t index)135 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
136   return instr->InputAt(index)->IsRegister();
137 }
138 
139 
140 namespace {
141 
142 
143 class OutOfLineRecordWrite final : public OutOfLineCode {
144  public:
OutOfLineRecordWrite(CodeGenerator * gen,Register object,Register index,Register value,Register scratch0,Register scratch1,RecordWriteMode mode)145   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
146                        Register value, Register scratch0, Register scratch1,
147                        RecordWriteMode mode)
148       : OutOfLineCode(gen),
149         object_(object),
150         index_(index),
151         value_(value),
152         scratch0_(scratch0),
153         scratch1_(scratch1),
154         mode_(mode),
155         must_save_lr_(!gen->frame_access_state()->has_frame()),
156         zone_(gen->zone()) {}
157 
SaveRegisters(RegList registers)158   void SaveRegisters(RegList registers) {
159     DCHECK_LT(0, NumRegs(registers));
160     RegList regs = 0;
161     for (int i = 0; i < Register::kNumRegisters; ++i) {
162       if ((registers >> i) & 1u) {
163         regs |= Register::from_code(i).bit();
164       }
165     }
166     __ MultiPush(regs | ra.bit());
167   }
168 
RestoreRegisters(RegList registers)169   void RestoreRegisters(RegList registers) {
170     DCHECK_LT(0, NumRegs(registers));
171     RegList regs = 0;
172     for (int i = 0; i < Register::kNumRegisters; ++i) {
173       if ((registers >> i) & 1u) {
174         regs |= Register::from_code(i).bit();
175       }
176     }
177     __ MultiPop(regs | ra.bit());
178   }
179 
Generate()180   void Generate() final {
181     if (mode_ > RecordWriteMode::kValueIsPointer) {
182       __ JumpIfSmi(value_, exit());
183     }
184     __ CheckPageFlag(value_, scratch0_,
185                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
186                      exit());
187     __ Daddu(scratch1_, object_, index_);
188     RememberedSetAction const remembered_set_action =
189         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
190                                              : OMIT_REMEMBERED_SET;
191     SaveFPRegsMode const save_fp_mode =
192         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
193     if (must_save_lr_) {
194       // We need to save and restore ra if the frame was elided.
195       __ Push(ra);
196     }
197     __ CallRecordWriteStub(object_, scratch1_, remembered_set_action,
198                            save_fp_mode);
199     if (must_save_lr_) {
200       __ Pop(ra);
201     }
202   }
203 
204  private:
205   Register const object_;
206   Register const index_;
207   Register const value_;
208   Register const scratch0_;
209   Register const scratch1_;
210   RecordWriteMode const mode_;
211   bool must_save_lr_;
212   Zone* zone_;
213 };
214 
215 #define CREATE_OOL_CLASS(ool_name, tasm_ool_name, T)                 \
216   class ool_name final : public OutOfLineCode {                      \
217    public:                                                           \
218     ool_name(CodeGenerator* gen, T dst, T src1, T src2)              \
219         : OutOfLineCode(gen), dst_(dst), src1_(src1), src2_(src2) {} \
220                                                                      \
221     void Generate() final { __ tasm_ool_name(dst_, src1_, src2_); }  \
222                                                                      \
223    private:                                                          \
224     T const dst_;                                                    \
225     T const src1_;                                                   \
226     T const src2_;                                                   \
227   }
228 
229 CREATE_OOL_CLASS(OutOfLineFloat32Max, Float32MaxOutOfLine, FPURegister);
230 CREATE_OOL_CLASS(OutOfLineFloat32Min, Float32MinOutOfLine, FPURegister);
231 CREATE_OOL_CLASS(OutOfLineFloat64Max, Float64MaxOutOfLine, FPURegister);
232 CREATE_OOL_CLASS(OutOfLineFloat64Min, Float64MinOutOfLine, FPURegister);
233 
234 #undef CREATE_OOL_CLASS
235 
FlagsConditionToConditionCmp(FlagsCondition condition)236 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
237   switch (condition) {
238     case kEqual:
239       return eq;
240     case kNotEqual:
241       return ne;
242     case kSignedLessThan:
243       return lt;
244     case kSignedGreaterThanOrEqual:
245       return ge;
246     case kSignedLessThanOrEqual:
247       return le;
248     case kSignedGreaterThan:
249       return gt;
250     case kUnsignedLessThan:
251       return lo;
252     case kUnsignedGreaterThanOrEqual:
253       return hs;
254     case kUnsignedLessThanOrEqual:
255       return ls;
256     case kUnsignedGreaterThan:
257       return hi;
258     case kUnorderedEqual:
259     case kUnorderedNotEqual:
260       break;
261     default:
262       break;
263   }
264   UNREACHABLE();
265 }
266 
267 
FlagsConditionToConditionTst(FlagsCondition condition)268 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
269   switch (condition) {
270     case kNotEqual:
271       return ne;
272     case kEqual:
273       return eq;
274     default:
275       break;
276   }
277   UNREACHABLE();
278 }
279 
280 
FlagsConditionToConditionOvf(FlagsCondition condition)281 Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
282   switch (condition) {
283     case kOverflow:
284       return ne;
285     case kNotOverflow:
286       return eq;
287     default:
288       break;
289   }
290   UNREACHABLE();
291 }
292 
293 
FlagsConditionToConditionCmpFPU(bool & predicate,FlagsCondition condition)294 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
295                                              FlagsCondition condition) {
296   switch (condition) {
297     case kEqual:
298       predicate = true;
299       return EQ;
300     case kNotEqual:
301       predicate = false;
302       return EQ;
303     case kUnsignedLessThan:
304       predicate = true;
305       return OLT;
306     case kUnsignedGreaterThanOrEqual:
307       predicate = false;
308       return OLT;
309     case kUnsignedLessThanOrEqual:
310       predicate = true;
311       return OLE;
312     case kUnsignedGreaterThan:
313       predicate = false;
314       return OLE;
315     case kUnorderedEqual:
316     case kUnorderedNotEqual:
317       predicate = true;
318       break;
319     default:
320       predicate = true;
321       break;
322   }
323   UNREACHABLE();
324 }
325 
EmitWordLoadPoisoningIfNeeded(CodeGenerator * codegen,InstructionCode opcode,Instruction * instr,MipsOperandConverter & i)326 void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
327                                    InstructionCode opcode, Instruction* instr,
328                                    MipsOperandConverter& i) {
329   const MemoryAccessMode access_mode =
330       static_cast<MemoryAccessMode>(MiscField::decode(opcode));
331   if (access_mode == kMemoryAccessPoisoned) {
332     Register value = i.OutputRegister();
333     codegen->tasm()->And(value, value, kSpeculationPoisonRegister);
334   }
335 }
336 
337 }  // namespace
338 
339 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
340   do {                                                   \
341     __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
342     __ sync();                                           \
343   } while (0)
344 
345 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)               \
346   do {                                                         \
347     __ sync();                                                 \
348     __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
349     __ sync();                                                 \
350   } while (0)
351 
352 #define ASSEMBLE_ATOMIC_BINOP(bin_instr)                                 \
353   do {                                                                   \
354     Label binop;                                                         \
355     __ Daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
356     __ sync();                                                           \
357     __ bind(&binop);                                                     \
358     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));        \
359     __ bin_instr(i.TempRegister(1), i.OutputRegister(0),                 \
360                  Operand(i.InputRegister(2)));                           \
361     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));          \
362     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));    \
363     __ sync();                                                           \
364   } while (0)
365 
366 #define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr)               \
367   do {                                                                        \
368     Label binop;                                                              \
369     __ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));      \
370     __ andi(i.TempRegister(3), i.TempRegister(0), 0x3);                       \
371     __ Dsubu(i.TempRegister(0), i.TempRegister(0),                            \
372              Operand(i.TempRegister(3)));                                     \
373     __ sll(i.TempRegister(3), i.TempRegister(3), 3);                          \
374     __ sync();                                                                \
375     __ bind(&binop);                                                          \
376     __ Ll(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));               \
377     __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3), \
378                    size, sign_extend);                                        \
379     __ bin_instr(i.TempRegister(2), i.OutputRegister(0),                      \
380                  Operand(i.InputRegister(2)));                                \
381     __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3),    \
382                   size);                                                      \
383     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));               \
384     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));         \
385     __ sync();                                                                \
386   } while (0)
387 
388 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER()                               \
389   do {                                                                   \
390     Label exchange;                                                      \
391     __ sync();                                                           \
392     __ bind(&exchange);                                                  \
393     __ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
394     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));        \
395     __ mov(i.TempRegister(1), i.InputRegister(2));                       \
396     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));          \
397     __ BranchShort(&exchange, eq, i.TempRegister(1), Operand(zero_reg)); \
398     __ sync();                                                           \
399   } while (0)
400 
401 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(sign_extend, size)               \
402   do {                                                                        \
403     Label exchange;                                                           \
404     __ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));      \
405     __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                       \
406     __ Dsubu(i.TempRegister(0), i.TempRegister(0),                            \
407              Operand(i.TempRegister(1)));                                     \
408     __ sll(i.TempRegister(1), i.TempRegister(1), 3);                          \
409     __ sync();                                                                \
410     __ bind(&exchange);                                                       \
411     __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));               \
412     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \
413                    size, sign_extend);                                        \
414     __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1),   \
415                   size);                                                      \
416     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));               \
417     __ BranchShort(&exchange, eq, i.TempRegister(2), Operand(zero_reg));      \
418     __ sync();                                                                \
419   } while (0)
420 
421 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER()                       \
422   do {                                                                   \
423     Label compareExchange;                                               \
424     Label exit;                                                          \
425     __ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
426     __ sync();                                                           \
427     __ bind(&compareExchange);                                           \
428     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));        \
429     __ BranchShort(&exit, ne, i.InputRegister(2),                        \
430                    Operand(i.OutputRegister(0)));                        \
431     __ mov(i.TempRegister(2), i.InputRegister(3));                       \
432     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));          \
433     __ BranchShort(&compareExchange, eq, i.TempRegister(2),              \
434                    Operand(zero_reg));                                   \
435     __ bind(&exit);                                                      \
436     __ sync();                                                           \
437   } while (0)
438 
439 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(sign_extend, size)       \
440   do {                                                                        \
441     Label compareExchange;                                                    \
442     Label exit;                                                               \
443     __ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));      \
444     __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                       \
445     __ Dsubu(i.TempRegister(0), i.TempRegister(0),                            \
446              Operand(i.TempRegister(1)));                                     \
447     __ sll(i.TempRegister(1), i.TempRegister(1), 3);                          \
448     __ sync();                                                                \
449     __ bind(&compareExchange);                                                \
450     __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));               \
451     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \
452                    size, sign_extend);                                        \
453     __ BranchShort(&exit, ne, i.InputRegister(2),                             \
454                    Operand(i.OutputRegister(0)));                             \
455     __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1),   \
456                   size);                                                      \
457     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));               \
458     __ BranchShort(&compareExchange, eq, i.TempRegister(2),                   \
459                    Operand(zero_reg));                                        \
460     __ bind(&exit);                                                           \
461     __ sync();                                                                \
462   } while (0)
463 
464 #define ASSEMBLE_IEEE754_BINOP(name)                                        \
465   do {                                                                      \
466     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
467     __ PrepareCallCFunction(0, 2, kScratchReg);                             \
468     __ MovToFloatParameters(i.InputDoubleRegister(0),                       \
469                             i.InputDoubleRegister(1));                      \
470     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
471     /* Move the result in the double result register. */                    \
472     __ MovFromFloatResult(i.OutputDoubleRegister());                        \
473   } while (0)
474 
475 #define ASSEMBLE_IEEE754_UNOP(name)                                         \
476   do {                                                                      \
477     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
478     __ PrepareCallCFunction(0, 1, kScratchReg);                             \
479     __ MovToFloatParameter(i.InputDoubleRegister(0));                       \
480     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
481     /* Move the result in the double result register. */                    \
482     __ MovFromFloatResult(i.OutputDoubleRegister());                        \
483   } while (0)
484 
AssembleDeconstructFrame()485 void CodeGenerator::AssembleDeconstructFrame() {
486   __ mov(sp, fp);
487   __ Pop(ra, fp);
488 }
489 
AssemblePrepareTailCall()490 void CodeGenerator::AssemblePrepareTailCall() {
491   if (frame_access_state()->has_frame()) {
492     __ Ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
493     __ Ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
494   }
495   frame_access_state()->SetFrameAccessToSP();
496 }
497 
AssemblePopArgumentsAdaptorFrame(Register args_reg,Register scratch1,Register scratch2,Register scratch3)498 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
499                                                      Register scratch1,
500                                                      Register scratch2,
501                                                      Register scratch3) {
502   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
503   Label done;
504 
505   // Check if current frame is an arguments adaptor frame.
506   __ Ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset));
507   __ Branch(&done, ne, scratch3,
508             Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
509 
510   // Load arguments count from current arguments adaptor frame (note, it
511   // does not include receiver).
512   Register caller_args_count_reg = scratch1;
513   __ Ld(caller_args_count_reg,
514         MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
515   __ SmiUntag(caller_args_count_reg);
516 
517   ParameterCount callee_args_count(args_reg);
518   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
519                         scratch3);
520   __ bind(&done);
521 }
522 
523 namespace {
524 
AdjustStackPointerForTailCall(TurboAssembler * tasm,FrameAccessState * state,int new_slot_above_sp,bool allow_shrinkage=true)525 void AdjustStackPointerForTailCall(TurboAssembler* tasm,
526                                    FrameAccessState* state,
527                                    int new_slot_above_sp,
528                                    bool allow_shrinkage = true) {
529   int current_sp_offset = state->GetSPToFPSlotCount() +
530                           StandardFrameConstants::kFixedSlotCountAboveFp;
531   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
532   if (stack_slot_delta > 0) {
533     tasm->Dsubu(sp, sp, stack_slot_delta * kPointerSize);
534     state->IncreaseSPDelta(stack_slot_delta);
535   } else if (allow_shrinkage && stack_slot_delta < 0) {
536     tasm->Daddu(sp, sp, -stack_slot_delta * kPointerSize);
537     state->IncreaseSPDelta(stack_slot_delta);
538   }
539 }
540 
541 }  // namespace
542 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_stack_slot)543 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
544                                               int first_unused_stack_slot) {
545   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
546                                 first_unused_stack_slot, false);
547 }
548 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_stack_slot)549 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
550                                              int first_unused_stack_slot) {
551   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
552                                 first_unused_stack_slot);
553 }
554 
555 // Check that {kJavaScriptCallCodeStartRegister} is correct.
AssembleCodeStartRegisterCheck()556 void CodeGenerator::AssembleCodeStartRegisterCheck() {
557   __ ComputeCodeStartAddress(kScratchReg);
558   __ Assert(eq, AbortReason::kWrongFunctionCodeStart,
559             kJavaScriptCallCodeStartRegister, Operand(kScratchReg));
560 }
561 
562 // Check if the code object is marked for deoptimization. If it is, then it
563 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
564 // to:
565 //    1. read from memory the word that contains that bit, which can be found in
566 //       the flags in the referenced {CodeDataContainer} object;
567 //    2. test kMarkedForDeoptimizationBit in those flags; and
568 //    3. if it is not zero then it jumps to the builtin.
BailoutIfDeoptimized()569 void CodeGenerator::BailoutIfDeoptimized() {
570   int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
571   __ Ld(kScratchReg, MemOperand(kJavaScriptCallCodeStartRegister, offset));
572   __ Lw(kScratchReg,
573         FieldMemOperand(kScratchReg,
574                         CodeDataContainer::kKindSpecificFlagsOffset));
575   __ And(kScratchReg, kScratchReg,
576          Operand(1 << Code::kMarkedForDeoptimizationBit));
577   // Ensure we're not serializing (otherwise we'd need to use an indirection to
578   // access the builtin below).
579   DCHECK(!isolate()->ShouldLoadConstantsFromRootList());
580   Handle<Code> code = isolate()->builtins()->builtin_handle(
581       Builtins::kCompileLazyDeoptimizedCode);
582   __ Jump(code, RelocInfo::CODE_TARGET, ne, kScratchReg, Operand(zero_reg));
583 }
584 
GenerateSpeculationPoisonFromCodeStartRegister()585 void CodeGenerator::GenerateSpeculationPoisonFromCodeStartRegister() {
586   // Calculate a mask which has all bits set in the normal case, but has all
587   // bits cleared if we are speculatively executing the wrong PC.
588   //    difference = (current - expected) | (expected - current)
589   //    poison = ~(difference >> (kBitsPerPointer - 1))
590   __ ComputeCodeStartAddress(kScratchReg);
591   __ Move(kSpeculationPoisonRegister, kScratchReg);
592   __ subu(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
593           kJavaScriptCallCodeStartRegister);
594   __ subu(kJavaScriptCallCodeStartRegister, kJavaScriptCallCodeStartRegister,
595           kScratchReg);
596   __ or_(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
597          kJavaScriptCallCodeStartRegister);
598   __ sra(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
599          kBitsPerPointer - 1);
600   __ nor(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
601          kSpeculationPoisonRegister);
602 }
603 
AssembleRegisterArgumentPoisoning()604 void CodeGenerator::AssembleRegisterArgumentPoisoning() {
605   __ And(kJSFunctionRegister, kJSFunctionRegister, kSpeculationPoisonRegister);
606   __ And(kContextRegister, kContextRegister, kSpeculationPoisonRegister);
607   __ And(sp, sp, kSpeculationPoisonRegister);
608 }
609 
610 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)611 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
612     Instruction* instr) {
613   MipsOperandConverter i(this, instr);
614   InstructionCode opcode = instr->opcode();
615   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
616   switch (arch_opcode) {
617     case kArchCallCodeObject: {
618       if (instr->InputAt(0)->IsImmediate()) {
619         __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
620       } else {
621         Register reg = i.InputRegister(0);
622         DCHECK_IMPLIES(
623             HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
624             reg == kJavaScriptCallCodeStartRegister);
625         __ daddiu(reg, reg, Code::kHeaderSize - kHeapObjectTag);
626         __ Call(reg);
627       }
628       RecordCallPosition(instr);
629       frame_access_state()->ClearSPDelta();
630       break;
631     }
632     case kArchCallWasmFunction: {
633       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
634         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
635                                          i.TempRegister(0), i.TempRegister(1),
636                                          i.TempRegister(2));
637       }
638       if (instr->InputAt(0)->IsImmediate()) {
639         Constant constant = i.ToConstant(instr->InputAt(0));
640         Address wasm_code = static_cast<Address>(constant.ToInt64());
641         __ Call(wasm_code, constant.rmode());
642       } else {
643         __ daddiu(kScratchReg, i.InputRegister(0), 0);
644         __ Call(kScratchReg);
645       }
646       RecordCallPosition(instr);
647       frame_access_state()->ClearSPDelta();
648       break;
649     }
650     case kArchTailCallCodeObjectFromJSFunction:
651     case kArchTailCallCodeObject: {
652       if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
653         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
654                                          i.TempRegister(0), i.TempRegister(1),
655                                          i.TempRegister(2));
656       }
657       if (instr->InputAt(0)->IsImmediate()) {
658         __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
659       } else {
660         Register reg = i.InputRegister(0);
661         DCHECK_IMPLIES(
662             HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
663             reg == kJavaScriptCallCodeStartRegister);
664         __ daddiu(reg, reg, Code::kHeaderSize - kHeapObjectTag);
665         __ Jump(reg);
666       }
667       frame_access_state()->ClearSPDelta();
668       frame_access_state()->SetFrameAccessToDefault();
669       break;
670     }
671     case kArchTailCallWasm: {
672       if (instr->InputAt(0)->IsImmediate()) {
673         Constant constant = i.ToConstant(instr->InputAt(0));
674         Address wasm_code = static_cast<Address>(constant.ToInt64());
675         __ Jump(wasm_code, constant.rmode());
676       } else {
677         __ daddiu(kScratchReg, i.InputRegister(0), 0);
678         __ Jump(kScratchReg);
679       }
680       frame_access_state()->ClearSPDelta();
681       frame_access_state()->SetFrameAccessToDefault();
682       break;
683     }
684     case kArchTailCallAddress: {
685       CHECK(!instr->InputAt(0)->IsImmediate());
686       Register reg = i.InputRegister(0);
687       DCHECK_IMPLIES(
688           HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
689           reg == kJavaScriptCallCodeStartRegister);
690       __ Jump(reg);
691       frame_access_state()->ClearSPDelta();
692       frame_access_state()->SetFrameAccessToDefault();
693       break;
694     }
695     case kArchCallJSFunction: {
696       Register func = i.InputRegister(0);
697       if (FLAG_debug_code) {
698         // Check the function's context matches the context argument.
699         __ Ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
700         __ Assert(eq, AbortReason::kWrongFunctionContext, cp,
701                   Operand(kScratchReg));
702       }
703       static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch");
704       __ Ld(a2, FieldMemOperand(func, JSFunction::kCodeOffset));
705       __ Daddu(a2, a2, Operand(Code::kHeaderSize - kHeapObjectTag));
706       __ Call(a2);
707       RecordCallPosition(instr);
708       frame_access_state()->ClearSPDelta();
709       break;
710     }
711     case kArchPrepareCallCFunction: {
712       int const num_parameters = MiscField::decode(instr->opcode());
713       __ PrepareCallCFunction(num_parameters, kScratchReg);
714       // Frame alignment requires using FP-relative frame addressing.
715       frame_access_state()->SetFrameAccessToFP();
716       break;
717     }
718     case kArchSaveCallerRegisters: {
719       fp_mode_ =
720           static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
721       DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
722       // kReturnRegister0 should have been saved before entering the stub.
723       int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
724       DCHECK_EQ(0, bytes % kPointerSize);
725       DCHECK_EQ(0, frame_access_state()->sp_delta());
726       frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
727       DCHECK(!caller_registers_saved_);
728       caller_registers_saved_ = true;
729       break;
730     }
731     case kArchRestoreCallerRegisters: {
732       DCHECK(fp_mode_ ==
733              static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
734       DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
735       // Don't overwrite the returned value.
736       int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
737       frame_access_state()->IncreaseSPDelta(-(bytes / kPointerSize));
738       DCHECK_EQ(0, frame_access_state()->sp_delta());
739       DCHECK(caller_registers_saved_);
740       caller_registers_saved_ = false;
741       break;
742     }
743     case kArchPrepareTailCall:
744       AssemblePrepareTailCall();
745       break;
746     case kArchCallCFunction: {
747       int const num_parameters = MiscField::decode(instr->opcode());
748       if (instr->InputAt(0)->IsImmediate()) {
749         ExternalReference ref = i.InputExternalReference(0);
750         __ CallCFunction(ref, num_parameters);
751       } else {
752         Register func = i.InputRegister(0);
753         __ CallCFunction(func, num_parameters);
754       }
755       frame_access_state()->SetFrameAccessToDefault();
756       // Ideally, we should decrement SP delta to match the change of stack
757       // pointer in CallCFunction. However, for certain architectures (e.g.
758       // ARM), there may be more strict alignment requirement, causing old SP
759       // to be saved on the stack. In those cases, we can not calculate the SP
760       // delta statically.
761       frame_access_state()->ClearSPDelta();
762       if (caller_registers_saved_) {
763         // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
764         // Here, we assume the sequence to be:
765         //   kArchSaveCallerRegisters;
766         //   kArchCallCFunction;
767         //   kArchRestoreCallerRegisters;
768         int bytes =
769             __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
770         frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
771       }
772       break;
773     }
774     case kArchJmp:
775       AssembleArchJump(i.InputRpo(0));
776       break;
777     case kArchBinarySearchSwitch:
778       AssembleArchBinarySearchSwitch(instr);
779       break;
780     case kArchLookupSwitch:
781       AssembleArchLookupSwitch(instr);
782       break;
783     case kArchTableSwitch:
784       AssembleArchTableSwitch(instr);
785       break;
786     case kArchDebugAbort:
787       DCHECK(i.InputRegister(0) == a0);
788       if (!frame_access_state()->has_frame()) {
789         // We don't actually want to generate a pile of code for this, so just
790         // claim there is a stack frame, without generating one.
791         FrameScope scope(tasm(), StackFrame::NONE);
792         __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
793                 RelocInfo::CODE_TARGET);
794       } else {
795         __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
796                 RelocInfo::CODE_TARGET);
797       }
798       __ stop("kArchDebugAbort");
799       break;
800     case kArchDebugBreak:
801       __ stop("kArchDebugBreak");
802       break;
803     case kArchComment:
804       __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)));
805       break;
806     case kArchNop:
807     case kArchThrowTerminator:
808       // don't emit code for nops.
809       break;
810     case kArchDeoptimize: {
811       int deopt_state_id =
812           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
813       CodeGenResult result =
814           AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
815       if (result != kSuccess) return result;
816       break;
817     }
818     case kArchRet:
819       AssembleReturn(instr->InputAt(0));
820       break;
821     case kArchStackPointer:
822       __ mov(i.OutputRegister(), sp);
823       break;
824     case kArchFramePointer:
825       __ mov(i.OutputRegister(), fp);
826       break;
827     case kArchParentFramePointer:
828       if (frame_access_state()->has_frame()) {
829         __ Ld(i.OutputRegister(), MemOperand(fp, 0));
830       } else {
831         __ mov(i.OutputRegister(), fp);
832       }
833       break;
834     case kArchTruncateDoubleToI:
835       __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
836                            i.InputDoubleRegister(0), DetermineStubCallMode());
837       break;
838     case kArchStoreWithWriteBarrier: {
839       RecordWriteMode mode =
840           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
841       Register object = i.InputRegister(0);
842       Register index = i.InputRegister(1);
843       Register value = i.InputRegister(2);
844       Register scratch0 = i.TempRegister(0);
845       Register scratch1 = i.TempRegister(1);
846       auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
847                                                    scratch0, scratch1, mode);
848       __ Daddu(kScratchReg, object, index);
849       __ Sd(value, MemOperand(kScratchReg));
850       __ CheckPageFlag(object, scratch0,
851                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
852                        ool->entry());
853       __ bind(ool->exit());
854       break;
855     }
856     case kArchStackSlot: {
857       FrameOffset offset =
858           frame_access_state()->GetFrameOffset(i.InputInt32(0));
859       Register base_reg = offset.from_stack_pointer() ? sp : fp;
860       __ Daddu(i.OutputRegister(), base_reg, Operand(offset.offset()));
861       int alignment = i.InputInt32(1);
862       DCHECK(alignment == 0 || alignment == 4 || alignment == 8 ||
863              alignment == 16);
864       if (FLAG_debug_code && alignment > 0) {
865         // Verify that the output_register is properly aligned
866         __ And(kScratchReg, i.OutputRegister(), Operand(kPointerSize - 1));
867         __ Assert(eq, AbortReason::kAllocationIsNotDoubleAligned, kScratchReg,
868                   Operand(zero_reg));
869       }
870       if (alignment == 2 * kPointerSize) {
871         Label done;
872         __ Daddu(kScratchReg, base_reg, Operand(offset.offset()));
873         __ And(kScratchReg, kScratchReg, Operand(alignment - 1));
874         __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg));
875         __ Daddu(i.OutputRegister(), i.OutputRegister(), kPointerSize);
876         __ bind(&done);
877       } else if (alignment > 2 * kPointerSize) {
878         Label done;
879         __ Daddu(kScratchReg, base_reg, Operand(offset.offset()));
880         __ And(kScratchReg, kScratchReg, Operand(alignment - 1));
881         __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg));
882         __ li(kScratchReg2, alignment);
883         __ Dsubu(kScratchReg2, kScratchReg2, Operand(kScratchReg));
884         __ Daddu(i.OutputRegister(), i.OutputRegister(), kScratchReg2);
885         __ bind(&done);
886       }
887 
888       break;
889     }
890     case kArchWordPoisonOnSpeculation:
891       __ And(i.OutputRegister(), i.InputRegister(0),
892              kSpeculationPoisonRegister);
893       break;
894     case kIeee754Float64Acos:
895       ASSEMBLE_IEEE754_UNOP(acos);
896       break;
897     case kIeee754Float64Acosh:
898       ASSEMBLE_IEEE754_UNOP(acosh);
899       break;
900     case kIeee754Float64Asin:
901       ASSEMBLE_IEEE754_UNOP(asin);
902       break;
903     case kIeee754Float64Asinh:
904       ASSEMBLE_IEEE754_UNOP(asinh);
905       break;
906     case kIeee754Float64Atan:
907       ASSEMBLE_IEEE754_UNOP(atan);
908       break;
909     case kIeee754Float64Atanh:
910       ASSEMBLE_IEEE754_UNOP(atanh);
911       break;
912     case kIeee754Float64Atan2:
913       ASSEMBLE_IEEE754_BINOP(atan2);
914       break;
915     case kIeee754Float64Cos:
916       ASSEMBLE_IEEE754_UNOP(cos);
917       break;
918     case kIeee754Float64Cosh:
919       ASSEMBLE_IEEE754_UNOP(cosh);
920       break;
921     case kIeee754Float64Cbrt:
922       ASSEMBLE_IEEE754_UNOP(cbrt);
923       break;
924     case kIeee754Float64Exp:
925       ASSEMBLE_IEEE754_UNOP(exp);
926       break;
927     case kIeee754Float64Expm1:
928       ASSEMBLE_IEEE754_UNOP(expm1);
929       break;
930     case kIeee754Float64Log:
931       ASSEMBLE_IEEE754_UNOP(log);
932       break;
933     case kIeee754Float64Log1p:
934       ASSEMBLE_IEEE754_UNOP(log1p);
935       break;
936     case kIeee754Float64Log2:
937       ASSEMBLE_IEEE754_UNOP(log2);
938       break;
939     case kIeee754Float64Log10:
940       ASSEMBLE_IEEE754_UNOP(log10);
941       break;
942     case kIeee754Float64Pow: {
943       __ Call(BUILTIN_CODE(isolate(), MathPowInternal), RelocInfo::CODE_TARGET);
944       break;
945     }
946     case kIeee754Float64Sin:
947       ASSEMBLE_IEEE754_UNOP(sin);
948       break;
949     case kIeee754Float64Sinh:
950       ASSEMBLE_IEEE754_UNOP(sinh);
951       break;
952     case kIeee754Float64Tan:
953       ASSEMBLE_IEEE754_UNOP(tan);
954       break;
955     case kIeee754Float64Tanh:
956       ASSEMBLE_IEEE754_UNOP(tanh);
957       break;
958     case kMips64Add:
959       __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
960       break;
961     case kMips64Dadd:
962       __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
963       break;
964     case kMips64DaddOvf:
965       __ DaddOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
966                       kScratchReg);
967       break;
968     case kMips64Sub:
969       __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
970       break;
971     case kMips64Dsub:
972       __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
973       break;
974     case kMips64DsubOvf:
975       __ DsubOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
976                       kScratchReg);
977       break;
978     case kMips64Mul:
979       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
980       break;
981     case kMips64MulOvf:
982       __ MulOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
983                      kScratchReg);
984       break;
985     case kMips64MulHigh:
986       __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
987       break;
988     case kMips64MulHighU:
989       __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
990       break;
991     case kMips64DMulHigh:
992       __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
993       break;
994     case kMips64Div:
995       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
996       if (kArchVariant == kMips64r6) {
997         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
998       } else {
999         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1000       }
1001       break;
1002     case kMips64DivU:
1003       __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1004       if (kArchVariant == kMips64r6) {
1005         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1006       } else {
1007         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1008       }
1009       break;
1010     case kMips64Mod:
1011       __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1012       break;
1013     case kMips64ModU:
1014       __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1015       break;
1016     case kMips64Dmul:
1017       __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1018       break;
1019     case kMips64Ddiv:
1020       __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1021       if (kArchVariant == kMips64r6) {
1022         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1023       } else {
1024         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1025       }
1026       break;
1027     case kMips64DdivU:
1028       __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1029       if (kArchVariant == kMips64r6) {
1030         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1031       } else {
1032         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1033       }
1034       break;
1035     case kMips64Dmod:
1036       __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1037       break;
1038     case kMips64DmodU:
1039       __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1040       break;
1041     case kMips64Dlsa:
1042       DCHECK(instr->InputAt(2)->IsImmediate());
1043       __ Dlsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1044               i.InputInt8(2));
1045       break;
1046     case kMips64Lsa:
1047       DCHECK(instr->InputAt(2)->IsImmediate());
1048       __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1049              i.InputInt8(2));
1050       break;
1051     case kMips64And:
1052       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1053       break;
1054     case kMips64And32:
1055       if (instr->InputAt(1)->IsRegister()) {
1056         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1057         __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1058         __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1059       } else {
1060         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1061         __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1062       }
1063       break;
1064     case kMips64Or:
1065       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1066       break;
1067     case kMips64Or32:
1068       if (instr->InputAt(1)->IsRegister()) {
1069         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1070         __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1071         __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1072       } else {
1073         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1074         __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1075       }
1076       break;
1077     case kMips64Nor:
1078       if (instr->InputAt(1)->IsRegister()) {
1079         __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1080       } else {
1081         DCHECK_EQ(0, i.InputOperand(1).immediate());
1082         __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1083       }
1084       break;
1085     case kMips64Nor32:
1086       if (instr->InputAt(1)->IsRegister()) {
1087         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1088         __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1089         __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1090       } else {
1091         DCHECK_EQ(0, i.InputOperand(1).immediate());
1092         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1093         __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1094       }
1095       break;
1096     case kMips64Xor:
1097       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1098       break;
1099     case kMips64Xor32:
1100       if (instr->InputAt(1)->IsRegister()) {
1101         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1102         __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1103         __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1104       } else {
1105         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1106         __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1107       }
1108       break;
1109     case kMips64Clz:
1110       __ Clz(i.OutputRegister(), i.InputRegister(0));
1111       break;
1112     case kMips64Dclz:
1113       __ dclz(i.OutputRegister(), i.InputRegister(0));
1114       break;
1115     case kMips64Ctz: {
1116       Register src = i.InputRegister(0);
1117       Register dst = i.OutputRegister();
1118       __ Ctz(dst, src);
1119     } break;
1120     case kMips64Dctz: {
1121       Register src = i.InputRegister(0);
1122       Register dst = i.OutputRegister();
1123       __ Dctz(dst, src);
1124     } break;
1125     case kMips64Popcnt: {
1126       Register src = i.InputRegister(0);
1127       Register dst = i.OutputRegister();
1128       __ Popcnt(dst, src);
1129     } break;
1130     case kMips64Dpopcnt: {
1131       Register src = i.InputRegister(0);
1132       Register dst = i.OutputRegister();
1133       __ Dpopcnt(dst, src);
1134     } break;
1135     case kMips64Shl:
1136       if (instr->InputAt(1)->IsRegister()) {
1137         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1138       } else {
1139         int64_t imm = i.InputOperand(1).immediate();
1140         __ sll(i.OutputRegister(), i.InputRegister(0),
1141                static_cast<uint16_t>(imm));
1142       }
1143       break;
1144     case kMips64Shr:
1145       if (instr->InputAt(1)->IsRegister()) {
1146         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1147         __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1148       } else {
1149         int64_t imm = i.InputOperand(1).immediate();
1150         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1151         __ srl(i.OutputRegister(), i.InputRegister(0),
1152                static_cast<uint16_t>(imm));
1153       }
1154       break;
1155     case kMips64Sar:
1156       if (instr->InputAt(1)->IsRegister()) {
1157         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1158         __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1159       } else {
1160         int64_t imm = i.InputOperand(1).immediate();
1161         __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1162         __ sra(i.OutputRegister(), i.InputRegister(0),
1163                static_cast<uint16_t>(imm));
1164       }
1165       break;
1166     case kMips64Ext:
1167       __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1168              i.InputInt8(2));
1169       break;
1170     case kMips64Ins:
1171       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1172         __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1173       } else {
1174         __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1175                i.InputInt8(2));
1176       }
1177       break;
1178     case kMips64Dext: {
1179       __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1180               i.InputInt8(2));
1181       break;
1182     }
1183     case kMips64Dins:
1184       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1185         __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1186       } else {
1187         __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1188                 i.InputInt8(2));
1189       }
1190       break;
1191     case kMips64Dshl:
1192       if (instr->InputAt(1)->IsRegister()) {
1193         __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1194       } else {
1195         int64_t imm = i.InputOperand(1).immediate();
1196         if (imm < 32) {
1197           __ dsll(i.OutputRegister(), i.InputRegister(0),
1198                   static_cast<uint16_t>(imm));
1199         } else {
1200           __ dsll32(i.OutputRegister(), i.InputRegister(0),
1201                     static_cast<uint16_t>(imm - 32));
1202         }
1203       }
1204       break;
1205     case kMips64Dshr:
1206       if (instr->InputAt(1)->IsRegister()) {
1207         __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1208       } else {
1209         int64_t imm = i.InputOperand(1).immediate();
1210         if (imm < 32) {
1211           __ dsrl(i.OutputRegister(), i.InputRegister(0),
1212                   static_cast<uint16_t>(imm));
1213         } else {
1214           __ dsrl32(i.OutputRegister(), i.InputRegister(0),
1215                     static_cast<uint16_t>(imm - 32));
1216         }
1217       }
1218       break;
1219     case kMips64Dsar:
1220       if (instr->InputAt(1)->IsRegister()) {
1221         __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1222       } else {
1223         int64_t imm = i.InputOperand(1).immediate();
1224         if (imm < 32) {
1225           __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
1226         } else {
1227           __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
1228         }
1229       }
1230       break;
1231     case kMips64Ror:
1232       __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1233       break;
1234     case kMips64Dror:
1235       __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1236       break;
1237     case kMips64Tst:
1238       __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1239       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1240       break;
1241     case kMips64Cmp:
1242       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1243       break;
1244     case kMips64Mov:
1245       // TODO(plind): Should we combine mov/li like this, or use separate instr?
1246       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1247       if (HasRegisterInput(instr, 0)) {
1248         __ mov(i.OutputRegister(), i.InputRegister(0));
1249       } else {
1250         __ li(i.OutputRegister(), i.InputOperand(0));
1251       }
1252       break;
1253 
1254     case kMips64CmpS: {
1255       FPURegister left = i.InputOrZeroSingleRegister(0);
1256       FPURegister right = i.InputOrZeroSingleRegister(1);
1257       bool predicate;
1258       FPUCondition cc =
1259           FlagsConditionToConditionCmpFPU(predicate, instr->flags_condition());
1260 
1261       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1262           !__ IsDoubleZeroRegSet()) {
1263         __ Move(kDoubleRegZero, 0.0);
1264       }
1265 
1266       __ CompareF32(cc, left, right);
1267     } break;
1268     case kMips64AddS:
1269       // TODO(plind): add special case: combine mult & add.
1270       __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1271                i.InputDoubleRegister(1));
1272       break;
1273     case kMips64SubS:
1274       __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1275                i.InputDoubleRegister(1));
1276       break;
1277     case kMips64MulS:
1278       // TODO(plind): add special case: right op is -1.0, see arm port.
1279       __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1280                i.InputDoubleRegister(1));
1281       break;
1282     case kMips64DivS:
1283       __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1284                i.InputDoubleRegister(1));
1285       break;
1286     case kMips64ModS: {
1287       // TODO(bmeurer): We should really get rid of this special instruction,
1288       // and generate a CallAddress instruction instead.
1289       FrameScope scope(tasm(), StackFrame::MANUAL);
1290       __ PrepareCallCFunction(0, 2, kScratchReg);
1291       __ MovToFloatParameters(i.InputDoubleRegister(0),
1292                               i.InputDoubleRegister(1));
1293       // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
1294       __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1295       // Move the result in the double result register.
1296       __ MovFromFloatResult(i.OutputSingleRegister());
1297       break;
1298     }
1299     case kMips64AbsS:
1300       __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1301       break;
1302     case kMips64NegS:
1303       __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1304       break;
1305     case kMips64SqrtS: {
1306       __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1307       break;
1308     }
1309     case kMips64MaxS:
1310       __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1311                i.InputDoubleRegister(1));
1312       break;
1313     case kMips64MinS:
1314       __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1315                i.InputDoubleRegister(1));
1316       break;
1317     case kMips64CmpD: {
1318       FPURegister left = i.InputOrZeroDoubleRegister(0);
1319       FPURegister right = i.InputOrZeroDoubleRegister(1);
1320       bool predicate;
1321       FPUCondition cc =
1322           FlagsConditionToConditionCmpFPU(predicate, instr->flags_condition());
1323       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1324           !__ IsDoubleZeroRegSet()) {
1325         __ Move(kDoubleRegZero, 0.0);
1326       }
1327       __ CompareF64(cc, left, right);
1328     } break;
1329     case kMips64AddD:
1330       // TODO(plind): add special case: combine mult & add.
1331       __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1332                i.InputDoubleRegister(1));
1333       break;
1334     case kMips64SubD:
1335       __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1336                i.InputDoubleRegister(1));
1337       break;
1338     case kMips64MulD:
1339       // TODO(plind): add special case: right op is -1.0, see arm port.
1340       __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1341                i.InputDoubleRegister(1));
1342       break;
1343     case kMips64DivD:
1344       __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1345                i.InputDoubleRegister(1));
1346       break;
1347     case kMips64ModD: {
1348       // TODO(bmeurer): We should really get rid of this special instruction,
1349       // and generate a CallAddress instruction instead.
1350       FrameScope scope(tasm(), StackFrame::MANUAL);
1351       __ PrepareCallCFunction(0, 2, kScratchReg);
1352       __ MovToFloatParameters(i.InputDoubleRegister(0),
1353                               i.InputDoubleRegister(1));
1354       __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1355       // Move the result in the double result register.
1356       __ MovFromFloatResult(i.OutputDoubleRegister());
1357       break;
1358     }
1359     case kMips64AbsD:
1360       __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1361       break;
1362     case kMips64NegD:
1363       __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1364       break;
1365     case kMips64SqrtD: {
1366       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1367       break;
1368     }
1369     case kMips64MaxD:
1370       __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1371                i.InputDoubleRegister(1));
1372       break;
1373     case kMips64MinD:
1374       __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1375                i.InputDoubleRegister(1));
1376       break;
1377     case kMips64Float64RoundDown: {
1378       __ Floor_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1379       break;
1380     }
1381     case kMips64Float32RoundDown: {
1382       __ Floor_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1383       break;
1384     }
1385     case kMips64Float64RoundTruncate: {
1386       __ Trunc_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1387       break;
1388     }
1389     case kMips64Float32RoundTruncate: {
1390       __ Trunc_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1391       break;
1392     }
1393     case kMips64Float64RoundUp: {
1394       __ Ceil_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1395       break;
1396     }
1397     case kMips64Float32RoundUp: {
1398       __ Ceil_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1399       break;
1400     }
1401     case kMips64Float64RoundTiesEven: {
1402       __ Round_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1403       break;
1404     }
1405     case kMips64Float32RoundTiesEven: {
1406       __ Round_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1407       break;
1408     }
1409     case kMips64Float32Max: {
1410       FPURegister dst = i.OutputSingleRegister();
1411       FPURegister src1 = i.InputSingleRegister(0);
1412       FPURegister src2 = i.InputSingleRegister(1);
1413       auto ool = new (zone()) OutOfLineFloat32Max(this, dst, src1, src2);
1414       __ Float32Max(dst, src1, src2, ool->entry());
1415       __ bind(ool->exit());
1416       break;
1417     }
1418     case kMips64Float64Max: {
1419       FPURegister dst = i.OutputDoubleRegister();
1420       FPURegister src1 = i.InputDoubleRegister(0);
1421       FPURegister src2 = i.InputDoubleRegister(1);
1422       auto ool = new (zone()) OutOfLineFloat64Max(this, dst, src1, src2);
1423       __ Float64Max(dst, src1, src2, ool->entry());
1424       __ bind(ool->exit());
1425       break;
1426     }
1427     case kMips64Float32Min: {
1428       FPURegister dst = i.OutputSingleRegister();
1429       FPURegister src1 = i.InputSingleRegister(0);
1430       FPURegister src2 = i.InputSingleRegister(1);
1431       auto ool = new (zone()) OutOfLineFloat32Min(this, dst, src1, src2);
1432       __ Float32Min(dst, src1, src2, ool->entry());
1433       __ bind(ool->exit());
1434       break;
1435     }
1436     case kMips64Float64Min: {
1437       FPURegister dst = i.OutputDoubleRegister();
1438       FPURegister src1 = i.InputDoubleRegister(0);
1439       FPURegister src2 = i.InputDoubleRegister(1);
1440       auto ool = new (zone()) OutOfLineFloat64Min(this, dst, src1, src2);
1441       __ Float64Min(dst, src1, src2, ool->entry());
1442       __ bind(ool->exit());
1443       break;
1444     }
1445     case kMips64Float64SilenceNaN:
1446       __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1447       break;
1448     case kMips64CvtSD:
1449       __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1450       break;
1451     case kMips64CvtDS:
1452       __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1453       break;
1454     case kMips64CvtDW: {
1455       FPURegister scratch = kScratchDoubleReg;
1456       __ mtc1(i.InputRegister(0), scratch);
1457       __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1458       break;
1459     }
1460     case kMips64CvtSW: {
1461       FPURegister scratch = kScratchDoubleReg;
1462       __ mtc1(i.InputRegister(0), scratch);
1463       __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1464       break;
1465     }
1466     case kMips64CvtSUw: {
1467       __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1468       break;
1469     }
1470     case kMips64CvtSL: {
1471       FPURegister scratch = kScratchDoubleReg;
1472       __ dmtc1(i.InputRegister(0), scratch);
1473       __ cvt_s_l(i.OutputDoubleRegister(), scratch);
1474       break;
1475     }
1476     case kMips64CvtDL: {
1477       FPURegister scratch = kScratchDoubleReg;
1478       __ dmtc1(i.InputRegister(0), scratch);
1479       __ cvt_d_l(i.OutputDoubleRegister(), scratch);
1480       break;
1481     }
1482     case kMips64CvtDUw: {
1483       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1484       break;
1485     }
1486     case kMips64CvtDUl: {
1487       __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1488       break;
1489     }
1490     case kMips64CvtSUl: {
1491       __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1492       break;
1493     }
1494     case kMips64FloorWD: {
1495       FPURegister scratch = kScratchDoubleReg;
1496       __ floor_w_d(scratch, i.InputDoubleRegister(0));
1497       __ mfc1(i.OutputRegister(), scratch);
1498       break;
1499     }
1500     case kMips64CeilWD: {
1501       FPURegister scratch = kScratchDoubleReg;
1502       __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1503       __ mfc1(i.OutputRegister(), scratch);
1504       break;
1505     }
1506     case kMips64RoundWD: {
1507       FPURegister scratch = kScratchDoubleReg;
1508       __ round_w_d(scratch, i.InputDoubleRegister(0));
1509       __ mfc1(i.OutputRegister(), scratch);
1510       break;
1511     }
1512     case kMips64TruncWD: {
1513       FPURegister scratch = kScratchDoubleReg;
1514       // Other arches use round to zero here, so we follow.
1515       __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1516       __ mfc1(i.OutputRegister(), scratch);
1517       break;
1518     }
1519     case kMips64FloorWS: {
1520       FPURegister scratch = kScratchDoubleReg;
1521       __ floor_w_s(scratch, i.InputDoubleRegister(0));
1522       __ mfc1(i.OutputRegister(), scratch);
1523       break;
1524     }
1525     case kMips64CeilWS: {
1526       FPURegister scratch = kScratchDoubleReg;
1527       __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1528       __ mfc1(i.OutputRegister(), scratch);
1529       break;
1530     }
1531     case kMips64RoundWS: {
1532       FPURegister scratch = kScratchDoubleReg;
1533       __ round_w_s(scratch, i.InputDoubleRegister(0));
1534       __ mfc1(i.OutputRegister(), scratch);
1535       break;
1536     }
1537     case kMips64TruncWS: {
1538       FPURegister scratch = kScratchDoubleReg;
1539       __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1540       __ mfc1(i.OutputRegister(), scratch);
1541       // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1542       // because INT32_MIN allows easier out-of-bounds detection.
1543       __ addiu(kScratchReg, i.OutputRegister(), 1);
1544       __ slt(kScratchReg2, kScratchReg, i.OutputRegister());
1545       __ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
1546       break;
1547     }
1548     case kMips64TruncLS: {
1549       FPURegister scratch = kScratchDoubleReg;
1550       Register tmp_fcsr = kScratchReg;
1551       Register result = kScratchReg2;
1552 
1553       bool load_status = instr->OutputCount() > 1;
1554       if (load_status) {
1555         // Save FCSR.
1556         __ cfc1(tmp_fcsr, FCSR);
1557         // Clear FPU flags.
1558         __ ctc1(zero_reg, FCSR);
1559       }
1560       // Other arches use round to zero here, so we follow.
1561       __ trunc_l_s(scratch, i.InputDoubleRegister(0));
1562       __ dmfc1(i.OutputRegister(), scratch);
1563       if (load_status) {
1564         __ cfc1(result, FCSR);
1565         // Check for overflow and NaNs.
1566         __ andi(result, result,
1567                 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1568         __ Slt(result, zero_reg, result);
1569         __ xori(result, result, 1);
1570         __ mov(i.OutputRegister(1), result);
1571         // Restore FCSR
1572         __ ctc1(tmp_fcsr, FCSR);
1573       }
1574       break;
1575     }
1576     case kMips64TruncLD: {
1577       FPURegister scratch = kScratchDoubleReg;
1578       Register tmp_fcsr = kScratchReg;
1579       Register result = kScratchReg2;
1580 
1581       bool load_status = instr->OutputCount() > 1;
1582       if (load_status) {
1583         // Save FCSR.
1584         __ cfc1(tmp_fcsr, FCSR);
1585         // Clear FPU flags.
1586         __ ctc1(zero_reg, FCSR);
1587       }
1588       // Other arches use round to zero here, so we follow.
1589       __ trunc_l_d(scratch, i.InputDoubleRegister(0));
1590       __ dmfc1(i.OutputRegister(0), scratch);
1591       if (load_status) {
1592         __ cfc1(result, FCSR);
1593         // Check for overflow and NaNs.
1594         __ andi(result, result,
1595                 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1596         __ Slt(result, zero_reg, result);
1597         __ xori(result, result, 1);
1598         __ mov(i.OutputRegister(1), result);
1599         // Restore FCSR
1600         __ ctc1(tmp_fcsr, FCSR);
1601       }
1602       break;
1603     }
1604     case kMips64TruncUwD: {
1605       FPURegister scratch = kScratchDoubleReg;
1606       __ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1607       break;
1608     }
1609     case kMips64TruncUwS: {
1610       FPURegister scratch = kScratchDoubleReg;
1611       __ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1612       // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1613       // because 0 allows easier out-of-bounds detection.
1614       __ addiu(kScratchReg, i.OutputRegister(), 1);
1615       __ Movz(i.OutputRegister(), zero_reg, kScratchReg);
1616       break;
1617     }
1618     case kMips64TruncUlS: {
1619       FPURegister scratch = kScratchDoubleReg;
1620       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1621       __ Trunc_ul_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch,
1622                     result);
1623       break;
1624     }
1625     case kMips64TruncUlD: {
1626       FPURegister scratch = kScratchDoubleReg;
1627       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1628       __ Trunc_ul_d(i.OutputRegister(0), i.InputDoubleRegister(0), scratch,
1629                     result);
1630       break;
1631     }
1632     case kMips64BitcastDL:
1633       __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0));
1634       break;
1635     case kMips64BitcastLD:
1636       __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister());
1637       break;
1638     case kMips64Float64ExtractLowWord32:
1639       __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1640       break;
1641     case kMips64Float64ExtractHighWord32:
1642       __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1643       break;
1644     case kMips64Float64InsertLowWord32:
1645       __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1646       break;
1647     case kMips64Float64InsertHighWord32:
1648       __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1649       break;
1650     // ... more basic instructions ...
1651 
1652     case kMips64Seb:
1653       __ seb(i.OutputRegister(), i.InputRegister(0));
1654       break;
1655     case kMips64Seh:
1656       __ seh(i.OutputRegister(), i.InputRegister(0));
1657       break;
1658     case kMips64Lbu:
1659       __ Lbu(i.OutputRegister(), i.MemoryOperand());
1660       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1661       break;
1662     case kMips64Lb:
1663       __ Lb(i.OutputRegister(), i.MemoryOperand());
1664       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1665       break;
1666     case kMips64Sb:
1667       __ Sb(i.InputOrZeroRegister(2), i.MemoryOperand());
1668       break;
1669     case kMips64Lhu:
1670       __ Lhu(i.OutputRegister(), i.MemoryOperand());
1671       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1672       break;
1673     case kMips64Ulhu:
1674       __ Ulhu(i.OutputRegister(), i.MemoryOperand());
1675       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1676       break;
1677     case kMips64Lh:
1678       __ Lh(i.OutputRegister(), i.MemoryOperand());
1679       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1680       break;
1681     case kMips64Ulh:
1682       __ Ulh(i.OutputRegister(), i.MemoryOperand());
1683       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1684       break;
1685     case kMips64Sh:
1686       __ Sh(i.InputOrZeroRegister(2), i.MemoryOperand());
1687       break;
1688     case kMips64Ush:
1689       __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
1690       break;
1691     case kMips64Lw:
1692       __ Lw(i.OutputRegister(), i.MemoryOperand());
1693       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1694       break;
1695     case kMips64Ulw:
1696       __ Ulw(i.OutputRegister(), i.MemoryOperand());
1697       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1698       break;
1699     case kMips64Lwu:
1700       __ Lwu(i.OutputRegister(), i.MemoryOperand());
1701       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1702       break;
1703     case kMips64Ulwu:
1704       __ Ulwu(i.OutputRegister(), i.MemoryOperand());
1705       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1706       break;
1707     case kMips64Ld:
1708       __ Ld(i.OutputRegister(), i.MemoryOperand());
1709       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1710       break;
1711     case kMips64Uld:
1712       __ Uld(i.OutputRegister(), i.MemoryOperand());
1713       EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1714       break;
1715     case kMips64Sw:
1716       __ Sw(i.InputOrZeroRegister(2), i.MemoryOperand());
1717       break;
1718     case kMips64Usw:
1719       __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
1720       break;
1721     case kMips64Sd:
1722       __ Sd(i.InputOrZeroRegister(2), i.MemoryOperand());
1723       break;
1724     case kMips64Usd:
1725       __ Usd(i.InputOrZeroRegister(2), i.MemoryOperand());
1726       break;
1727     case kMips64Lwc1: {
1728       __ Lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1729       break;
1730     }
1731     case kMips64Ulwc1: {
1732       __ Ulwc1(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg);
1733       break;
1734     }
1735     case kMips64Swc1: {
1736       size_t index = 0;
1737       MemOperand operand = i.MemoryOperand(&index);
1738       FPURegister ft = i.InputOrZeroSingleRegister(index);
1739       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1740         __ Move(kDoubleRegZero, 0.0);
1741       }
1742       __ Swc1(ft, operand);
1743       break;
1744     }
1745     case kMips64Uswc1: {
1746       size_t index = 0;
1747       MemOperand operand = i.MemoryOperand(&index);
1748       FPURegister ft = i.InputOrZeroSingleRegister(index);
1749       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1750         __ Move(kDoubleRegZero, 0.0);
1751       }
1752       __ Uswc1(ft, operand, kScratchReg);
1753       break;
1754     }
1755     case kMips64Ldc1:
1756       __ Ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1757       break;
1758     case kMips64Uldc1:
1759       __ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
1760       break;
1761     case kMips64Sdc1: {
1762       FPURegister ft = i.InputOrZeroDoubleRegister(2);
1763       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1764         __ Move(kDoubleRegZero, 0.0);
1765       }
1766       __ Sdc1(ft, i.MemoryOperand());
1767       break;
1768     }
1769     case kMips64Usdc1: {
1770       FPURegister ft = i.InputOrZeroDoubleRegister(2);
1771       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1772         __ Move(kDoubleRegZero, 0.0);
1773       }
1774       __ Usdc1(ft, i.MemoryOperand(), kScratchReg);
1775       break;
1776     }
1777     case kMips64Push:
1778       if (instr->InputAt(0)->IsFPRegister()) {
1779         __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1780         __ Subu(sp, sp, Operand(kDoubleSize));
1781         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1782       } else {
1783         __ Push(i.InputRegister(0));
1784         frame_access_state()->IncreaseSPDelta(1);
1785       }
1786       break;
1787     case kMips64Peek: {
1788       // The incoming value is 0-based, but we need a 1-based value.
1789       int reverse_slot = i.InputInt32(0) + 1;
1790       int offset =
1791           FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
1792       if (instr->OutputAt(0)->IsFPRegister()) {
1793         LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
1794         if (op->representation() == MachineRepresentation::kFloat64) {
1795           __ Ldc1(i.OutputDoubleRegister(), MemOperand(fp, offset));
1796         } else {
1797           DCHECK_EQ(op->representation(), MachineRepresentation::kFloat32);
1798           __ lwc1(
1799               i.OutputSingleRegister(0),
1800               MemOperand(fp, offset + kLessSignificantWordInDoublewordOffset));
1801         }
1802       } else {
1803         __ Ld(i.OutputRegister(0), MemOperand(fp, offset));
1804       }
1805       break;
1806     }
1807     case kMips64StackClaim: {
1808       __ Dsubu(sp, sp, Operand(i.InputInt32(0)));
1809       frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
1810       break;
1811     }
1812     case kMips64StoreToStackSlot: {
1813       if (instr->InputAt(0)->IsFPRegister()) {
1814         if (instr->InputAt(0)->IsSimd128Register()) {
1815           CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1816           __ st_b(i.InputSimd128Register(0), MemOperand(sp, i.InputInt32(1)));
1817         } else {
1818           __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1819         }
1820       } else {
1821         __ Sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1822       }
1823       break;
1824     }
1825     case kMips64ByteSwap64: {
1826       __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 8);
1827       break;
1828     }
1829     case kMips64ByteSwap32: {
1830       __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 4);
1831       break;
1832     }
1833     case kWord32AtomicLoadInt8:
1834       ASSEMBLE_ATOMIC_LOAD_INTEGER(Lb);
1835       break;
1836     case kWord32AtomicLoadUint8:
1837       ASSEMBLE_ATOMIC_LOAD_INTEGER(Lbu);
1838       break;
1839     case kWord32AtomicLoadInt16:
1840       ASSEMBLE_ATOMIC_LOAD_INTEGER(Lh);
1841       break;
1842     case kWord32AtomicLoadUint16:
1843       ASSEMBLE_ATOMIC_LOAD_INTEGER(Lhu);
1844       break;
1845     case kWord32AtomicLoadWord32:
1846       ASSEMBLE_ATOMIC_LOAD_INTEGER(Lw);
1847       break;
1848     case kWord32AtomicStoreWord8:
1849       ASSEMBLE_ATOMIC_STORE_INTEGER(Sb);
1850       break;
1851     case kWord32AtomicStoreWord16:
1852       ASSEMBLE_ATOMIC_STORE_INTEGER(Sh);
1853       break;
1854     case kWord32AtomicStoreWord32:
1855       ASSEMBLE_ATOMIC_STORE_INTEGER(Sw);
1856       break;
1857     case kWord32AtomicExchangeInt8:
1858       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 8);
1859       break;
1860     case kWord32AtomicExchangeUint8:
1861       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 8);
1862       break;
1863     case kWord32AtomicExchangeInt16:
1864       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 16);
1865       break;
1866     case kWord32AtomicExchangeUint16:
1867       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 16);
1868       break;
1869     case kWord32AtomicExchangeWord32:
1870       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER();
1871       break;
1872     case kWord32AtomicCompareExchangeInt8:
1873       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 8);
1874       break;
1875     case kWord32AtomicCompareExchangeUint8:
1876       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 8);
1877       break;
1878     case kWord32AtomicCompareExchangeInt16:
1879       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 16);
1880       break;
1881     case kWord32AtomicCompareExchangeUint16:
1882       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 16);
1883       break;
1884     case kWord32AtomicCompareExchangeWord32:
1885       __ sll(i.InputRegister(2), i.InputRegister(2), 0);
1886       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER();
1887       break;
1888 #define ATOMIC_BINOP_CASE(op, inst)             \
1889   case kWord32Atomic##op##Int8:                 \
1890     ASSEMBLE_ATOMIC_BINOP_EXT(true, 8, inst);   \
1891     break;                                      \
1892   case kWord32Atomic##op##Uint8:                \
1893     ASSEMBLE_ATOMIC_BINOP_EXT(false, 8, inst);  \
1894     break;                                      \
1895   case kWord32Atomic##op##Int16:                \
1896     ASSEMBLE_ATOMIC_BINOP_EXT(true, 16, inst);  \
1897     break;                                      \
1898   case kWord32Atomic##op##Uint16:               \
1899     ASSEMBLE_ATOMIC_BINOP_EXT(false, 16, inst); \
1900     break;                                      \
1901   case kWord32Atomic##op##Word32:               \
1902     ASSEMBLE_ATOMIC_BINOP(inst);                \
1903     break;
1904       ATOMIC_BINOP_CASE(Add, Addu)
1905       ATOMIC_BINOP_CASE(Sub, Subu)
1906       ATOMIC_BINOP_CASE(And, And)
1907       ATOMIC_BINOP_CASE(Or, Or)
1908       ATOMIC_BINOP_CASE(Xor, Xor)
1909 #undef ATOMIC_BINOP_CASE
1910     case kMips64AssertEqual:
1911       __ Assert(eq, static_cast<AbortReason>(i.InputOperand(2).immediate()),
1912                 i.InputRegister(0), Operand(i.InputRegister(1)));
1913       break;
1914     case kMips64S128Zero: {
1915       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1916       __ xor_v(i.OutputSimd128Register(), i.OutputSimd128Register(),
1917                i.OutputSimd128Register());
1918       break;
1919     }
1920     case kMips64I32x4Splat: {
1921       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1922       __ fill_w(i.OutputSimd128Register(), i.InputRegister(0));
1923       break;
1924     }
1925     case kMips64I32x4ExtractLane: {
1926       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1927       __ copy_s_w(i.OutputRegister(), i.InputSimd128Register(0),
1928                   i.InputInt8(1));
1929       break;
1930     }
1931     case kMips64I32x4ReplaceLane: {
1932       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1933       Simd128Register src = i.InputSimd128Register(0);
1934       Simd128Register dst = i.OutputSimd128Register();
1935       if (src != dst) {
1936         __ move_v(dst, src);
1937       }
1938       __ insert_w(dst, i.InputInt8(1), i.InputRegister(2));
1939       break;
1940     }
1941     case kMips64I32x4Add: {
1942       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1943       __ addv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
1944                 i.InputSimd128Register(1));
1945       break;
1946     }
1947     case kMips64I32x4Sub: {
1948       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1949       __ subv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
1950                 i.InputSimd128Register(1));
1951       break;
1952     }
1953     case kMips64F32x4Splat: {
1954       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1955       __ FmoveLow(kScratchReg, i.InputSingleRegister(0));
1956       __ fill_w(i.OutputSimd128Register(), kScratchReg);
1957       break;
1958     }
1959     case kMips64F32x4ExtractLane: {
1960       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1961       __ copy_u_w(kScratchReg, i.InputSimd128Register(0), i.InputInt8(1));
1962       __ FmoveLow(i.OutputSingleRegister(), kScratchReg);
1963       break;
1964     }
1965     case kMips64F32x4ReplaceLane: {
1966       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1967       Simd128Register src = i.InputSimd128Register(0);
1968       Simd128Register dst = i.OutputSimd128Register();
1969       if (src != dst) {
1970         __ move_v(dst, src);
1971       }
1972       __ FmoveLow(kScratchReg, i.InputSingleRegister(2));
1973       __ insert_w(dst, i.InputInt8(1), kScratchReg);
1974       break;
1975     }
1976     case kMips64F32x4SConvertI32x4: {
1977       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1978       __ ffint_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
1979       break;
1980     }
1981     case kMips64F32x4UConvertI32x4: {
1982       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1983       __ ffint_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
1984       break;
1985     }
1986     case kMips64I32x4Mul: {
1987       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1988       __ mulv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
1989                 i.InputSimd128Register(1));
1990       break;
1991     }
1992     case kMips64I32x4MaxS: {
1993       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1994       __ max_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
1995                  i.InputSimd128Register(1));
1996       break;
1997     }
1998     case kMips64I32x4MinS: {
1999       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2000       __ min_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2001                  i.InputSimd128Register(1));
2002       break;
2003     }
2004     case kMips64I32x4Eq: {
2005       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2006       __ ceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2007                i.InputSimd128Register(1));
2008       break;
2009     }
2010     case kMips64I32x4Ne: {
2011       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2012       Simd128Register dst = i.OutputSimd128Register();
2013       __ ceq_w(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
2014       __ nor_v(dst, dst, dst);
2015       break;
2016     }
2017     case kMips64I32x4Shl: {
2018       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2019       __ slli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2020                 i.InputInt5(1));
2021       break;
2022     }
2023     case kMips64I32x4ShrS: {
2024       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2025       __ srai_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2026                 i.InputInt5(1));
2027       break;
2028     }
2029     case kMips64I32x4ShrU: {
2030       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2031       __ srli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2032                 i.InputInt5(1));
2033       break;
2034     }
2035     case kMips64I32x4MaxU: {
2036       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2037       __ max_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2038                  i.InputSimd128Register(1));
2039       break;
2040     }
2041     case kMips64I32x4MinU: {
2042       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2043       __ min_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2044                  i.InputSimd128Register(1));
2045       break;
2046     }
2047     case kMips64S128Select: {
2048       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2049       DCHECK(i.OutputSimd128Register() == i.InputSimd128Register(0));
2050       __ bsel_v(i.OutputSimd128Register(), i.InputSimd128Register(2),
2051                 i.InputSimd128Register(1));
2052       break;
2053     }
2054     case kMips64F32x4Abs: {
2055       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2056       __ bclri_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
2057       break;
2058     }
2059     case kMips64F32x4Neg: {
2060       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2061       __ bnegi_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
2062       break;
2063     }
2064     case kMips64F32x4RecipApprox: {
2065       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2066       __ frcp_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2067       break;
2068     }
2069     case kMips64F32x4RecipSqrtApprox: {
2070       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2071       __ frsqrt_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2072       break;
2073     }
2074     case kMips64F32x4Add: {
2075       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2076       __ fadd_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2077                 i.InputSimd128Register(1));
2078       break;
2079     }
2080     case kMips64F32x4Sub: {
2081       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2082       __ fsub_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2083                 i.InputSimd128Register(1));
2084       break;
2085     }
2086     case kMips64F32x4Mul: {
2087       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2088       __ fmul_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2089                 i.InputSimd128Register(1));
2090       break;
2091     }
2092     case kMips64F32x4Max: {
2093       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2094       __ fmax_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2095                 i.InputSimd128Register(1));
2096       break;
2097     }
2098     case kMips64F32x4Min: {
2099       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2100       __ fmin_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2101                 i.InputSimd128Register(1));
2102       break;
2103     }
2104     case kMips64F32x4Eq: {
2105       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2106       __ fceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2107                 i.InputSimd128Register(1));
2108       break;
2109     }
2110     case kMips64F32x4Ne: {
2111       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2112       __ fcne_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2113                 i.InputSimd128Register(1));
2114       break;
2115     }
2116     case kMips64F32x4Lt: {
2117       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2118       __ fclt_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2119                 i.InputSimd128Register(1));
2120       break;
2121     }
2122     case kMips64F32x4Le: {
2123       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2124       __ fcle_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2125                 i.InputSimd128Register(1));
2126       break;
2127     }
2128     case kMips64I32x4SConvertF32x4: {
2129       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2130       __ ftrunc_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2131       break;
2132     }
2133     case kMips64I32x4UConvertF32x4: {
2134       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2135       __ ftrunc_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2136       break;
2137     }
2138     case kMips64I32x4Neg: {
2139       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2140       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2141       __ subv_w(i.OutputSimd128Register(), kSimd128RegZero,
2142                 i.InputSimd128Register(0));
2143       break;
2144     }
2145     case kMips64I32x4GtS: {
2146       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2147       __ clt_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2148                  i.InputSimd128Register(0));
2149       break;
2150     }
2151     case kMips64I32x4GeS: {
2152       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2153       __ cle_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2154                  i.InputSimd128Register(0));
2155       break;
2156     }
2157     case kMips64I32x4GtU: {
2158       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2159       __ clt_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2160                  i.InputSimd128Register(0));
2161       break;
2162     }
2163     case kMips64I32x4GeU: {
2164       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2165       __ cle_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2166                  i.InputSimd128Register(0));
2167       break;
2168     }
2169     case kMips64I16x8Splat: {
2170       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2171       __ fill_h(i.OutputSimd128Register(), i.InputRegister(0));
2172       break;
2173     }
2174     case kMips64I16x8ExtractLane: {
2175       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2176       __ copy_s_h(i.OutputRegister(), i.InputSimd128Register(0),
2177                   i.InputInt8(1));
2178       break;
2179     }
2180     case kMips64I16x8ReplaceLane: {
2181       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2182       Simd128Register src = i.InputSimd128Register(0);
2183       Simd128Register dst = i.OutputSimd128Register();
2184       if (src != dst) {
2185         __ move_v(dst, src);
2186       }
2187       __ insert_h(dst, i.InputInt8(1), i.InputRegister(2));
2188       break;
2189     }
2190     case kMips64I16x8Neg: {
2191       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2192       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2193       __ subv_h(i.OutputSimd128Register(), kSimd128RegZero,
2194                 i.InputSimd128Register(0));
2195       break;
2196     }
2197     case kMips64I16x8Shl: {
2198       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2199       __ slli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2200                 i.InputInt4(1));
2201       break;
2202     }
2203     case kMips64I16x8ShrS: {
2204       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2205       __ srai_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2206                 i.InputInt4(1));
2207       break;
2208     }
2209     case kMips64I16x8ShrU: {
2210       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2211       __ srli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2212                 i.InputInt4(1));
2213       break;
2214     }
2215     case kMips64I16x8Add: {
2216       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2217       __ addv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2218                 i.InputSimd128Register(1));
2219       break;
2220     }
2221     case kMips64I16x8AddSaturateS: {
2222       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2223       __ adds_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2224                   i.InputSimd128Register(1));
2225       break;
2226     }
2227     case kMips64I16x8Sub: {
2228       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2229       __ subv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2230                 i.InputSimd128Register(1));
2231       break;
2232     }
2233     case kMips64I16x8SubSaturateS: {
2234       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2235       __ subs_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2236                   i.InputSimd128Register(1));
2237       break;
2238     }
2239     case kMips64I16x8Mul: {
2240       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2241       __ mulv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2242                 i.InputSimd128Register(1));
2243       break;
2244     }
2245     case kMips64I16x8MaxS: {
2246       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2247       __ max_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2248                  i.InputSimd128Register(1));
2249       break;
2250     }
2251     case kMips64I16x8MinS: {
2252       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2253       __ min_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2254                  i.InputSimd128Register(1));
2255       break;
2256     }
2257     case kMips64I16x8Eq: {
2258       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2259       __ ceq_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2260                i.InputSimd128Register(1));
2261       break;
2262     }
2263     case kMips64I16x8Ne: {
2264       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2265       Simd128Register dst = i.OutputSimd128Register();
2266       __ ceq_h(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
2267       __ nor_v(dst, dst, dst);
2268       break;
2269     }
2270     case kMips64I16x8GtS: {
2271       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2272       __ clt_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2273                  i.InputSimd128Register(0));
2274       break;
2275     }
2276     case kMips64I16x8GeS: {
2277       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2278       __ cle_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2279                  i.InputSimd128Register(0));
2280       break;
2281     }
2282     case kMips64I16x8AddSaturateU: {
2283       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2284       __ adds_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2285                   i.InputSimd128Register(1));
2286       break;
2287     }
2288     case kMips64I16x8SubSaturateU: {
2289       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2290       __ subs_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2291                   i.InputSimd128Register(1));
2292       break;
2293     }
2294     case kMips64I16x8MaxU: {
2295       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2296       __ max_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2297                  i.InputSimd128Register(1));
2298       break;
2299     }
2300     case kMips64I16x8MinU: {
2301       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2302       __ min_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2303                  i.InputSimd128Register(1));
2304       break;
2305     }
2306     case kMips64I16x8GtU: {
2307       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2308       __ clt_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2309                  i.InputSimd128Register(0));
2310       break;
2311     }
2312     case kMips64I16x8GeU: {
2313       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2314       __ cle_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2315                  i.InputSimd128Register(0));
2316       break;
2317     }
2318     case kMips64I8x16Splat: {
2319       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2320       __ fill_b(i.OutputSimd128Register(), i.InputRegister(0));
2321       break;
2322     }
2323     case kMips64I8x16ExtractLane: {
2324       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2325       __ copy_s_b(i.OutputRegister(), i.InputSimd128Register(0),
2326                   i.InputInt8(1));
2327       break;
2328     }
2329     case kMips64I8x16ReplaceLane: {
2330       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2331       Simd128Register src = i.InputSimd128Register(0);
2332       Simd128Register dst = i.OutputSimd128Register();
2333       if (src != dst) {
2334         __ move_v(dst, src);
2335       }
2336       __ insert_b(dst, i.InputInt8(1), i.InputRegister(2));
2337       break;
2338     }
2339     case kMips64I8x16Neg: {
2340       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2341       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2342       __ subv_b(i.OutputSimd128Register(), kSimd128RegZero,
2343                 i.InputSimd128Register(0));
2344       break;
2345     }
2346     case kMips64I8x16Shl: {
2347       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2348       __ slli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2349                 i.InputInt3(1));
2350       break;
2351     }
2352     case kMips64I8x16ShrS: {
2353       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2354       __ srai_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2355                 i.InputInt3(1));
2356       break;
2357     }
2358     case kMips64I8x16Add: {
2359       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2360       __ addv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2361                 i.InputSimd128Register(1));
2362       break;
2363     }
2364     case kMips64I8x16AddSaturateS: {
2365       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2366       __ adds_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2367                   i.InputSimd128Register(1));
2368       break;
2369     }
2370     case kMips64I8x16Sub: {
2371       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2372       __ subv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2373                 i.InputSimd128Register(1));
2374       break;
2375     }
2376     case kMips64I8x16SubSaturateS: {
2377       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2378       __ subs_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2379                   i.InputSimd128Register(1));
2380       break;
2381     }
2382     case kMips64I8x16Mul: {
2383       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2384       __ mulv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2385                 i.InputSimd128Register(1));
2386       break;
2387     }
2388     case kMips64I8x16MaxS: {
2389       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2390       __ max_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2391                  i.InputSimd128Register(1));
2392       break;
2393     }
2394     case kMips64I8x16MinS: {
2395       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2396       __ min_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2397                  i.InputSimd128Register(1));
2398       break;
2399     }
2400     case kMips64I8x16Eq: {
2401       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2402       __ ceq_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2403                i.InputSimd128Register(1));
2404       break;
2405     }
2406     case kMips64I8x16Ne: {
2407       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2408       Simd128Register dst = i.OutputSimd128Register();
2409       __ ceq_b(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
2410       __ nor_v(dst, dst, dst);
2411       break;
2412     }
2413     case kMips64I8x16GtS: {
2414       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2415       __ clt_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
2416                  i.InputSimd128Register(0));
2417       break;
2418     }
2419     case kMips64I8x16GeS: {
2420       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2421       __ cle_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
2422                  i.InputSimd128Register(0));
2423       break;
2424     }
2425     case kMips64I8x16ShrU: {
2426       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2427       __ srli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2428                 i.InputInt3(1));
2429       break;
2430     }
2431     case kMips64I8x16AddSaturateU: {
2432       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2433       __ adds_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2434                   i.InputSimd128Register(1));
2435       break;
2436     }
2437     case kMips64I8x16SubSaturateU: {
2438       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2439       __ subs_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2440                   i.InputSimd128Register(1));
2441       break;
2442     }
2443     case kMips64I8x16MaxU: {
2444       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2445       __ max_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2446                  i.InputSimd128Register(1));
2447       break;
2448     }
2449     case kMips64I8x16MinU: {
2450       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2451       __ min_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2452                  i.InputSimd128Register(1));
2453       break;
2454     }
2455     case kMips64I8x16GtU: {
2456       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2457       __ clt_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
2458                  i.InputSimd128Register(0));
2459       break;
2460     }
2461     case kMips64I8x16GeU: {
2462       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2463       __ cle_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
2464                  i.InputSimd128Register(0));
2465       break;
2466     }
2467     case kMips64S128And: {
2468       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2469       __ and_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
2470                i.InputSimd128Register(1));
2471       break;
2472     }
2473     case kMips64S128Or: {
2474       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2475       __ or_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
2476               i.InputSimd128Register(1));
2477       break;
2478     }
2479     case kMips64S128Xor: {
2480       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2481       __ xor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
2482                i.InputSimd128Register(1));
2483       break;
2484     }
2485     case kMips64S128Not: {
2486       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2487       __ nor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
2488                i.InputSimd128Register(0));
2489       break;
2490     }
2491     case kMips64S1x4AnyTrue:
2492     case kMips64S1x8AnyTrue:
2493     case kMips64S1x16AnyTrue: {
2494       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2495       Register dst = i.OutputRegister();
2496       Label all_false;
2497       __ BranchMSA(&all_false, MSA_BRANCH_V, all_zero,
2498                    i.InputSimd128Register(0), USE_DELAY_SLOT);
2499       __ li(dst, 0);  // branch delay slot
2500       __ li(dst, -1);
2501       __ bind(&all_false);
2502       break;
2503     }
2504     case kMips64S1x4AllTrue: {
2505       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2506       Register dst = i.OutputRegister();
2507       Label all_true;
2508       __ BranchMSA(&all_true, MSA_BRANCH_W, all_not_zero,
2509                    i.InputSimd128Register(0), USE_DELAY_SLOT);
2510       __ li(dst, -1);  // branch delay slot
2511       __ li(dst, 0);
2512       __ bind(&all_true);
2513       break;
2514     }
2515     case kMips64S1x8AllTrue: {
2516       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2517       Register dst = i.OutputRegister();
2518       Label all_true;
2519       __ BranchMSA(&all_true, MSA_BRANCH_H, all_not_zero,
2520                    i.InputSimd128Register(0), USE_DELAY_SLOT);
2521       __ li(dst, -1);  // branch delay slot
2522       __ li(dst, 0);
2523       __ bind(&all_true);
2524       break;
2525     }
2526     case kMips64S1x16AllTrue: {
2527       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2528       Register dst = i.OutputRegister();
2529       Label all_true;
2530       __ BranchMSA(&all_true, MSA_BRANCH_B, all_not_zero,
2531                    i.InputSimd128Register(0), USE_DELAY_SLOT);
2532       __ li(dst, -1);  // branch delay slot
2533       __ li(dst, 0);
2534       __ bind(&all_true);
2535       break;
2536     }
2537     case kMips64MsaLd: {
2538       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2539       __ ld_b(i.OutputSimd128Register(), i.MemoryOperand());
2540       break;
2541     }
2542     case kMips64MsaSt: {
2543       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2544       __ st_b(i.InputSimd128Register(2), i.MemoryOperand());
2545       break;
2546     }
2547     case kMips64S32x4InterleaveRight: {
2548       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2549       Simd128Register dst = i.OutputSimd128Register(),
2550                       src0 = i.InputSimd128Register(0),
2551                       src1 = i.InputSimd128Register(1);
2552       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2553       // dst = [5, 1, 4, 0]
2554       __ ilvr_w(dst, src1, src0);
2555       break;
2556     }
2557     case kMips64S32x4InterleaveLeft: {
2558       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2559       Simd128Register dst = i.OutputSimd128Register(),
2560                       src0 = i.InputSimd128Register(0),
2561                       src1 = i.InputSimd128Register(1);
2562       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2563       // dst = [7, 3, 6, 2]
2564       __ ilvl_w(dst, src1, src0);
2565       break;
2566     }
2567     case kMips64S32x4PackEven: {
2568       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2569       Simd128Register dst = i.OutputSimd128Register(),
2570                       src0 = i.InputSimd128Register(0),
2571                       src1 = i.InputSimd128Register(1);
2572       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2573       // dst = [6, 4, 2, 0]
2574       __ pckev_w(dst, src1, src0);
2575       break;
2576     }
2577     case kMips64S32x4PackOdd: {
2578       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2579       Simd128Register dst = i.OutputSimd128Register(),
2580                       src0 = i.InputSimd128Register(0),
2581                       src1 = i.InputSimd128Register(1);
2582       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2583       // dst = [7, 5, 3, 1]
2584       __ pckod_w(dst, src1, src0);
2585       break;
2586     }
2587     case kMips64S32x4InterleaveEven: {
2588       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2589       Simd128Register dst = i.OutputSimd128Register(),
2590                       src0 = i.InputSimd128Register(0),
2591                       src1 = i.InputSimd128Register(1);
2592       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2593       // dst = [6, 2, 4, 0]
2594       __ ilvev_w(dst, src1, src0);
2595       break;
2596     }
2597     case kMips64S32x4InterleaveOdd: {
2598       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2599       Simd128Register dst = i.OutputSimd128Register(),
2600                       src0 = i.InputSimd128Register(0),
2601                       src1 = i.InputSimd128Register(1);
2602       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
2603       // dst = [7, 3, 5, 1]
2604       __ ilvod_w(dst, src1, src0);
2605       break;
2606     }
2607     case kMips64S32x4Shuffle: {
2608       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2609       Simd128Register dst = i.OutputSimd128Register(),
2610                       src0 = i.InputSimd128Register(0),
2611                       src1 = i.InputSimd128Register(1);
2612 
2613       int32_t shuffle = i.InputInt32(2);
2614 
2615       if (src0 == src1) {
2616         // Unary S32x4 shuffles are handled with shf.w instruction
2617         unsigned lane = shuffle & 0xFF;
2618         if (FLAG_debug_code) {
2619           // range of all four lanes, for unary instruction,
2620           // should belong to the same range, which can be one of these:
2621           // [0, 3] or [4, 7]
2622           if (lane >= 4) {
2623             int32_t shuffle_helper = shuffle;
2624             for (int i = 0; i < 4; ++i) {
2625               lane = shuffle_helper & 0xFF;
2626               CHECK_GE(lane, 4);
2627               shuffle_helper >>= 8;
2628             }
2629           }
2630         }
2631         uint32_t i8 = 0;
2632         for (int i = 0; i < 4; i++) {
2633           lane = shuffle & 0xFF;
2634           if (lane >= 4) {
2635             lane -= 4;
2636           }
2637           DCHECK_GT(4, lane);
2638           i8 |= lane << (2 * i);
2639           shuffle >>= 8;
2640         }
2641         __ shf_w(dst, src0, i8);
2642       } else {
2643         // For binary shuffles use vshf.w instruction
2644         if (dst == src0) {
2645           __ move_v(kSimd128ScratchReg, src0);
2646           src0 = kSimd128ScratchReg;
2647         } else if (dst == src1) {
2648           __ move_v(kSimd128ScratchReg, src1);
2649           src1 = kSimd128ScratchReg;
2650         }
2651 
2652         __ li(kScratchReg, i.InputInt32(2));
2653         __ insert_w(dst, 0, kScratchReg);
2654         __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2655         __ ilvr_b(dst, kSimd128RegZero, dst);
2656         __ ilvr_h(dst, kSimd128RegZero, dst);
2657         __ vshf_w(dst, src1, src0);
2658       }
2659       break;
2660     }
2661     case kMips64S16x8InterleaveRight: {
2662       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2663       Simd128Register dst = i.OutputSimd128Register(),
2664                       src0 = i.InputSimd128Register(0),
2665                       src1 = i.InputSimd128Register(1);
2666       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2667       // dst = [11, 3, 10, 2, 9, 1, 8, 0]
2668       __ ilvr_h(dst, src1, src0);
2669       break;
2670     }
2671     case kMips64S16x8InterleaveLeft: {
2672       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2673       Simd128Register dst = i.OutputSimd128Register(),
2674                       src0 = i.InputSimd128Register(0),
2675                       src1 = i.InputSimd128Register(1);
2676       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2677       // dst = [15, 7, 14, 6, 13, 5, 12, 4]
2678       __ ilvl_h(dst, src1, src0);
2679       break;
2680     }
2681     case kMips64S16x8PackEven: {
2682       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2683       Simd128Register dst = i.OutputSimd128Register(),
2684                       src0 = i.InputSimd128Register(0),
2685                       src1 = i.InputSimd128Register(1);
2686       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2687       // dst = [14, 12, 10, 8, 6, 4, 2, 0]
2688       __ pckev_h(dst, src1, src0);
2689       break;
2690     }
2691     case kMips64S16x8PackOdd: {
2692       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2693       Simd128Register dst = i.OutputSimd128Register(),
2694                       src0 = i.InputSimd128Register(0),
2695                       src1 = i.InputSimd128Register(1);
2696       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2697       // dst = [15, 13, 11, 9, 7, 5, 3, 1]
2698       __ pckod_h(dst, src1, src0);
2699       break;
2700     }
2701     case kMips64S16x8InterleaveEven: {
2702       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2703       Simd128Register dst = i.OutputSimd128Register(),
2704                       src0 = i.InputSimd128Register(0),
2705                       src1 = i.InputSimd128Register(1);
2706       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2707       // dst = [14, 6, 12, 4, 10, 2, 8, 0]
2708       __ ilvev_h(dst, src1, src0);
2709       break;
2710     }
2711     case kMips64S16x8InterleaveOdd: {
2712       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2713       Simd128Register dst = i.OutputSimd128Register(),
2714                       src0 = i.InputSimd128Register(0),
2715                       src1 = i.InputSimd128Register(1);
2716       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
2717       // dst = [15, 7, ... 11, 3, 9, 1]
2718       __ ilvod_h(dst, src1, src0);
2719       break;
2720     }
2721     case kMips64S16x4Reverse: {
2722       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2723       // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [4, 5, 6, 7, 0, 1, 2, 3]
2724       // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
2725       __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
2726       break;
2727     }
2728     case kMips64S16x2Reverse: {
2729       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2730       // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [6, 7, 4, 5, 3, 2, 0, 1]
2731       // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
2732       __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
2733       break;
2734     }
2735     case kMips64S8x16InterleaveRight: {
2736       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2737       Simd128Register dst = i.OutputSimd128Register(),
2738                       src0 = i.InputSimd128Register(0),
2739                       src1 = i.InputSimd128Register(1);
2740       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2741       // dst = [23, 7, ... 17, 1, 16, 0]
2742       __ ilvr_b(dst, src1, src0);
2743       break;
2744     }
2745     case kMips64S8x16InterleaveLeft: {
2746       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2747       Simd128Register dst = i.OutputSimd128Register(),
2748                       src0 = i.InputSimd128Register(0),
2749                       src1 = i.InputSimd128Register(1);
2750       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2751       // dst = [31, 15, ... 25, 9, 24, 8]
2752       __ ilvl_b(dst, src1, src0);
2753       break;
2754     }
2755     case kMips64S8x16PackEven: {
2756       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2757       Simd128Register dst = i.OutputSimd128Register(),
2758                       src0 = i.InputSimd128Register(0),
2759                       src1 = i.InputSimd128Register(1);
2760       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2761       // dst = [30, 28, ... 6, 4, 2, 0]
2762       __ pckev_b(dst, src1, src0);
2763       break;
2764     }
2765     case kMips64S8x16PackOdd: {
2766       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2767       Simd128Register dst = i.OutputSimd128Register(),
2768                       src0 = i.InputSimd128Register(0),
2769                       src1 = i.InputSimd128Register(1);
2770       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2771       // dst = [31, 29, ... 7, 5, 3, 1]
2772       __ pckod_b(dst, src1, src0);
2773       break;
2774     }
2775     case kMips64S8x16InterleaveEven: {
2776       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2777       Simd128Register dst = i.OutputSimd128Register(),
2778                       src0 = i.InputSimd128Register(0),
2779                       src1 = i.InputSimd128Register(1);
2780       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2781       // dst = [30, 14, ... 18, 2, 16, 0]
2782       __ ilvev_b(dst, src1, src0);
2783       break;
2784     }
2785     case kMips64S8x16InterleaveOdd: {
2786       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2787       Simd128Register dst = i.OutputSimd128Register(),
2788                       src0 = i.InputSimd128Register(0),
2789                       src1 = i.InputSimd128Register(1);
2790       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
2791       // dst = [31, 15, ... 19, 3, 17, 1]
2792       __ ilvod_b(dst, src1, src0);
2793       break;
2794     }
2795     case kMips64S8x16Concat: {
2796       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2797       Simd128Register dst = i.OutputSimd128Register();
2798       DCHECK(dst == i.InputSimd128Register(0));
2799       __ sldi_b(dst, i.InputSimd128Register(1), i.InputInt4(2));
2800       break;
2801     }
2802     case kMips64S8x16Shuffle: {
2803       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2804       Simd128Register dst = i.OutputSimd128Register(),
2805                       src0 = i.InputSimd128Register(0),
2806                       src1 = i.InputSimd128Register(1);
2807 
2808       if (dst == src0) {
2809         __ move_v(kSimd128ScratchReg, src0);
2810         src0 = kSimd128ScratchReg;
2811       } else if (dst == src1) {
2812         __ move_v(kSimd128ScratchReg, src1);
2813         src1 = kSimd128ScratchReg;
2814       }
2815 
2816       int64_t control_low =
2817           static_cast<int64_t>(i.InputInt32(3)) << 32 | i.InputInt32(2);
2818       int64_t control_hi =
2819           static_cast<int64_t>(i.InputInt32(5)) << 32 | i.InputInt32(4);
2820       __ li(kScratchReg, control_low);
2821       __ insert_d(dst, 0, kScratchReg);
2822       __ li(kScratchReg, control_hi);
2823       __ insert_d(dst, 1, kScratchReg);
2824       __ vshf_b(dst, src1, src0);
2825       break;
2826     }
2827     case kMips64S8x8Reverse: {
2828       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2829       // src = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
2830       // dst = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]
2831       // [A B C D] => [B A D C]: shf.w imm: 2 3 0 1 = 10110001 = 0xB1
2832       // C: [7, 6, 5, 4] => A': [4, 5, 6, 7]: shf.b imm: 00011011 = 0x1B
2833       __ shf_w(kSimd128ScratchReg, i.InputSimd128Register(0), 0xB1);
2834       __ shf_b(i.OutputSimd128Register(), kSimd128ScratchReg, 0x1B);
2835       break;
2836     }
2837     case kMips64S8x4Reverse: {
2838       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2839       // src = [15, 14, ... 3, 2, 1, 0], dst = [12, 13, 14, 15, ... 0, 1, 2, 3]
2840       // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
2841       __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
2842       break;
2843     }
2844     case kMips64S8x2Reverse: {
2845       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2846       // src = [15, 14, ... 3, 2, 1, 0], dst = [14, 15, 12, 13, ... 2, 3, 0, 1]
2847       // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
2848       __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
2849       break;
2850     }
2851     case kMips64I32x4SConvertI16x8Low: {
2852       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2853       Simd128Register dst = i.OutputSimd128Register();
2854       Simd128Register src = i.InputSimd128Register(0);
2855       __ ilvr_h(kSimd128ScratchReg, src, src);
2856       __ slli_w(dst, kSimd128ScratchReg, 16);
2857       __ srai_w(dst, dst, 16);
2858       break;
2859     }
2860     case kMips64I32x4SConvertI16x8High: {
2861       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2862       Simd128Register dst = i.OutputSimd128Register();
2863       Simd128Register src = i.InputSimd128Register(0);
2864       __ ilvl_h(kSimd128ScratchReg, src, src);
2865       __ slli_w(dst, kSimd128ScratchReg, 16);
2866       __ srai_w(dst, dst, 16);
2867       break;
2868     }
2869     case kMips64I32x4UConvertI16x8Low: {
2870       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2871       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2872       __ ilvr_h(i.OutputSimd128Register(), kSimd128RegZero,
2873                 i.InputSimd128Register(0));
2874       break;
2875     }
2876     case kMips64I32x4UConvertI16x8High: {
2877       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2878       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2879       __ ilvl_h(i.OutputSimd128Register(), kSimd128RegZero,
2880                 i.InputSimd128Register(0));
2881       break;
2882     }
2883     case kMips64I16x8SConvertI8x16Low: {
2884       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2885       Simd128Register dst = i.OutputSimd128Register();
2886       Simd128Register src = i.InputSimd128Register(0);
2887       __ ilvr_b(kSimd128ScratchReg, src, src);
2888       __ slli_h(dst, kSimd128ScratchReg, 8);
2889       __ srai_h(dst, dst, 8);
2890       break;
2891     }
2892     case kMips64I16x8SConvertI8x16High: {
2893       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2894       Simd128Register dst = i.OutputSimd128Register();
2895       Simd128Register src = i.InputSimd128Register(0);
2896       __ ilvl_b(kSimd128ScratchReg, src, src);
2897       __ slli_h(dst, kSimd128ScratchReg, 8);
2898       __ srai_h(dst, dst, 8);
2899       break;
2900     }
2901     case kMips64I16x8SConvertI32x4: {
2902       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2903       Simd128Register dst = i.OutputSimd128Register();
2904       Simd128Register src0 = i.InputSimd128Register(0);
2905       Simd128Register src1 = i.InputSimd128Register(1);
2906       __ sat_s_w(kSimd128ScratchReg, src0, 15);
2907       __ sat_s_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
2908       __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
2909       break;
2910     }
2911     case kMips64I16x8UConvertI32x4: {
2912       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2913       Simd128Register dst = i.OutputSimd128Register();
2914       Simd128Register src0 = i.InputSimd128Register(0);
2915       Simd128Register src1 = i.InputSimd128Register(1);
2916       __ sat_u_w(kSimd128ScratchReg, src0, 15);
2917       __ sat_u_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
2918       __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
2919       break;
2920     }
2921     case kMips64I16x8UConvertI8x16Low: {
2922       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2923       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2924       __ ilvr_b(i.OutputSimd128Register(), kSimd128RegZero,
2925                 i.InputSimd128Register(0));
2926       break;
2927     }
2928     case kMips64I16x8UConvertI8x16High: {
2929       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2930       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2931       __ ilvl_b(i.OutputSimd128Register(), kSimd128RegZero,
2932                 i.InputSimd128Register(0));
2933       break;
2934     }
2935     case kMips64I8x16SConvertI16x8: {
2936       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2937       Simd128Register dst = i.OutputSimd128Register();
2938       Simd128Register src0 = i.InputSimd128Register(0);
2939       Simd128Register src1 = i.InputSimd128Register(1);
2940       __ sat_s_h(kSimd128ScratchReg, src0, 7);
2941       __ sat_s_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
2942       __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
2943       break;
2944     }
2945     case kMips64I8x16UConvertI16x8: {
2946       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2947       Simd128Register dst = i.OutputSimd128Register();
2948       Simd128Register src0 = i.InputSimd128Register(0);
2949       Simd128Register src1 = i.InputSimd128Register(1);
2950       __ sat_u_h(kSimd128ScratchReg, src0, 7);
2951       __ sat_u_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
2952       __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
2953       break;
2954     }
2955     case kMips64F32x4AddHoriz: {
2956       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2957       Simd128Register src0 = i.InputSimd128Register(0);
2958       Simd128Register src1 = i.InputSimd128Register(1);
2959       Simd128Register dst = i.OutputSimd128Register();
2960       __ shf_w(kSimd128ScratchReg, src0, 0xB1);  // 2 3 0 1 : 10110001 : 0xB1
2961       __ shf_w(kSimd128RegZero, src1, 0xB1);     // kSimd128RegZero as scratch
2962       __ fadd_w(kSimd128ScratchReg, kSimd128ScratchReg, src0);
2963       __ fadd_w(kSimd128RegZero, kSimd128RegZero, src1);
2964       __ pckev_w(dst, kSimd128RegZero, kSimd128ScratchReg);
2965       break;
2966     }
2967     case kMips64I32x4AddHoriz: {
2968       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2969       Simd128Register src0 = i.InputSimd128Register(0);
2970       Simd128Register src1 = i.InputSimd128Register(1);
2971       Simd128Register dst = i.OutputSimd128Register();
2972       __ hadd_s_d(kSimd128ScratchReg, src0, src0);
2973       __ hadd_s_d(kSimd128RegZero, src1, src1);  // kSimd128RegZero as scratch
2974       __ pckev_w(dst, kSimd128RegZero, kSimd128ScratchReg);
2975       break;
2976     }
2977     case kMips64I16x8AddHoriz: {
2978       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2979       Simd128Register src0 = i.InputSimd128Register(0);
2980       Simd128Register src1 = i.InputSimd128Register(1);
2981       Simd128Register dst = i.OutputSimd128Register();
2982       __ hadd_s_w(kSimd128ScratchReg, src0, src0);
2983       __ hadd_s_w(kSimd128RegZero, src1, src1);  // kSimd128RegZero as scratch
2984       __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
2985       break;
2986     }
2987   }
2988   return kSuccess;
2989 }  // NOLINT(readability/fn_size)
2990 
2991 #define UNSUPPORTED_COND(opcode, condition)                                    \
2992   StdoutStream{} << "Unsupported " << #opcode << " condition: \"" << condition \
2993                  << "\"";                                                      \
2994   UNIMPLEMENTED();
2995 
AssembleBranchToLabels(CodeGenerator * gen,TurboAssembler * tasm,Instruction * instr,FlagsCondition condition,Label * tlabel,Label * flabel,bool fallthru)2996 void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
2997                             Instruction* instr, FlagsCondition condition,
2998                             Label* tlabel, Label* flabel, bool fallthru) {
2999 #undef __
3000 #define __ tasm->
3001   MipsOperandConverter i(gen, instr);
3002 
3003   Condition cc = kNoCondition;
3004   // MIPS does not have condition code flags, so compare and branch are
3005   // implemented differently than on the other arch's. The compare operations
3006   // emit mips pseudo-instructions, which are handled here by branch
3007   // instructions that do the actual comparison. Essential that the input
3008   // registers to compare pseudo-op are not modified before this branch op, as
3009   // they are tested here.
3010 
3011   if (instr->arch_opcode() == kMips64Tst) {
3012     cc = FlagsConditionToConditionTst(condition);
3013     __ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
3014   } else if (instr->arch_opcode() == kMips64Dadd ||
3015              instr->arch_opcode() == kMips64Dsub) {
3016     cc = FlagsConditionToConditionOvf(condition);
3017     __ dsra32(kScratchReg, i.OutputRegister(), 0);
3018     __ sra(kScratchReg2, i.OutputRegister(), 31);
3019     __ Branch(tlabel, cc, kScratchReg2, Operand(kScratchReg));
3020   } else if (instr->arch_opcode() == kMips64DaddOvf ||
3021              instr->arch_opcode() == kMips64DsubOvf) {
3022     switch (condition) {
3023       // Overflow occurs if overflow register is negative
3024       case kOverflow:
3025         __ Branch(tlabel, lt, kScratchReg, Operand(zero_reg));
3026         break;
3027       case kNotOverflow:
3028         __ Branch(tlabel, ge, kScratchReg, Operand(zero_reg));
3029         break;
3030       default:
3031         UNSUPPORTED_COND(instr->arch_opcode(), condition);
3032         break;
3033     }
3034   } else if (instr->arch_opcode() == kMips64MulOvf) {
3035     // Overflow occurs if overflow register is not zero
3036     switch (condition) {
3037       case kOverflow:
3038         __ Branch(tlabel, ne, kScratchReg, Operand(zero_reg));
3039         break;
3040       case kNotOverflow:
3041         __ Branch(tlabel, eq, kScratchReg, Operand(zero_reg));
3042         break;
3043       default:
3044         UNSUPPORTED_COND(kMipsMulOvf, condition);
3045         break;
3046     }
3047   } else if (instr->arch_opcode() == kMips64Cmp) {
3048     cc = FlagsConditionToConditionCmp(condition);
3049     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
3050   } else if (instr->arch_opcode() == kMips64CmpS ||
3051              instr->arch_opcode() == kMips64CmpD) {
3052     bool predicate;
3053     FlagsConditionToConditionCmpFPU(predicate, condition);
3054     if (predicate) {
3055       __ BranchTrueF(tlabel);
3056     } else {
3057       __ BranchFalseF(tlabel);
3058     }
3059   } else {
3060     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
3061            instr->arch_opcode());
3062     UNIMPLEMENTED();
3063   }
3064   if (!fallthru) __ Branch(flabel);  // no fallthru to flabel.
3065 #undef __
3066 #define __ tasm()->
3067 }
3068 
3069 // Assembles branches after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)3070 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
3071   Label* tlabel = branch->true_label;
3072   Label* flabel = branch->false_label;
3073 
3074   AssembleBranchToLabels(this, tasm(), instr, branch->condition, tlabel, flabel,
3075                          branch->fallthru);
3076 }
3077 
AssembleBranchPoisoning(FlagsCondition condition,Instruction * instr)3078 void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition,
3079                                             Instruction* instr) {
3080   // TODO(jarin) Handle float comparisons (kUnordered[Not]Equal).
3081   if (condition == kUnorderedEqual || condition == kUnorderedNotEqual) {
3082     return;
3083   }
3084 
3085   MipsOperandConverter i(this, instr);
3086   condition = NegateFlagsCondition(condition);
3087 
3088   switch (instr->arch_opcode()) {
3089     case kMips64Cmp: {
3090       __ LoadZeroOnCondition(kSpeculationPoisonRegister, i.InputRegister(0),
3091                              i.InputOperand(1),
3092                              FlagsConditionToConditionCmp(condition));
3093     }
3094       return;
3095     case kMips64Tst: {
3096       switch (condition) {
3097         case kEqual:
3098           __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
3099           break;
3100         case kNotEqual:
3101           __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
3102                                         kScratchReg);
3103           break;
3104         default:
3105           UNREACHABLE();
3106       }
3107     }
3108       return;
3109     case kMips64Dadd:
3110     case kMips64Dsub: {
3111       // Check for overflow creates 1 or 0 for result.
3112       __ dsrl32(kScratchReg, i.OutputRegister(), 31);
3113       __ srl(kScratchReg2, i.OutputRegister(), 31);
3114       __ xor_(kScratchReg2, kScratchReg, kScratchReg2);
3115       switch (condition) {
3116         case kOverflow:
3117           __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
3118                                         kScratchReg2);
3119           break;
3120         case kNotOverflow:
3121           __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2);
3122           break;
3123         default:
3124           UNSUPPORTED_COND(instr->arch_opcode(), condition);
3125       }
3126     }
3127       return;
3128     case kMips64DaddOvf:
3129     case kMips64DsubOvf: {
3130       // Overflow occurs if overflow register is negative
3131       __ Slt(kScratchReg2, kScratchReg, zero_reg);
3132       switch (condition) {
3133         case kOverflow:
3134           __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
3135                                         kScratchReg2);
3136           break;
3137         case kNotOverflow:
3138           __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2);
3139           break;
3140         default:
3141           UNSUPPORTED_COND(instr->arch_opcode(), condition);
3142       }
3143     }
3144       return;
3145     case kMips64MulOvf: {
3146       // Overflow occurs if overflow register is not zero
3147       switch (condition) {
3148         case kOverflow:
3149           __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
3150                                         kScratchReg);
3151           break;
3152         case kNotOverflow:
3153           __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
3154           break;
3155         default:
3156           UNSUPPORTED_COND(instr->arch_opcode(), condition);
3157       }
3158     }
3159       return;
3160     case kMips64CmpS:
3161     case kMips64CmpD: {
3162       bool predicate;
3163       FlagsConditionToConditionCmpFPU(predicate, condition);
3164       if (predicate) {
3165         __ LoadZeroIfFPUCondition(kSpeculationPoisonRegister);
3166       } else {
3167         __ LoadZeroIfNotFPUCondition(kSpeculationPoisonRegister);
3168       }
3169     }
3170       return;
3171     default:
3172       UNREACHABLE();
3173       break;
3174   }
3175 }
3176 
AssembleArchDeoptBranch(Instruction * instr,BranchInfo * branch)3177 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
3178                                             BranchInfo* branch) {
3179   AssembleArchBranch(instr, branch);
3180 }
3181 
AssembleArchJump(RpoNumber target)3182 void CodeGenerator::AssembleArchJump(RpoNumber target) {
3183   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
3184 }
3185 
AssembleArchTrap(Instruction * instr,FlagsCondition condition)3186 void CodeGenerator::AssembleArchTrap(Instruction* instr,
3187                                      FlagsCondition condition) {
3188   class OutOfLineTrap final : public OutOfLineCode {
3189    public:
3190     OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
3191         : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
3192     void Generate() final {
3193       MipsOperandConverter i(gen_, instr_);
3194       TrapId trap_id =
3195           static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
3196       GenerateCallToTrap(trap_id);
3197     }
3198 
3199    private:
3200     void GenerateCallToTrap(TrapId trap_id) {
3201       if (trap_id == TrapId::kInvalid) {
3202         // We cannot test calls to the runtime in cctest/test-run-wasm.
3203         // Therefore we emit a call to C here instead of a call to the runtime.
3204         // We use the context register as the scratch register, because we do
3205         // not have a context here.
3206         __ PrepareCallCFunction(0, 0, cp);
3207         __ CallCFunction(
3208             ExternalReference::wasm_call_trap_callback_for_testing(), 0);
3209         __ LeaveFrame(StackFrame::WASM_COMPILED);
3210         auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
3211         int pop_count =
3212             static_cast<int>(call_descriptor->StackParameterCount());
3213         pop_count += (pop_count & 1);  // align
3214         __ Drop(pop_count);
3215         __ Ret();
3216       } else {
3217         gen_->AssembleSourcePosition(instr_);
3218         // A direct call to a wasm runtime stub defined in this module.
3219         // Just encode the stub index. This will be patched at relocation.
3220         __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
3221         ReferenceMap* reference_map =
3222             new (gen_->zone()) ReferenceMap(gen_->zone());
3223         gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
3224                               Safepoint::kNoLazyDeopt);
3225         if (FLAG_debug_code) {
3226           __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromWasmTrap));
3227         }
3228       }
3229     }
3230     Instruction* instr_;
3231     CodeGenerator* gen_;
3232   };
3233   auto ool = new (zone()) OutOfLineTrap(this, instr);
3234   Label* tlabel = ool->entry();
3235   AssembleBranchToLabels(this, tasm(), instr, condition, tlabel, nullptr, true);
3236 }
3237 
3238 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)3239 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
3240                                         FlagsCondition condition) {
3241   MipsOperandConverter i(this, instr);
3242   Label done;
3243 
3244   // Materialize a full 32-bit 1 or 0 value. The result register is always the
3245   // last output of the instruction.
3246   Label false_value;
3247   DCHECK_NE(0u, instr->OutputCount());
3248   Register result = i.OutputRegister(instr->OutputCount() - 1);
3249   Condition cc = kNoCondition;
3250   // MIPS does not have condition code flags, so compare and branch are
3251   // implemented differently than on the other arch's. The compare operations
3252   // emit mips pseudo-instructions, which are checked and handled here.
3253 
3254   if (instr->arch_opcode() == kMips64Tst) {
3255     cc = FlagsConditionToConditionTst(condition);
3256     if (cc == eq) {
3257       __ Sltu(result, kScratchReg, 1);
3258     } else {
3259       __ Sltu(result, zero_reg, kScratchReg);
3260     }
3261     return;
3262   } else if (instr->arch_opcode() == kMips64Dadd ||
3263              instr->arch_opcode() == kMips64Dsub) {
3264     cc = FlagsConditionToConditionOvf(condition);
3265     // Check for overflow creates 1 or 0 for result.
3266     __ dsrl32(kScratchReg, i.OutputRegister(), 31);
3267     __ srl(kScratchReg2, i.OutputRegister(), 31);
3268     __ xor_(result, kScratchReg, kScratchReg2);
3269     if (cc == eq)  // Toggle result for not overflow.
3270       __ xori(result, result, 1);
3271     return;
3272   } else if (instr->arch_opcode() == kMips64DaddOvf ||
3273              instr->arch_opcode() == kMips64DsubOvf) {
3274     // Overflow occurs if overflow register is negative
3275     __ slt(result, kScratchReg, zero_reg);
3276   } else if (instr->arch_opcode() == kMips64MulOvf) {
3277     // Overflow occurs if overflow register is not zero
3278     __ Sgtu(result, kScratchReg, zero_reg);
3279   } else if (instr->arch_opcode() == kMips64Cmp) {
3280     cc = FlagsConditionToConditionCmp(condition);
3281     switch (cc) {
3282       case eq:
3283       case ne: {
3284         Register left = i.InputRegister(0);
3285         Operand right = i.InputOperand(1);
3286         if (instr->InputAt(1)->IsImmediate()) {
3287           if (is_int16(-right.immediate())) {
3288             if (right.immediate() == 0) {
3289               if (cc == eq) {
3290                 __ Sltu(result, left, 1);
3291               } else {
3292                 __ Sltu(result, zero_reg, left);
3293               }
3294             } else {
3295               __ Daddu(result, left, Operand(-right.immediate()));
3296               if (cc == eq) {
3297                 __ Sltu(result, result, 1);
3298               } else {
3299                 __ Sltu(result, zero_reg, result);
3300               }
3301             }
3302           } else {
3303             if (is_uint16(right.immediate())) {
3304               __ Xor(result, left, right);
3305             } else {
3306               __ li(kScratchReg, right);
3307               __ Xor(result, left, kScratchReg);
3308             }
3309             if (cc == eq) {
3310               __ Sltu(result, result, 1);
3311             } else {
3312               __ Sltu(result, zero_reg, result);
3313             }
3314           }
3315         } else {
3316           __ Xor(result, left, right);
3317           if (cc == eq) {
3318             __ Sltu(result, result, 1);
3319           } else {
3320             __ Sltu(result, zero_reg, result);
3321           }
3322         }
3323       } break;
3324       case lt:
3325       case ge: {
3326         Register left = i.InputRegister(0);
3327         Operand right = i.InputOperand(1);
3328         __ Slt(result, left, right);
3329         if (cc == ge) {
3330           __ xori(result, result, 1);
3331         }
3332       } break;
3333       case gt:
3334       case le: {
3335         Register left = i.InputRegister(1);
3336         Operand right = i.InputOperand(0);
3337         __ Slt(result, left, right);
3338         if (cc == le) {
3339           __ xori(result, result, 1);
3340         }
3341       } break;
3342       case lo:
3343       case hs: {
3344         Register left = i.InputRegister(0);
3345         Operand right = i.InputOperand(1);
3346         __ Sltu(result, left, right);
3347         if (cc == hs) {
3348           __ xori(result, result, 1);
3349         }
3350       } break;
3351       case hi:
3352       case ls: {
3353         Register left = i.InputRegister(1);
3354         Operand right = i.InputOperand(0);
3355         __ Sltu(result, left, right);
3356         if (cc == ls) {
3357           __ xori(result, result, 1);
3358         }
3359       } break;
3360       default:
3361         UNREACHABLE();
3362     }
3363     return;
3364   } else if (instr->arch_opcode() == kMips64CmpD ||
3365              instr->arch_opcode() == kMips64CmpS) {
3366     FPURegister left = i.InputOrZeroDoubleRegister(0);
3367     FPURegister right = i.InputOrZeroDoubleRegister(1);
3368     if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
3369         !__ IsDoubleZeroRegSet()) {
3370       __ Move(kDoubleRegZero, 0.0);
3371     }
3372     bool predicate;
3373     FlagsConditionToConditionCmpFPU(predicate, condition);
3374     if (kArchVariant != kMips64r6) {
3375       __ li(result, Operand(1));
3376       if (predicate) {
3377         __ Movf(result, zero_reg);
3378       } else {
3379         __ Movt(result, zero_reg);
3380       }
3381     } else {
3382       if (instr->arch_opcode() == kMips64CmpD) {
3383         __ dmfc1(result, kDoubleCompareReg);
3384       } else {
3385         DCHECK_EQ(kMips64CmpS, instr->arch_opcode());
3386         __ mfc1(result, kDoubleCompareReg);
3387       }
3388       if (predicate) {
3389         __ And(result, result, 1);  // cmp returns all 1's/0's, use only LSB.
3390       } else {
3391         __ Addu(result, result, 1);  // Toggle result for not equal.
3392       }
3393     }
3394     return;
3395   } else {
3396     PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
3397            instr->arch_opcode());
3398     TRACE_UNIMPL();
3399     UNIMPLEMENTED();
3400   }
3401 }
3402 
AssembleArchBinarySearchSwitch(Instruction * instr)3403 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
3404   MipsOperandConverter i(this, instr);
3405   Register input = i.InputRegister(0);
3406   std::vector<std::pair<int32_t, Label*>> cases;
3407   for (size_t index = 2; index < instr->InputCount(); index += 2) {
3408     cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
3409   }
3410   AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
3411                                       cases.data() + cases.size());
3412 }
3413 
AssembleArchLookupSwitch(Instruction * instr)3414 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
3415   MipsOperandConverter i(this, instr);
3416   Register input = i.InputRegister(0);
3417   for (size_t index = 2; index < instr->InputCount(); index += 2) {
3418     __ li(kScratchReg, Operand(i.InputInt32(index + 0)));
3419     __ Branch(GetLabel(i.InputRpo(index + 1)), eq, input, Operand(kScratchReg));
3420   }
3421   AssembleArchJump(i.InputRpo(1));
3422 }
3423 
AssembleArchTableSwitch(Instruction * instr)3424 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
3425   MipsOperandConverter i(this, instr);
3426   Register input = i.InputRegister(0);
3427   size_t const case_count = instr->InputCount() - 2;
3428 
3429   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
3430   __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
3431     return GetLabel(i.InputRpo(index + 2));
3432   });
3433 }
3434 
FinishFrame(Frame * frame)3435 void CodeGenerator::FinishFrame(Frame* frame) {
3436   auto call_descriptor = linkage()->GetIncomingDescriptor();
3437 
3438   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3439   if (saves_fpu != 0) {
3440     int count = base::bits::CountPopulation(saves_fpu);
3441     DCHECK_EQ(kNumCalleeSavedFPU, count);
3442     frame->AllocateSavedCalleeRegisterSlots(count *
3443                                             (kDoubleSize / kPointerSize));
3444   }
3445 
3446   const RegList saves = call_descriptor->CalleeSavedRegisters();
3447   if (saves != 0) {
3448     int count = base::bits::CountPopulation(saves);
3449     DCHECK_EQ(kNumCalleeSaved, count + 1);
3450     frame->AllocateSavedCalleeRegisterSlots(count);
3451   }
3452 }
3453 
AssembleConstructFrame()3454 void CodeGenerator::AssembleConstructFrame() {
3455   auto call_descriptor = linkage()->GetIncomingDescriptor();
3456 
3457   if (frame_access_state()->has_frame()) {
3458     if (call_descriptor->IsCFunctionCall()) {
3459       __ Push(ra, fp);
3460       __ mov(fp, sp);
3461     } else if (call_descriptor->IsJSFunctionCall()) {
3462       __ Prologue();
3463       if (call_descriptor->PushArgumentCount()) {
3464         __ Push(kJavaScriptCallArgCountRegister);
3465       }
3466     } else {
3467       __ StubPrologue(info()->GetOutputStackFrameType());
3468       if (call_descriptor->IsWasmFunctionCall()) {
3469         __ Push(kWasmInstanceRegister);
3470       }
3471     }
3472   }
3473 
3474   int shrink_slots = frame()->GetTotalFrameSlotCount() -
3475                      call_descriptor->CalculateFixedFrameSize();
3476 
3477   if (info()->is_osr()) {
3478     // TurboFan OSR-compiled functions cannot be entered directly.
3479     __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
3480 
3481     // Unoptimized code jumps directly to this entrypoint while the unoptimized
3482     // frame is still on the stack. Optimized code uses OSR values directly from
3483     // the unoptimized frame. Thus, all that needs to be done is to allocate the
3484     // remaining stack slots.
3485     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
3486     osr_pc_offset_ = __ pc_offset();
3487     shrink_slots -= osr_helper()->UnoptimizedFrameSlots();
3488     ResetSpeculationPoison();
3489   }
3490 
3491   const RegList saves = call_descriptor->CalleeSavedRegisters();
3492   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3493   const int returns = frame()->GetReturnSlotCount();
3494 
3495   // Skip callee-saved and return slots, which are pushed below.
3496   shrink_slots -= base::bits::CountPopulation(saves);
3497   shrink_slots -= base::bits::CountPopulation(saves_fpu);
3498   shrink_slots -= returns;
3499   if (shrink_slots > 0) {
3500     __ Dsubu(sp, sp, Operand(shrink_slots * kPointerSize));
3501   }
3502 
3503   if (saves_fpu != 0) {
3504     // Save callee-saved FPU registers.
3505     __ MultiPushFPU(saves_fpu);
3506     DCHECK_EQ(kNumCalleeSavedFPU, base::bits::CountPopulation(saves_fpu));
3507   }
3508 
3509   if (saves != 0) {
3510     // Save callee-saved registers.
3511     __ MultiPush(saves);
3512     DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation(saves) + 1);
3513   }
3514 
3515   if (returns != 0) {
3516     // Create space for returns.
3517     __ Dsubu(sp, sp, Operand(returns * kPointerSize));
3518   }
3519 }
3520 
AssembleReturn(InstructionOperand * pop)3521 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
3522   auto call_descriptor = linkage()->GetIncomingDescriptor();
3523 
3524   const int returns = frame()->GetReturnSlotCount();
3525   if (returns != 0) {
3526     __ Daddu(sp, sp, Operand(returns * kPointerSize));
3527   }
3528 
3529   // Restore GP registers.
3530   const RegList saves = call_descriptor->CalleeSavedRegisters();
3531   if (saves != 0) {
3532     __ MultiPop(saves);
3533   }
3534 
3535   // Restore FPU registers.
3536   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3537   if (saves_fpu != 0) {
3538     __ MultiPopFPU(saves_fpu);
3539   }
3540 
3541   MipsOperandConverter g(this, nullptr);
3542   if (call_descriptor->IsCFunctionCall()) {
3543     AssembleDeconstructFrame();
3544   } else if (frame_access_state()->has_frame()) {
3545     // Canonicalize JSFunction return sites for now unless they have an variable
3546     // number of stack slot pops.
3547     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
3548       if (return_label_.is_bound()) {
3549         __ Branch(&return_label_);
3550         return;
3551       } else {
3552         __ bind(&return_label_);
3553         AssembleDeconstructFrame();
3554       }
3555     } else {
3556       AssembleDeconstructFrame();
3557     }
3558   }
3559   int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
3560   if (pop->IsImmediate()) {
3561     pop_count += g.ToConstant(pop).ToInt32();
3562   } else {
3563     Register pop_reg = g.ToRegister(pop);
3564     __ dsll(pop_reg, pop_reg, kPointerSizeLog2);
3565     __ Daddu(sp, sp, pop_reg);
3566   }
3567   if (pop_count != 0) {
3568     __ DropAndRet(pop_count);
3569   } else {
3570     __ Ret();
3571   }
3572 }
3573 
FinishCode()3574 void CodeGenerator::FinishCode() {}
3575 
AssembleMove(InstructionOperand * source,InstructionOperand * destination)3576 void CodeGenerator::AssembleMove(InstructionOperand* source,
3577                                  InstructionOperand* destination) {
3578   MipsOperandConverter g(this, nullptr);
3579   // Dispatch on the source and destination operand kinds.  Not all
3580   // combinations are possible.
3581   if (source->IsRegister()) {
3582     DCHECK(destination->IsRegister() || destination->IsStackSlot());
3583     Register src = g.ToRegister(source);
3584     if (destination->IsRegister()) {
3585       __ mov(g.ToRegister(destination), src);
3586     } else {
3587       __ Sd(src, g.ToMemOperand(destination));
3588     }
3589   } else if (source->IsStackSlot()) {
3590     DCHECK(destination->IsRegister() || destination->IsStackSlot());
3591     MemOperand src = g.ToMemOperand(source);
3592     if (destination->IsRegister()) {
3593       __ Ld(g.ToRegister(destination), src);
3594     } else {
3595       Register temp = kScratchReg;
3596       __ Ld(temp, src);
3597       __ Sd(temp, g.ToMemOperand(destination));
3598     }
3599   } else if (source->IsConstant()) {
3600     Constant src = g.ToConstant(source);
3601     if (destination->IsRegister() || destination->IsStackSlot()) {
3602       Register dst =
3603           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
3604       switch (src.type()) {
3605         case Constant::kInt32:
3606           __ li(dst, Operand(src.ToInt32()));
3607           break;
3608         case Constant::kFloat32:
3609           __ li(dst, Operand::EmbeddedNumber(src.ToFloat32()));
3610           break;
3611         case Constant::kInt64:
3612           if (RelocInfo::IsWasmPtrReference(src.rmode())) {
3613             __ li(dst, Operand(src.ToInt64(), src.rmode()));
3614           } else {
3615             __ li(dst, Operand(src.ToInt64()));
3616           }
3617           break;
3618         case Constant::kFloat64:
3619           __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
3620           break;
3621         case Constant::kExternalReference:
3622           __ li(dst, src.ToExternalReference());
3623           break;
3624         case Constant::kHeapObject: {
3625           Handle<HeapObject> src_object = src.ToHeapObject();
3626           Heap::RootListIndex index;
3627           if (IsMaterializableFromRoot(src_object, &index)) {
3628             __ LoadRoot(dst, index);
3629           } else {
3630             __ li(dst, src_object);
3631           }
3632           break;
3633         }
3634         case Constant::kRpoNumber:
3635           UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
3636           break;
3637       }
3638       if (destination->IsStackSlot()) __ Sd(dst, g.ToMemOperand(destination));
3639     } else if (src.type() == Constant::kFloat32) {
3640       if (destination->IsFPStackSlot()) {
3641         MemOperand dst = g.ToMemOperand(destination);
3642         if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
3643           __ Sd(zero_reg, dst);
3644         } else {
3645           __ li(kScratchReg, Operand(bit_cast<int32_t>(src.ToFloat32())));
3646           __ Sd(kScratchReg, dst);
3647         }
3648       } else {
3649         DCHECK(destination->IsFPRegister());
3650         FloatRegister dst = g.ToSingleRegister(destination);
3651         __ Move(dst, src.ToFloat32());
3652       }
3653     } else {
3654       DCHECK_EQ(Constant::kFloat64, src.type());
3655       DoubleRegister dst = destination->IsFPRegister()
3656                                ? g.ToDoubleRegister(destination)
3657                                : kScratchDoubleReg;
3658       __ Move(dst, src.ToFloat64().value());
3659       if (destination->IsFPStackSlot()) {
3660         __ Sdc1(dst, g.ToMemOperand(destination));
3661       }
3662     }
3663   } else if (source->IsFPRegister()) {
3664     MachineRepresentation rep = LocationOperand::cast(source)->representation();
3665     if (rep == MachineRepresentation::kSimd128) {
3666       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3667       MSARegister src = g.ToSimd128Register(source);
3668       if (destination->IsSimd128Register()) {
3669         MSARegister dst = g.ToSimd128Register(destination);
3670         __ move_v(dst, src);
3671       } else {
3672         DCHECK(destination->IsSimd128StackSlot());
3673         __ st_b(src, g.ToMemOperand(destination));
3674       }
3675     } else {
3676       FPURegister src = g.ToDoubleRegister(source);
3677       if (destination->IsFPRegister()) {
3678         FPURegister dst = g.ToDoubleRegister(destination);
3679         __ Move(dst, src);
3680       } else {
3681         DCHECK(destination->IsFPStackSlot());
3682         __ Sdc1(src, g.ToMemOperand(destination));
3683       }
3684     }
3685   } else if (source->IsFPStackSlot()) {
3686     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
3687     MemOperand src = g.ToMemOperand(source);
3688     MachineRepresentation rep = LocationOperand::cast(source)->representation();
3689     if (rep == MachineRepresentation::kSimd128) {
3690       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3691       if (destination->IsSimd128Register()) {
3692         __ ld_b(g.ToSimd128Register(destination), src);
3693       } else {
3694         DCHECK(destination->IsSimd128StackSlot());
3695         MSARegister temp = kSimd128ScratchReg;
3696         __ ld_b(temp, src);
3697         __ st_b(temp, g.ToMemOperand(destination));
3698       }
3699     } else {
3700       if (destination->IsFPRegister()) {
3701         __ Ldc1(g.ToDoubleRegister(destination), src);
3702       } else {
3703         DCHECK(destination->IsFPStackSlot());
3704         FPURegister temp = kScratchDoubleReg;
3705         __ Ldc1(temp, src);
3706         __ Sdc1(temp, g.ToMemOperand(destination));
3707       }
3708     }
3709   } else {
3710     UNREACHABLE();
3711   }
3712 }
3713 
3714 
AssembleSwap(InstructionOperand * source,InstructionOperand * destination)3715 void CodeGenerator::AssembleSwap(InstructionOperand* source,
3716                                  InstructionOperand* destination) {
3717   MipsOperandConverter g(this, nullptr);
3718   // Dispatch on the source and destination operand kinds.  Not all
3719   // combinations are possible.
3720   if (source->IsRegister()) {
3721     // Register-register.
3722     Register temp = kScratchReg;
3723     Register src = g.ToRegister(source);
3724     if (destination->IsRegister()) {
3725       Register dst = g.ToRegister(destination);
3726       __ Move(temp, src);
3727       __ Move(src, dst);
3728       __ Move(dst, temp);
3729     } else {
3730       DCHECK(destination->IsStackSlot());
3731       MemOperand dst = g.ToMemOperand(destination);
3732       __ mov(temp, src);
3733       __ Ld(src, dst);
3734       __ Sd(temp, dst);
3735     }
3736   } else if (source->IsStackSlot()) {
3737     DCHECK(destination->IsStackSlot());
3738     Register temp_0 = kScratchReg;
3739     Register temp_1 = kScratchReg2;
3740     MemOperand src = g.ToMemOperand(source);
3741     MemOperand dst = g.ToMemOperand(destination);
3742     __ Ld(temp_0, src);
3743     __ Ld(temp_1, dst);
3744     __ Sd(temp_0, dst);
3745     __ Sd(temp_1, src);
3746   } else if (source->IsFPRegister()) {
3747     MachineRepresentation rep = LocationOperand::cast(source)->representation();
3748     if (rep == MachineRepresentation::kSimd128) {
3749       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3750       MSARegister temp = kSimd128ScratchReg;
3751       MSARegister src = g.ToSimd128Register(source);
3752       if (destination->IsSimd128Register()) {
3753         MSARegister dst = g.ToSimd128Register(destination);
3754         __ move_v(temp, src);
3755         __ move_v(src, dst);
3756         __ move_v(dst, temp);
3757       } else {
3758         DCHECK(destination->IsSimd128StackSlot());
3759         MemOperand dst = g.ToMemOperand(destination);
3760         __ move_v(temp, src);
3761         __ ld_b(src, dst);
3762         __ st_b(temp, dst);
3763       }
3764     } else {
3765       FPURegister temp = kScratchDoubleReg;
3766       FPURegister src = g.ToDoubleRegister(source);
3767       if (destination->IsFPRegister()) {
3768         FPURegister dst = g.ToDoubleRegister(destination);
3769         __ Move(temp, src);
3770         __ Move(src, dst);
3771         __ Move(dst, temp);
3772       } else {
3773         DCHECK(destination->IsFPStackSlot());
3774         MemOperand dst = g.ToMemOperand(destination);
3775         __ Move(temp, src);
3776         __ Ldc1(src, dst);
3777         __ Sdc1(temp, dst);
3778       }
3779     }
3780   } else if (source->IsFPStackSlot()) {
3781     DCHECK(destination->IsFPStackSlot());
3782     Register temp_0 = kScratchReg;
3783     MemOperand src0 = g.ToMemOperand(source);
3784     MemOperand src1(src0.rm(), src0.offset() + kIntSize);
3785     MemOperand dst0 = g.ToMemOperand(destination);
3786     MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
3787     MachineRepresentation rep = LocationOperand::cast(source)->representation();
3788     if (rep == MachineRepresentation::kSimd128) {
3789       MemOperand src2(src0.rm(), src0.offset() + 2 * kIntSize);
3790       MemOperand src3(src0.rm(), src0.offset() + 3 * kIntSize);
3791       MemOperand dst2(dst0.rm(), dst0.offset() + 2 * kIntSize);
3792       MemOperand dst3(dst0.rm(), dst0.offset() + 3 * kIntSize);
3793       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3794       MSARegister temp_1 = kSimd128ScratchReg;
3795       __ ld_b(temp_1, dst0);  // Save destination in temp_1.
3796       __ Lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
3797       __ Sw(temp_0, dst0);
3798       __ Lw(temp_0, src1);
3799       __ Sw(temp_0, dst1);
3800       __ Lw(temp_0, src2);
3801       __ Sw(temp_0, dst2);
3802       __ Lw(temp_0, src3);
3803       __ Sw(temp_0, dst3);
3804       __ st_b(temp_1, src0);
3805     } else {
3806       FPURegister temp_1 = kScratchDoubleReg;
3807       __ Ldc1(temp_1, dst0);  // Save destination in temp_1.
3808       __ Lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
3809       __ Sw(temp_0, dst0);
3810       __ Lw(temp_0, src1);
3811       __ Sw(temp_0, dst1);
3812       __ Sdc1(temp_1, src0);
3813     }
3814   } else {
3815     // No other combinations are possible.
3816     UNREACHABLE();
3817   }
3818 }
3819 
3820 
AssembleJumpTable(Label ** targets,size_t target_count)3821 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
3822   // On 64-bit MIPS we emit the jump tables inline.
3823   UNREACHABLE();
3824 }
3825 
3826 #undef __
3827 
3828 }  // namespace compiler
3829 }  // namespace internal
3830 }  // namespace v8
3831