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