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/optimized-compilation-info.h"
9 #include "src/compiler/backend/code-generator-impl.h"
10 #include "src/compiler/backend/code-generator.h"
11 #include "src/compiler/backend/gap-resolver.h"
12 #include "src/compiler/node-matchers.h"
13 #include "src/compiler/osr.h"
14 #include "src/heap/memory-chunk.h"
15 
16 #if V8_ENABLE_WEBASSEMBLY
17 #include "src/wasm/wasm-code-manager.h"
18 #endif  // V8_ENABLE_WEBASSEMBLY
19 
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23 
24 #define __ tasm()->
25 
26 // TODO(plind): consider renaming these macros.
27 #define TRACE_MSG(msg)                                                      \
28   PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
29          __LINE__)
30 
31 #define TRACE_UNIMPL()                                                       \
32   PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
33          __LINE__)
34 
35 // Adds Mips-specific methods to convert InstructionOperands.
36 class MipsOperandConverter final : public InstructionOperandConverter {
37  public:
MipsOperandConverter(CodeGenerator * gen,Instruction * instr)38   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
39       : InstructionOperandConverter(gen, instr) {}
40 
OutputSingleRegister(size_t index=0)41   FloatRegister OutputSingleRegister(size_t index = 0) {
42     return ToSingleRegister(instr_->OutputAt(index));
43   }
44 
InputSingleRegister(size_t index)45   FloatRegister InputSingleRegister(size_t index) {
46     return ToSingleRegister(instr_->InputAt(index));
47   }
48 
ToSingleRegister(InstructionOperand * op)49   FloatRegister ToSingleRegister(InstructionOperand* op) {
50     // Single (Float) and Double register namespace is same on MIPS,
51     // both are typedefs of FPURegister.
52     return ToDoubleRegister(op);
53   }
54 
InputOrZeroRegister(size_t index)55   Register InputOrZeroRegister(size_t index) {
56     if (instr_->InputAt(index)->IsImmediate()) {
57       DCHECK_EQ(0, InputInt32(index));
58       return zero_reg;
59     }
60     return InputRegister(index);
61   }
62 
InputOrZeroDoubleRegister(size_t index)63   DoubleRegister InputOrZeroDoubleRegister(size_t index) {
64     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
65 
66     return InputDoubleRegister(index);
67   }
68 
InputOrZeroSingleRegister(size_t index)69   DoubleRegister InputOrZeroSingleRegister(size_t index) {
70     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
71 
72     return InputSingleRegister(index);
73   }
74 
InputImmediate(size_t index)75   Operand InputImmediate(size_t index) {
76     Constant constant = ToConstant(instr_->InputAt(index));
77     switch (constant.type()) {
78       case Constant::kInt32:
79         return Operand(constant.ToInt32());
80       case Constant::kFloat32:
81         return Operand::EmbeddedNumber(constant.ToFloat32());
82       case Constant::kFloat64:
83         return Operand::EmbeddedNumber(constant.ToFloat64().value());
84       case Constant::kInt64:
85       case Constant::kExternalReference:
86       case Constant::kCompressedHeapObject:
87       case Constant::kHeapObject:
88         // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
89         //    maybe not done on arm due to const pool ??
90         break;
91       case Constant::kDelayedStringConstant:
92         return Operand::EmbeddedStringConstant(
93             constant.ToDelayedStringConstant());
94       case Constant::kRpoNumber:
95         UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
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 #if V8_ENABLE_WEBASSEMBLY
156         stub_mode_(stub_mode),
157 #endif  // V8_ENABLE_WEBASSEMBLY
158         must_save_lr_(!gen->frame_access_state()->has_frame()),
159         zone_(gen->zone()) {
160     DCHECK(!AreAliased(object, index, scratch0, scratch1));
161     DCHECK(!AreAliased(value, index, scratch0, scratch1));
162   }
163 
Generate()164   void Generate() final {
165     __ CheckPageFlag(value_, scratch0_,
166                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
167                      exit());
168     __ Addu(scratch1_, object_, index_);
169     RememberedSetAction const remembered_set_action =
170         mode_ > RecordWriteMode::kValueIsMap ? RememberedSetAction::kEmit
171                                              : RememberedSetAction::kOmit;
172     SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
173                                             ? SaveFPRegsMode::kSave
174                                             : SaveFPRegsMode::kIgnore;
175     if (must_save_lr_) {
176       // We need to save and restore ra if the frame was elided.
177       __ Push(ra);
178     }
179 
180     if (mode_ == RecordWriteMode::kValueIsEphemeronKey) {
181       __ CallEphemeronKeyBarrier(object_, scratch1_, save_fp_mode);
182 #if V8_ENABLE_WEBASSEMBLY
183     } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
184       // A direct call to a wasm runtime stub defined in this module.
185       // Just encode the stub index. This will be patched when the code
186       // is added to the native module and copied into wasm code space.
187       __ CallRecordWriteStubSaveRegisters(object_, scratch1_,
188                                           remembered_set_action, save_fp_mode,
189                                           StubCallMode::kCallWasmRuntimeStub);
190 #endif  // V8_ENABLE_WEBASSEMBLY
191     } else {
192       __ CallRecordWriteStubSaveRegisters(object_, scratch1_,
193                                           remembered_set_action, save_fp_mode);
194     }
195     if (must_save_lr_) {
196       __ Pop(ra);
197     }
198   }
199 
200  private:
201   Register const object_;
202   Register const index_;
203   Register const value_;
204   Register const scratch0_;
205   Register const scratch1_;
206   RecordWriteMode const mode_;
207 #if V8_ENABLE_WEBASSEMBLY
208   StubCallMode const stub_mode_;
209 #endif  // V8_ENABLE_WEBASSEMBLY
210   bool must_save_lr_;
211   Zone* zone_;
212 };
213 
214 #define CREATE_OOL_CLASS(ool_name, tasm_ool_name, T)                 \
215   class ool_name final : public OutOfLineCode {                      \
216    public:                                                           \
217     ool_name(CodeGenerator* gen, T dst, T src1, T src2)              \
218         : OutOfLineCode(gen), dst_(dst), src1_(src1), src2_(src2) {} \
219                                                                      \
220     void Generate() final { __ tasm_ool_name(dst_, src1_, src2_); }  \
221                                                                      \
222    private:                                                          \
223     T const dst_;                                                    \
224     T const src1_;                                                   \
225     T const src2_;                                                   \
226   }
227 
228 CREATE_OOL_CLASS(OutOfLineFloat32Max, Float32MaxOutOfLine, FPURegister);
229 CREATE_OOL_CLASS(OutOfLineFloat32Min, Float32MinOutOfLine, FPURegister);
230 CREATE_OOL_CLASS(OutOfLineFloat64Max, Float64MaxOutOfLine, DoubleRegister);
231 CREATE_OOL_CLASS(OutOfLineFloat64Min, Float64MinOutOfLine, DoubleRegister);
232 
233 #undef CREATE_OOL_CLASS
234 
FlagsConditionToConditionCmp(FlagsCondition condition)235 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
236   switch (condition) {
237     case kEqual:
238       return eq;
239     case kNotEqual:
240       return ne;
241     case kSignedLessThan:
242       return lt;
243     case kSignedGreaterThanOrEqual:
244       return ge;
245     case kSignedLessThanOrEqual:
246       return le;
247     case kSignedGreaterThan:
248       return gt;
249     case kUnsignedLessThan:
250       return lo;
251     case kUnsignedGreaterThanOrEqual:
252       return hs;
253     case kUnsignedLessThanOrEqual:
254       return ls;
255     case kUnsignedGreaterThan:
256       return hi;
257     case kUnorderedEqual:
258     case kUnorderedNotEqual:
259       break;
260     default:
261       break;
262   }
263   UNREACHABLE();
264 }
265 
FlagsConditionToConditionTst(FlagsCondition condition)266 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
267   switch (condition) {
268     case kNotEqual:
269       return ne;
270     case kEqual:
271       return eq;
272     default:
273       break;
274   }
275   UNREACHABLE();
276 }
277 
FlagsConditionToConditionCmpFPU(bool * predicate,FlagsCondition condition)278 FPUCondition FlagsConditionToConditionCmpFPU(bool* predicate,
279                                              FlagsCondition condition) {
280   switch (condition) {
281     case kEqual:
282       *predicate = true;
283       return EQ;
284     case kNotEqual:
285       *predicate = false;
286       return EQ;
287     case kUnsignedLessThan:
288       *predicate = true;
289       return OLT;
290     case kUnsignedGreaterThanOrEqual:
291       *predicate = false;
292       return OLT;
293     case kUnsignedLessThanOrEqual:
294       *predicate = true;
295       return OLE;
296     case kUnsignedGreaterThan:
297       *predicate = false;
298       return OLE;
299     case kUnorderedEqual:
300     case kUnorderedNotEqual:
301       *predicate = true;
302       break;
303     default:
304       *predicate = true;
305       break;
306   }
307   UNREACHABLE();
308 }
309 
310 #define UNSUPPORTED_COND(opcode, condition)                                    \
311   StdoutStream{} << "Unsupported " << #opcode << " condition: \"" << condition \
312                  << "\"";                                                      \
313   UNIMPLEMENTED();
314 
315 }  // namespace
316 
317 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
318   do {                                                   \
319     __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
320     __ sync();                                           \
321   } while (0)
322 
323 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)               \
324   do {                                                         \
325     __ sync();                                                 \
326     __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
327     __ sync();                                                 \
328   } while (0)
329 
330 #define ASSEMBLE_ATOMIC_BINOP(bin_instr)                                \
331   do {                                                                  \
332     Label binop;                                                        \
333     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
334     __ sync();                                                          \
335     __ bind(&binop);                                                    \
336     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));       \
337     __ bin_instr(i.TempRegister(1), i.OutputRegister(0),                \
338                  Operand(i.InputRegister(2)));                          \
339     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));         \
340     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));   \
341     __ sync();                                                          \
342   } while (0)
343 
344 #define ASSEMBLE_ATOMIC64_LOGIC_BINOP(bin_instr, external)                     \
345   do {                                                                         \
346     if (IsMipsArchVariant(kMips32r6)) {                                        \
347       Label binop;                                                             \
348       Register oldval_low =                                                    \
349           instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1); \
350       Register oldval_high =                                                   \
351           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2); \
352       __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));      \
353       __ sync();                                                               \
354       __ bind(&binop);                                                         \
355       __ llx(oldval_high, MemOperand(i.TempRegister(0), 4));                   \
356       __ ll(oldval_low, MemOperand(i.TempRegister(0), 0));                     \
357       __ bin_instr(i.TempRegister(1), i.TempRegister(2), oldval_low,           \
358                    oldval_high, i.InputRegister(2), i.InputRegister(3));       \
359       __ scx(i.TempRegister(2), MemOperand(i.TempRegister(0), 4));             \
360       __ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));              \
361       __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));        \
362       __ sync();                                                               \
363     } else {                                                                   \
364       FrameScope scope(tasm(), StackFrame::MANUAL);                            \
365       __ Addu(a0, i.InputRegister(0), i.InputRegister(1));                     \
366       __ PushCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);                     \
367       __ PrepareCallCFunction(3, 0, kScratchReg);                              \
368       __ CallCFunction(ExternalReference::external(), 3, 0);                   \
369       __ PopCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);                      \
370     }                                                                          \
371   } while (0)
372 
373 #define ASSEMBLE_ATOMIC64_ARITH_BINOP(bin_instr, external)                     \
374   do {                                                                         \
375     if (IsMipsArchVariant(kMips32r6)) {                                        \
376       Label binop;                                                             \
377       Register oldval_low =                                                    \
378           instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1); \
379       Register oldval_high =                                                   \
380           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2); \
381       __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));      \
382       __ sync();                                                               \
383       __ bind(&binop);                                                         \
384       __ llx(oldval_high, MemOperand(i.TempRegister(0), 4));                   \
385       __ ll(oldval_low, MemOperand(i.TempRegister(0), 0));                     \
386       __ bin_instr(i.TempRegister(1), i.TempRegister(2), oldval_low,           \
387                    oldval_high, i.InputRegister(2), i.InputRegister(3),        \
388                    kScratchReg, kScratchReg2);                                 \
389       __ scx(i.TempRegister(2), MemOperand(i.TempRegister(0), 4));             \
390       __ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));              \
391       __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));        \
392       __ sync();                                                               \
393     } else {                                                                   \
394       FrameScope scope(tasm(), StackFrame::MANUAL);                            \
395       __ Addu(a0, i.InputRegister(0), i.InputRegister(1));                     \
396       __ PushCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);                     \
397       __ PrepareCallCFunction(3, 0, kScratchReg);                              \
398       __ CallCFunction(ExternalReference::external(), 3, 0);                   \
399       __ PopCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);                      \
400     }                                                                          \
401   } while (0)
402 
403 #define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr)                \
404   do {                                                                         \
405     Label binop;                                                               \
406     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
407     __ andi(i.TempRegister(3), i.TempRegister(0), 0x3);                        \
408     __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(3))); \
409     __ sll(i.TempRegister(3), i.TempRegister(3), 3);                           \
410     __ sync();                                                                 \
411     __ bind(&binop);                                                           \
412     __ Ll(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));                \
413     __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3),  \
414                    size, sign_extend);                                         \
415     __ bin_instr(i.TempRegister(2), i.OutputRegister(0),                       \
416                  Operand(i.InputRegister(2)));                                 \
417     __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3),     \
418                   size);                                                       \
419     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));                \
420     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));          \
421     __ sync();                                                                 \
422   } while (0)
423 
424 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER()                               \
425   do {                                                                   \
426     Label exchange;                                                      \
427     __ sync();                                                           \
428     __ bind(&exchange);                                                  \
429     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));  \
430     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));        \
431     __ mov(i.TempRegister(1), i.InputRegister(2));                       \
432     __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));          \
433     __ BranchShort(&exchange, eq, i.TempRegister(1), Operand(zero_reg)); \
434     __ sync();                                                           \
435   } while (0)
436 
437 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(sign_extend, size)                \
438   do {                                                                         \
439     Label exchange;                                                            \
440     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
441     __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                        \
442     __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(1))); \
443     __ sll(i.TempRegister(1), i.TempRegister(1), 3);                           \
444     __ sync();                                                                 \
445     __ bind(&exchange);                                                        \
446     __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
447     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
448                    size, sign_extend);                                         \
449     __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1),    \
450                   size);                                                       \
451     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
452     __ BranchShort(&exchange, eq, i.TempRegister(2), Operand(zero_reg));       \
453     __ sync();                                                                 \
454   } while (0)
455 
456 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER()                      \
457   do {                                                                  \
458     Label compareExchange;                                              \
459     Label exit;                                                         \
460     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
461     __ sync();                                                          \
462     __ bind(&compareExchange);                                          \
463     __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));       \
464     __ BranchShort(&exit, ne, i.InputRegister(2),                       \
465                    Operand(i.OutputRegister(0)));                       \
466     __ mov(i.TempRegister(2), i.InputRegister(3));                      \
467     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));         \
468     __ BranchShort(&compareExchange, eq, i.TempRegister(2),             \
469                    Operand(zero_reg));                                  \
470     __ bind(&exit);                                                     \
471     __ sync();                                                          \
472   } while (0)
473 
474 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(sign_extend, size)        \
475   do {                                                                         \
476     Label compareExchange;                                                     \
477     Label exit;                                                                \
478     __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
479     __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                        \
480     __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(1))); \
481     __ sll(i.TempRegister(1), i.TempRegister(1), 3);                           \
482     __ sync();                                                                 \
483     __ bind(&compareExchange);                                                 \
484     __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
485     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
486                    size, sign_extend);                                         \
487     __ ExtractBits(i.InputRegister(2), i.InputRegister(2), zero_reg, size,     \
488                    sign_extend);                                               \
489     __ BranchShort(&exit, ne, i.InputRegister(2),                              \
490                    Operand(i.OutputRegister(0)));                              \
491     __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1),    \
492                   size);                                                       \
493     __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
494     __ BranchShort(&compareExchange, eq, i.TempRegister(2),                    \
495                    Operand(zero_reg));                                         \
496     __ bind(&exit);                                                            \
497     __ sync();                                                                 \
498   } while (0)
499 
500 #define ASSEMBLE_IEEE754_BINOP(name)                                        \
501   do {                                                                      \
502     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
503     __ PrepareCallCFunction(0, 2, kScratchReg);                             \
504     __ MovToFloatParameters(i.InputDoubleRegister(0),                       \
505                             i.InputDoubleRegister(1));                      \
506     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
507     /* Move the result in the double result register. */                    \
508     __ MovFromFloatResult(i.OutputDoubleRegister());                        \
509   } while (0)
510 
511 #define ASSEMBLE_IEEE754_UNOP(name)                                         \
512   do {                                                                      \
513     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
514     __ PrepareCallCFunction(0, 1, kScratchReg);                             \
515     __ MovToFloatParameter(i.InputDoubleRegister(0));                       \
516     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
517     /* Move the result in the double result register. */                    \
518     __ MovFromFloatResult(i.OutputDoubleRegister());                        \
519   } while (0)
520 
521 #define ASSEMBLE_F64X2_ARITHMETIC_BINOP(op)                     \
522   do {                                                          \
523     __ op(i.OutputSimd128Register(), i.InputSimd128Register(0), \
524           i.InputSimd128Register(1));                           \
525   } while (0)
526 
527 #define ASSEMBLE_SIMD_EXTENDED_MULTIPLY(op0, op1)                           \
528   do {                                                                      \
529     CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);                           \
530     __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);            \
531     __ op0(kSimd128ScratchReg, kSimd128RegZero, i.InputSimd128Register(0)); \
532     __ op0(kSimd128RegZero, kSimd128RegZero, i.InputSimd128Register(1));    \
533     __ op1(i.OutputSimd128Register(), kSimd128ScratchReg, kSimd128RegZero); \
534   } while (0)
535 
AssembleDeconstructFrame()536 void CodeGenerator::AssembleDeconstructFrame() {
537   __ mov(sp, fp);
538   __ Pop(ra, fp);
539 }
540 
AssemblePrepareTailCall()541 void CodeGenerator::AssemblePrepareTailCall() {
542   if (frame_access_state()->has_frame()) {
543     __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
544     __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
545   }
546   frame_access_state()->SetFrameAccessToSP();
547 }
548 namespace {
549 
AdjustStackPointerForTailCall(TurboAssembler * tasm,FrameAccessState * state,int new_slot_above_sp,bool allow_shrinkage=true)550 void AdjustStackPointerForTailCall(TurboAssembler* tasm,
551                                    FrameAccessState* state,
552                                    int new_slot_above_sp,
553                                    bool allow_shrinkage = true) {
554   int current_sp_offset = state->GetSPToFPSlotCount() +
555                           StandardFrameConstants::kFixedSlotCountAboveFp;
556   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
557   if (stack_slot_delta > 0) {
558     tasm->Subu(sp, sp, stack_slot_delta * kSystemPointerSize);
559     state->IncreaseSPDelta(stack_slot_delta);
560   } else if (allow_shrinkage && stack_slot_delta < 0) {
561     tasm->Addu(sp, sp, -stack_slot_delta * kSystemPointerSize);
562     state->IncreaseSPDelta(stack_slot_delta);
563   }
564 }
565 
566 }  // namespace
567 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_slot_offset)568 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
569                                               int first_unused_slot_offset) {
570   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
571                                 first_unused_slot_offset, false);
572 }
573 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_slot_offset)574 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
575                                              int first_unused_slot_offset) {
576   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
577                                 first_unused_slot_offset);
578 }
579 
580 // Check that {kJavaScriptCallCodeStartRegister} is correct.
AssembleCodeStartRegisterCheck()581 void CodeGenerator::AssembleCodeStartRegisterCheck() {
582   __ ComputeCodeStartAddress(kScratchReg);
583   __ Assert(eq, AbortReason::kWrongFunctionCodeStart,
584             kJavaScriptCallCodeStartRegister, Operand(kScratchReg));
585 }
586 
587 // Check if the code object is marked for deoptimization. If it is, then it
588 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
589 // to:
590 //    1. read from memory the word that contains that bit, which can be found in
591 //       the flags in the referenced {CodeDataContainer} object;
592 //    2. test kMarkedForDeoptimizationBit in those flags; and
593 //    3. if it is not zero then it jumps to the builtin.
BailoutIfDeoptimized()594 void CodeGenerator::BailoutIfDeoptimized() {
595   int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
596   __ lw(kScratchReg, MemOperand(kJavaScriptCallCodeStartRegister, offset));
597   __ lw(kScratchReg,
598         FieldMemOperand(kScratchReg,
599                         CodeDataContainer::kKindSpecificFlagsOffset));
600   __ And(kScratchReg, kScratchReg,
601          Operand(1 << Code::kMarkedForDeoptimizationBit));
602   __ Jump(BUILTIN_CODE(isolate(), CompileLazyDeoptimizedCode),
603           RelocInfo::CODE_TARGET, ne, kScratchReg, Operand(zero_reg));
604 }
605 
606 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)607 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
608     Instruction* instr) {
609   MipsOperandConverter i(this, instr);
610   InstructionCode opcode = instr->opcode();
611   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
612   switch (arch_opcode) {
613     case kArchCallCodeObject: {
614       if (instr->InputAt(0)->IsImmediate()) {
615         __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
616       } else {
617         Register reg = i.InputRegister(0);
618         DCHECK_IMPLIES(
619             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
620             reg == kJavaScriptCallCodeStartRegister);
621         __ Call(reg, reg, Code::kHeaderSize - kHeapObjectTag);
622       }
623       RecordCallPosition(instr);
624       frame_access_state()->ClearSPDelta();
625       break;
626     }
627     case kArchCallBuiltinPointer: {
628       DCHECK(!instr->InputAt(0)->IsImmediate());
629       Register builtin_index = i.InputRegister(0);
630       __ CallBuiltinByIndex(builtin_index);
631       RecordCallPosition(instr);
632       frame_access_state()->ClearSPDelta();
633       break;
634     }
635 #if V8_ENABLE_WEBASSEMBLY
636     case kArchCallWasmFunction: {
637       if (instr->InputAt(0)->IsImmediate()) {
638         Constant constant = i.ToConstant(instr->InputAt(0));
639         Address wasm_code = static_cast<Address>(constant.ToInt32());
640         __ Call(wasm_code, constant.rmode());
641       } else {
642         __ Call(i.InputRegister(0));
643       }
644       RecordCallPosition(instr);
645       frame_access_state()->ClearSPDelta();
646       break;
647     }
648     case kArchTailCallWasm: {
649       if (instr->InputAt(0)->IsImmediate()) {
650         Constant constant = i.ToConstant(instr->InputAt(0));
651         Address wasm_code = static_cast<Address>(constant.ToInt32());
652         __ Jump(wasm_code, constant.rmode());
653       } else {
654         __ Jump(i.InputRegister(0));
655       }
656       frame_access_state()->ClearSPDelta();
657       frame_access_state()->SetFrameAccessToDefault();
658       break;
659     }
660 #endif  // V8_ENABLE_WEBASSEMBLY
661     case kArchTailCallCodeObject: {
662       if (instr->InputAt(0)->IsImmediate()) {
663         __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
664       } else {
665         Register reg = i.InputRegister(0);
666         DCHECK_IMPLIES(
667             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
668             reg == kJavaScriptCallCodeStartRegister);
669         __ Addu(reg, reg, Code::kHeaderSize - kHeapObjectTag);
670         __ Jump(reg);
671       }
672       frame_access_state()->ClearSPDelta();
673       frame_access_state()->SetFrameAccessToDefault();
674       break;
675     }
676     case kArchTailCallAddress: {
677       CHECK(!instr->InputAt(0)->IsImmediate());
678       Register reg = i.InputRegister(0);
679       DCHECK_IMPLIES(
680           instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
681           reg == kJavaScriptCallCodeStartRegister);
682       __ Jump(reg);
683       frame_access_state()->ClearSPDelta();
684       frame_access_state()->SetFrameAccessToDefault();
685       break;
686     }
687     case kArchCallJSFunction: {
688       Register func = i.InputRegister(0);
689       if (FLAG_debug_code) {
690         // Check the function's context matches the context argument.
691         __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
692         __ Assert(eq, AbortReason::kWrongFunctionContext, cp,
693                   Operand(kScratchReg));
694       }
695       static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch");
696       __ lw(a2, FieldMemOperand(func, JSFunction::kCodeOffset));
697       __ Addu(a2, a2, Code::kHeaderSize - kHeapObjectTag);
698       __ Call(a2);
699       RecordCallPosition(instr);
700       frame_access_state()->ClearSPDelta();
701       frame_access_state()->SetFrameAccessToDefault();
702       break;
703     }
704     case kArchPrepareCallCFunction: {
705       int const num_parameters = MiscField::decode(instr->opcode());
706       __ PrepareCallCFunction(num_parameters, kScratchReg);
707       // Frame alignment requires using FP-relative frame addressing.
708       frame_access_state()->SetFrameAccessToFP();
709       break;
710     }
711     case kArchSaveCallerRegisters: {
712       fp_mode_ =
713           static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
714       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
715              fp_mode_ == SaveFPRegsMode::kSave);
716       // kReturnRegister0 should have been saved before entering the stub.
717       int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
718       DCHECK(IsAligned(bytes, kSystemPointerSize));
719       DCHECK_EQ(0, frame_access_state()->sp_delta());
720       frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
721       DCHECK(!caller_registers_saved_);
722       caller_registers_saved_ = true;
723       break;
724     }
725     case kArchRestoreCallerRegisters: {
726       DCHECK(fp_mode_ ==
727              static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
728       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
729              fp_mode_ == SaveFPRegsMode::kSave);
730       // Don't overwrite the returned value.
731       int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
732       frame_access_state()->IncreaseSPDelta(-(bytes / kSystemPointerSize));
733       DCHECK_EQ(0, frame_access_state()->sp_delta());
734       DCHECK(caller_registers_saved_);
735       caller_registers_saved_ = false;
736       break;
737     }
738     case kArchPrepareTailCall:
739       AssemblePrepareTailCall();
740       break;
741     case kArchCallCFunction: {
742       int const num_parameters = MiscField::decode(instr->opcode());
743 #if V8_ENABLE_WEBASSEMBLY
744       Label start_call;
745       bool isWasmCapiFunction =
746           linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
747       // from start_call to return address.
748       int offset = __ root_array_available() ? 64 : 88;
749 #endif  // V8_ENABLE_WEBASSEMBLY
750 #if V8_HOST_ARCH_MIPS
751       if (FLAG_debug_code) {
752         offset += 16;
753       }
754 #endif
755 
756 #if V8_ENABLE_WEBASSEMBLY
757       if (isWasmCapiFunction) {
758         // Put the return address in a stack slot.
759         __ mov(kScratchReg, ra);
760         __ bind(&start_call);
761         __ nal();
762         __ nop();
763         __ Addu(ra, ra, offset - 8);  // 8 = nop + nal
764         __ sw(ra, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
765         __ mov(ra, kScratchReg);
766       }
767 #endif  // V8_ENABLE_WEBASSEMBLY
768 
769       if (instr->InputAt(0)->IsImmediate()) {
770         ExternalReference ref = i.InputExternalReference(0);
771         __ CallCFunction(ref, num_parameters);
772       } else {
773         Register func = i.InputRegister(0);
774         __ CallCFunction(func, num_parameters);
775       }
776 
777 #if V8_ENABLE_WEBASSEMBLY
778       if (isWasmCapiFunction) {
779         CHECK_EQ(offset, __ SizeOfCodeGeneratedSince(&start_call));
780         RecordSafepoint(instr->reference_map());
781       }
782 #endif  // V8_ENABLE_WEBASSEMBLY
783 
784       frame_access_state()->SetFrameAccessToDefault();
785       // Ideally, we should decrement SP delta to match the change of stack
786       // pointer in CallCFunction. However, for certain architectures (e.g.
787       // ARM), there may be more strict alignment requirement, causing old SP
788       // to be saved on the stack. In those cases, we can not calculate the SP
789       // delta statically.
790       frame_access_state()->ClearSPDelta();
791       if (caller_registers_saved_) {
792         // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
793         // Here, we assume the sequence to be:
794         //   kArchSaveCallerRegisters;
795         //   kArchCallCFunction;
796         //   kArchRestoreCallerRegisters;
797         int bytes =
798             __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
799         frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
800       }
801       break;
802     }
803     case kArchJmp:
804       AssembleArchJump(i.InputRpo(0));
805       break;
806     case kArchBinarySearchSwitch:
807       AssembleArchBinarySearchSwitch(instr);
808       break;
809     case kArchTableSwitch:
810       AssembleArchTableSwitch(instr);
811       break;
812     case kArchAbortCSADcheck:
813       DCHECK(i.InputRegister(0) == a0);
814       {
815         // We don't actually want to generate a pile of code for this, so just
816         // claim there is a stack frame, without generating one.
817         FrameScope scope(tasm(), StackFrame::NO_FRAME_TYPE);
818         __ Call(isolate()->builtins()->code_handle(Builtin::kAbortCSADcheck),
819                 RelocInfo::CODE_TARGET);
820       }
821       __ stop();
822       break;
823     case kArchDebugBreak:
824       __ DebugBreak();
825       break;
826     case kArchComment:
827       __ RecordComment(reinterpret_cast<const char*>(i.InputInt32(0)));
828       break;
829     case kArchNop:
830     case kArchThrowTerminator:
831       // don't emit code for nops.
832       break;
833     case kArchDeoptimize: {
834       DeoptimizationExit* exit =
835           BuildTranslation(instr, -1, 0, 0, OutputFrameStateCombine::Ignore());
836       __ Branch(exit->label());
837       break;
838     }
839     case kArchRet:
840       AssembleReturn(instr->InputAt(0));
841       break;
842     case kArchStackPointerGreaterThan: {
843       Register lhs_register = sp;
844       uint32_t offset;
845       if (ShouldApplyOffsetToStackCheck(instr, &offset)) {
846         lhs_register = i.TempRegister(1);
847         __ Subu(lhs_register, sp, offset);
848       }
849       __ Sltu(i.TempRegister(0), i.InputRegister(0), lhs_register);
850       break;
851     }
852     case kArchStackCheckOffset:
853       __ Move(i.OutputRegister(), Smi::FromInt(GetStackCheckOffset()));
854       break;
855     case kArchFramePointer:
856       __ mov(i.OutputRegister(), fp);
857       break;
858     case kArchParentFramePointer:
859       if (frame_access_state()->has_frame()) {
860         __ lw(i.OutputRegister(), MemOperand(fp, 0));
861       } else {
862         __ mov(i.OutputRegister(), fp);
863       }
864       break;
865     case kArchTruncateDoubleToI:
866       __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
867                            i.InputDoubleRegister(0), DetermineStubCallMode());
868       break;
869     case kArchStoreWithWriteBarrier:
870     case kArchAtomicStoreWithWriteBarrier: {
871       RecordWriteMode mode =
872           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
873       Register object = i.InputRegister(0);
874       Register index = i.InputRegister(1);
875       Register value = i.InputRegister(2);
876       Register scratch0 = i.TempRegister(0);
877       Register scratch1 = i.TempRegister(1);
878       auto ool = zone()->New<OutOfLineRecordWrite>(this, object, index, value,
879                                                    scratch0, scratch1, mode,
880                                                    DetermineStubCallMode());
881       __ Addu(kScratchReg, object, index);
882       if (arch_opcode == kArchStoreWithWriteBarrier) {
883         __ sw(value, MemOperand(kScratchReg));
884       } else {
885         DCHECK_EQ(kArchAtomicStoreWithWriteBarrier, arch_opcode);
886         __ sync();
887         __ sw(value, MemOperand(kScratchReg));
888         __ sync();
889       }
890       if (mode > RecordWriteMode::kValueIsPointer) {
891         __ JumpIfSmi(value, ool->exit());
892       }
893       __ CheckPageFlag(object, scratch0,
894                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
895                        ool->entry());
896       __ bind(ool->exit());
897       break;
898     }
899     case kArchStackSlot: {
900       FrameOffset offset =
901           frame_access_state()->GetFrameOffset(i.InputInt32(0));
902       Register base_reg = offset.from_stack_pointer() ? sp : fp;
903       __ Addu(i.OutputRegister(), base_reg, Operand(offset.offset()));
904       if (FLAG_debug_code > 0) {
905         // Verify that the output_register is properly aligned
906         __ And(kScratchReg, i.OutputRegister(),
907                Operand(kSystemPointerSize - 1));
908         __ Assert(eq, AbortReason::kAllocationIsNotDoubleAligned, kScratchReg,
909                   Operand(zero_reg));
910       }
911       break;
912     }
913     case kIeee754Float64Acos:
914       ASSEMBLE_IEEE754_UNOP(acos);
915       break;
916     case kIeee754Float64Acosh:
917       ASSEMBLE_IEEE754_UNOP(acosh);
918       break;
919     case kIeee754Float64Asin:
920       ASSEMBLE_IEEE754_UNOP(asin);
921       break;
922     case kIeee754Float64Asinh:
923       ASSEMBLE_IEEE754_UNOP(asinh);
924       break;
925     case kIeee754Float64Atan:
926       ASSEMBLE_IEEE754_UNOP(atan);
927       break;
928     case kIeee754Float64Atanh:
929       ASSEMBLE_IEEE754_UNOP(atanh);
930       break;
931     case kIeee754Float64Atan2:
932       ASSEMBLE_IEEE754_BINOP(atan2);
933       break;
934     case kIeee754Float64Cos:
935       ASSEMBLE_IEEE754_UNOP(cos);
936       break;
937     case kIeee754Float64Cosh:
938       ASSEMBLE_IEEE754_UNOP(cosh);
939       break;
940     case kIeee754Float64Cbrt:
941       ASSEMBLE_IEEE754_UNOP(cbrt);
942       break;
943     case kIeee754Float64Exp:
944       ASSEMBLE_IEEE754_UNOP(exp);
945       break;
946     case kIeee754Float64Expm1:
947       ASSEMBLE_IEEE754_UNOP(expm1);
948       break;
949     case kIeee754Float64Log:
950       ASSEMBLE_IEEE754_UNOP(log);
951       break;
952     case kIeee754Float64Log1p:
953       ASSEMBLE_IEEE754_UNOP(log1p);
954       break;
955     case kIeee754Float64Log10:
956       ASSEMBLE_IEEE754_UNOP(log10);
957       break;
958     case kIeee754Float64Log2:
959       ASSEMBLE_IEEE754_UNOP(log2);
960       break;
961     case kIeee754Float64Pow:
962       ASSEMBLE_IEEE754_BINOP(pow);
963       break;
964     case kIeee754Float64Sin:
965       ASSEMBLE_IEEE754_UNOP(sin);
966       break;
967     case kIeee754Float64Sinh:
968       ASSEMBLE_IEEE754_UNOP(sinh);
969       break;
970     case kIeee754Float64Tan:
971       ASSEMBLE_IEEE754_UNOP(tan);
972       break;
973     case kIeee754Float64Tanh:
974       ASSEMBLE_IEEE754_UNOP(tanh);
975       break;
976     case kMipsAdd:
977       __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
978       break;
979     case kMipsAddOvf:
980       __ AddOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
981                      kScratchReg);
982       break;
983     case kMipsSub:
984       __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
985       break;
986     case kMipsSubOvf:
987       __ SubOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
988                      kScratchReg);
989       break;
990     case kMipsMul:
991       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
992       break;
993     case kMipsMulOvf:
994       __ MulOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
995                      kScratchReg);
996       break;
997     case kMipsMulHigh:
998       __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
999       break;
1000     case kMipsMulHighU:
1001       __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1002       break;
1003     case kMipsDiv:
1004       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1005       if (IsMipsArchVariant(kMips32r6)) {
1006         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1007       } else {
1008         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1009       }
1010       break;
1011     case kMipsDivU:
1012       __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1013       if (IsMipsArchVariant(kMips32r6)) {
1014         __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1015       } else {
1016         __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
1017       }
1018       break;
1019     case kMipsMod:
1020       __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1021       break;
1022     case kMipsModU:
1023       __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1024       break;
1025     case kMipsAnd:
1026       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1027       break;
1028     case kMipsOr:
1029       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1030       break;
1031     case kMipsNor:
1032       if (instr->InputAt(1)->IsRegister()) {
1033         __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1034       } else {
1035         DCHECK_EQ(0, i.InputOperand(1).immediate());
1036         __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1037       }
1038       break;
1039     case kMipsXor:
1040       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1041       break;
1042     case kMipsClz:
1043       __ Clz(i.OutputRegister(), i.InputRegister(0));
1044       break;
1045     case kMipsCtz: {
1046       Register src = i.InputRegister(0);
1047       Register dst = i.OutputRegister();
1048       __ Ctz(dst, src);
1049     } break;
1050     case kMipsPopcnt: {
1051       Register src = i.InputRegister(0);
1052       Register dst = i.OutputRegister();
1053       __ Popcnt(dst, src);
1054     } break;
1055     case kMipsShl:
1056       if (instr->InputAt(1)->IsRegister()) {
1057         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1058       } else {
1059         int32_t imm = i.InputOperand(1).immediate();
1060         __ sll(i.OutputRegister(), i.InputRegister(0), imm);
1061       }
1062       break;
1063     case kMipsShr:
1064       if (instr->InputAt(1)->IsRegister()) {
1065         __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1066       } else {
1067         int32_t imm = i.InputOperand(1).immediate();
1068         __ srl(i.OutputRegister(), i.InputRegister(0), imm);
1069       }
1070       break;
1071     case kMipsSar:
1072       if (instr->InputAt(1)->IsRegister()) {
1073         __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1074       } else {
1075         int32_t imm = i.InputOperand(1).immediate();
1076         __ sra(i.OutputRegister(), i.InputRegister(0), imm);
1077       }
1078       break;
1079     case kMipsShlPair: {
1080       Register second_output =
1081           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1082       if (instr->InputAt(2)->IsRegister()) {
1083         __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1084                    i.InputRegister(1), i.InputRegister(2), kScratchReg,
1085                    kScratchReg2);
1086       } else {
1087         uint32_t imm = i.InputOperand(2).immediate();
1088         __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1089                    i.InputRegister(1), imm, kScratchReg);
1090       }
1091     } break;
1092     case kMipsShrPair: {
1093       Register second_output =
1094           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1095       if (instr->InputAt(2)->IsRegister()) {
1096         __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1097                    i.InputRegister(1), i.InputRegister(2), kScratchReg,
1098                    kScratchReg2);
1099       } else {
1100         uint32_t imm = i.InputOperand(2).immediate();
1101         __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1102                    i.InputRegister(1), imm, kScratchReg);
1103       }
1104     } break;
1105     case kMipsSarPair: {
1106       Register second_output =
1107           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1108       if (instr->InputAt(2)->IsRegister()) {
1109         __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1110                    i.InputRegister(1), i.InputRegister(2), kScratchReg,
1111                    kScratchReg2);
1112       } else {
1113         uint32_t imm = i.InputOperand(2).immediate();
1114         __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1115                    i.InputRegister(1), imm, kScratchReg);
1116       }
1117     } break;
1118     case kMipsExt:
1119       __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1120              i.InputInt8(2));
1121       break;
1122     case kMipsIns:
1123       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1124         __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1125       } else {
1126         __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1127                i.InputInt8(2));
1128       }
1129       break;
1130     case kMipsRor:
1131       __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1132       break;
1133     case kMipsTst:
1134       __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1135       break;
1136     case kMipsCmp:
1137       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1138       break;
1139     case kMipsMov:
1140       // TODO(plind): Should we combine mov/li like this, or use separate instr?
1141       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1142       if (HasRegisterInput(instr, 0)) {
1143         __ mov(i.OutputRegister(), i.InputRegister(0));
1144       } else {
1145         __ li(i.OutputRegister(), i.InputOperand(0));
1146       }
1147       break;
1148     case kMipsLsa:
1149       DCHECK(instr->InputAt(2)->IsImmediate());
1150       __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1151              i.InputInt8(2));
1152       break;
1153     case kMipsCmpS: {
1154       FPURegister left = i.InputOrZeroSingleRegister(0);
1155       FPURegister right = i.InputOrZeroSingleRegister(1);
1156       bool predicate;
1157       FPUCondition cc =
1158           FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1159 
1160       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1161           !__ IsDoubleZeroRegSet()) {
1162         __ Move(kDoubleRegZero, 0.0);
1163       }
1164 
1165       __ CompareF32(cc, left, right);
1166     } break;
1167     case kMipsAddS:
1168       // TODO(plind): add special case: combine mult & add.
1169       __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1170                i.InputDoubleRegister(1));
1171       break;
1172     case kMipsSubS:
1173       __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1174                i.InputDoubleRegister(1));
1175       break;
1176     case kMipsMulS:
1177       // TODO(plind): add special case: right op is -1.0, see arm port.
1178       __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1179                i.InputDoubleRegister(1));
1180       break;
1181     case kMipsDivS:
1182       __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1183                i.InputDoubleRegister(1));
1184       break;
1185     case kMipsAbsS:
1186       if (IsMipsArchVariant(kMips32r6)) {
1187         __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1188       } else {
1189         __ mfc1(kScratchReg, i.InputSingleRegister(0));
1190         __ Ins(kScratchReg, zero_reg, 31, 1);
1191         __ mtc1(kScratchReg, i.OutputSingleRegister());
1192       }
1193       break;
1194     case kMipsSqrtS: {
1195       __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1196       break;
1197     }
1198     case kMipsMaxS:
1199       __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1200                i.InputDoubleRegister(1));
1201       break;
1202     case kMipsMinS:
1203       __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1204                i.InputDoubleRegister(1));
1205       break;
1206     case kMipsCmpD: {
1207       FPURegister left = i.InputOrZeroDoubleRegister(0);
1208       FPURegister right = i.InputOrZeroDoubleRegister(1);
1209       bool predicate;
1210       FPUCondition cc =
1211           FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1212       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1213           !__ IsDoubleZeroRegSet()) {
1214         __ Move(kDoubleRegZero, 0.0);
1215       }
1216       __ CompareF64(cc, left, right);
1217     } break;
1218     case kMipsAddPair:
1219       __ AddPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1220                  i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1221                  kScratchReg, kScratchReg2);
1222       break;
1223     case kMipsSubPair:
1224       __ SubPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1225                  i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1226                  kScratchReg, kScratchReg2);
1227       break;
1228     case kMipsMulPair: {
1229       __ MulPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1230                  i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1231                  kScratchReg, kScratchReg2);
1232     } break;
1233     case kMipsAddD:
1234       // TODO(plind): add special case: combine mult & add.
1235       __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1236                i.InputDoubleRegister(1));
1237       break;
1238     case kMipsSubD:
1239       __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1240                i.InputDoubleRegister(1));
1241       break;
1242     case kMipsMaddS:
1243       __ Madd_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
1244                 i.InputFloatRegister(1), i.InputFloatRegister(2),
1245                 kScratchDoubleReg);
1246       break;
1247     case kMipsMaddD:
1248       __ Madd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1249                 i.InputDoubleRegister(1), i.InputDoubleRegister(2),
1250                 kScratchDoubleReg);
1251       break;
1252     case kMipsMsubS:
1253       __ Msub_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
1254                 i.InputFloatRegister(1), i.InputFloatRegister(2),
1255                 kScratchDoubleReg);
1256       break;
1257     case kMipsMsubD:
1258       __ Msub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1259                 i.InputDoubleRegister(1), i.InputDoubleRegister(2),
1260                 kScratchDoubleReg);
1261       break;
1262     case kMipsMulD:
1263       // TODO(plind): add special case: right op is -1.0, see arm port.
1264       __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1265                i.InputDoubleRegister(1));
1266       break;
1267     case kMipsDivD:
1268       __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1269                i.InputDoubleRegister(1));
1270       break;
1271     case kMipsModD: {
1272       // TODO(bmeurer): We should really get rid of this special instruction,
1273       // and generate a CallAddress instruction instead.
1274       FrameScope scope(tasm(), StackFrame::MANUAL);
1275       __ PrepareCallCFunction(0, 2, kScratchReg);
1276       __ MovToFloatParameters(i.InputDoubleRegister(0),
1277                               i.InputDoubleRegister(1));
1278       __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1279       // Move the result in the double result register.
1280       __ MovFromFloatResult(i.OutputDoubleRegister());
1281       break;
1282     }
1283     case kMipsAbsD: {
1284       FPURegister src = i.InputDoubleRegister(0);
1285       FPURegister dst = i.OutputDoubleRegister();
1286       if (IsMipsArchVariant(kMips32r6)) {
1287         __ abs_d(dst, src);
1288       } else {
1289         __ Move(dst, src);
1290         __ mfhc1(kScratchReg, src);
1291         __ Ins(kScratchReg, zero_reg, 31, 1);
1292         __ mthc1(kScratchReg, dst);
1293       }
1294       break;
1295     }
1296     case kMipsNegS:
1297       __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1298       break;
1299     case kMipsNegD:
1300       __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1301       break;
1302     case kMipsSqrtD: {
1303       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1304       break;
1305     }
1306     case kMipsMaxD:
1307       __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1308                i.InputDoubleRegister(1));
1309       break;
1310     case kMipsMinD:
1311       __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1312                i.InputDoubleRegister(1));
1313       break;
1314     case kMipsFloat64RoundDown: {
1315       __ Floor_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1316       break;
1317     }
1318     case kMipsFloat32RoundDown: {
1319       __ Floor_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1320       break;
1321     }
1322     case kMipsFloat64RoundTruncate: {
1323       __ Trunc_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1324       break;
1325     }
1326     case kMipsFloat32RoundTruncate: {
1327       __ Trunc_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1328       break;
1329     }
1330     case kMipsFloat64RoundUp: {
1331       __ Ceil_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1332       break;
1333     }
1334     case kMipsFloat32RoundUp: {
1335       __ Ceil_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1336       break;
1337     }
1338     case kMipsFloat64RoundTiesEven: {
1339       __ Round_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1340       break;
1341     }
1342     case kMipsFloat32RoundTiesEven: {
1343       __ Round_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1344       break;
1345     }
1346     case kMipsFloat32Max: {
1347       FPURegister dst = i.OutputSingleRegister();
1348       FPURegister src1 = i.InputSingleRegister(0);
1349       FPURegister src2 = i.InputSingleRegister(1);
1350       auto ool = zone()->New<OutOfLineFloat32Max>(this, dst, src1, src2);
1351       __ Float32Max(dst, src1, src2, ool->entry());
1352       __ bind(ool->exit());
1353       break;
1354     }
1355     case kMipsFloat64Max: {
1356       DoubleRegister dst = i.OutputDoubleRegister();
1357       DoubleRegister src1 = i.InputDoubleRegister(0);
1358       DoubleRegister src2 = i.InputDoubleRegister(1);
1359       auto ool = zone()->New<OutOfLineFloat64Max>(this, dst, src1, src2);
1360       __ Float64Max(dst, src1, src2, ool->entry());
1361       __ bind(ool->exit());
1362       break;
1363     }
1364     case kMipsFloat32Min: {
1365       FPURegister dst = i.OutputSingleRegister();
1366       FPURegister src1 = i.InputSingleRegister(0);
1367       FPURegister src2 = i.InputSingleRegister(1);
1368       auto ool = zone()->New<OutOfLineFloat32Min>(this, dst, src1, src2);
1369       __ Float32Min(dst, src1, src2, ool->entry());
1370       __ bind(ool->exit());
1371       break;
1372     }
1373     case kMipsFloat64Min: {
1374       DoubleRegister dst = i.OutputDoubleRegister();
1375       DoubleRegister src1 = i.InputDoubleRegister(0);
1376       DoubleRegister src2 = i.InputDoubleRegister(1);
1377       auto ool = zone()->New<OutOfLineFloat64Min>(this, dst, src1, src2);
1378       __ Float64Min(dst, src1, src2, ool->entry());
1379       __ bind(ool->exit());
1380       break;
1381     }
1382     case kMipsCvtSD: {
1383       __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1384       break;
1385     }
1386     case kMipsCvtDS: {
1387       __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1388       break;
1389     }
1390     case kMipsCvtDW: {
1391       FPURegister scratch = kScratchDoubleReg;
1392       __ mtc1(i.InputRegister(0), scratch);
1393       __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1394       break;
1395     }
1396     case kMipsCvtSW: {
1397       FPURegister scratch = kScratchDoubleReg;
1398       __ mtc1(i.InputRegister(0), scratch);
1399       __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1400       break;
1401     }
1402     case kMipsCvtSUw: {
1403       FPURegister scratch = kScratchDoubleReg;
1404       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1405       __ cvt_s_d(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1406       break;
1407     }
1408     case kMipsCvtDUw: {
1409       FPURegister scratch = kScratchDoubleReg;
1410       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1411       break;
1412     }
1413     case kMipsFloorWD: {
1414       FPURegister scratch = kScratchDoubleReg;
1415       __ Floor_w_d(scratch, i.InputDoubleRegister(0));
1416       __ mfc1(i.OutputRegister(), scratch);
1417       break;
1418     }
1419     case kMipsCeilWD: {
1420       FPURegister scratch = kScratchDoubleReg;
1421       __ Ceil_w_d(scratch, i.InputDoubleRegister(0));
1422       __ mfc1(i.OutputRegister(), scratch);
1423       break;
1424     }
1425     case kMipsRoundWD: {
1426       FPURegister scratch = kScratchDoubleReg;
1427       __ Round_w_d(scratch, i.InputDoubleRegister(0));
1428       __ mfc1(i.OutputRegister(), scratch);
1429       break;
1430     }
1431     case kMipsTruncWD: {
1432       FPURegister scratch = kScratchDoubleReg;
1433       // Other arches use round to zero here, so we follow.
1434       __ Trunc_w_d(scratch, i.InputDoubleRegister(0));
1435       __ mfc1(i.OutputRegister(), scratch);
1436       break;
1437     }
1438     case kMipsFloorWS: {
1439       FPURegister scratch = kScratchDoubleReg;
1440       __ floor_w_s(scratch, i.InputDoubleRegister(0));
1441       __ mfc1(i.OutputRegister(), scratch);
1442       break;
1443     }
1444     case kMipsCeilWS: {
1445       FPURegister scratch = kScratchDoubleReg;
1446       __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1447       __ mfc1(i.OutputRegister(), scratch);
1448       break;
1449     }
1450     case kMipsRoundWS: {
1451       FPURegister scratch = kScratchDoubleReg;
1452       __ round_w_s(scratch, i.InputDoubleRegister(0));
1453       __ mfc1(i.OutputRegister(), scratch);
1454       break;
1455     }
1456     case kMipsTruncWS: {
1457       FPURegister scratch = kScratchDoubleReg;
1458       __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1459       __ mfc1(i.OutputRegister(), scratch);
1460       // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1461       // because INT32_MIN allows easier out-of-bounds detection.
1462       bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1463       if (set_overflow_to_min_i32) {
1464         __ Addu(kScratchReg, i.OutputRegister(), 1);
1465         __ Slt(kScratchReg2, kScratchReg, i.OutputRegister());
1466         __ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
1467       }
1468       break;
1469     }
1470     case kMipsTruncUwD: {
1471       FPURegister scratch = kScratchDoubleReg;
1472       __ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1473       break;
1474     }
1475     case kMipsTruncUwS: {
1476       FPURegister scratch = kScratchDoubleReg;
1477       __ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1478       // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1479       // because 0 allows easier out-of-bounds detection.
1480       bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1481       if (set_overflow_to_min_i32) {
1482         __ Addu(kScratchReg, i.OutputRegister(), 1);
1483         __ Movz(i.OutputRegister(), zero_reg, kScratchReg);
1484       }
1485       break;
1486     }
1487     case kMipsFloat64ExtractLowWord32:
1488       __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1489       break;
1490     case kMipsFloat64ExtractHighWord32:
1491       __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1492       break;
1493     case kMipsFloat64InsertLowWord32:
1494       __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1495       break;
1496     case kMipsFloat64InsertHighWord32:
1497       __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1498       break;
1499     case kMipsFloat64SilenceNaN:
1500       __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1501       break;
1502 
1503     // ... more basic instructions ...
1504     case kMipsSeb:
1505       __ Seb(i.OutputRegister(), i.InputRegister(0));
1506       break;
1507     case kMipsSeh:
1508       __ Seh(i.OutputRegister(), i.InputRegister(0));
1509       break;
1510     case kMipsLbu:
1511       __ lbu(i.OutputRegister(), i.MemoryOperand());
1512       break;
1513     case kMipsLb:
1514       __ lb(i.OutputRegister(), i.MemoryOperand());
1515       break;
1516     case kMipsSb:
1517       __ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
1518       break;
1519     case kMipsLhu:
1520       __ lhu(i.OutputRegister(), i.MemoryOperand());
1521       break;
1522     case kMipsUlhu:
1523       __ Ulhu(i.OutputRegister(), i.MemoryOperand());
1524       break;
1525     case kMipsLh:
1526       __ lh(i.OutputRegister(), i.MemoryOperand());
1527       break;
1528     case kMipsUlh:
1529       __ Ulh(i.OutputRegister(), i.MemoryOperand());
1530       break;
1531     case kMipsSh:
1532       __ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
1533       break;
1534     case kMipsUsh:
1535       __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
1536       break;
1537     case kMipsLw:
1538       __ lw(i.OutputRegister(), i.MemoryOperand());
1539       break;
1540     case kMipsUlw:
1541       __ Ulw(i.OutputRegister(), i.MemoryOperand());
1542       break;
1543     case kMipsSw:
1544       __ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
1545       break;
1546     case kMipsUsw:
1547       __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
1548       break;
1549     case kMipsLwc1: {
1550       __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1551       break;
1552     }
1553     case kMipsUlwc1: {
1554       __ Ulwc1(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg);
1555       break;
1556     }
1557     case kMipsSwc1: {
1558       size_t index = 0;
1559       MemOperand operand = i.MemoryOperand(&index);
1560       FPURegister ft = i.InputOrZeroSingleRegister(index);
1561       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1562         __ Move(kDoubleRegZero, 0.0);
1563       }
1564       __ swc1(ft, operand);
1565       break;
1566     }
1567     case kMipsUswc1: {
1568       size_t index = 0;
1569       MemOperand operand = i.MemoryOperand(&index);
1570       FPURegister ft = i.InputOrZeroSingleRegister(index);
1571       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1572         __ Move(kDoubleRegZero, 0.0);
1573       }
1574       __ Uswc1(ft, operand, kScratchReg);
1575       break;
1576     }
1577     case kMipsLdc1:
1578       __ Ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1579       break;
1580     case kMipsUldc1:
1581       __ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
1582       break;
1583     case kMipsSdc1: {
1584       FPURegister ft = i.InputOrZeroDoubleRegister(2);
1585       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1586         __ Move(kDoubleRegZero, 0.0);
1587       }
1588       __ Sdc1(ft, i.MemoryOperand());
1589       break;
1590     }
1591     case kMipsUsdc1: {
1592       FPURegister ft = i.InputOrZeroDoubleRegister(2);
1593       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1594         __ Move(kDoubleRegZero, 0.0);
1595       }
1596       __ Usdc1(ft, i.MemoryOperand(), kScratchReg);
1597       break;
1598     }
1599     case kMipsSync: {
1600       __ sync();
1601       break;
1602     }
1603     case kMipsPush:
1604       if (instr->InputAt(0)->IsFPRegister()) {
1605         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1606         switch (op->representation()) {
1607           case MachineRepresentation::kFloat32:
1608             __ swc1(i.InputFloatRegister(0), MemOperand(sp, -kFloatSize));
1609             __ Subu(sp, sp, Operand(kFloatSize));
1610             frame_access_state()->IncreaseSPDelta(kFloatSize /
1611                                                   kSystemPointerSize);
1612             break;
1613           case MachineRepresentation::kFloat64:
1614             __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1615             __ Subu(sp, sp, Operand(kDoubleSize));
1616             frame_access_state()->IncreaseSPDelta(kDoubleSize /
1617                                                   kSystemPointerSize);
1618             break;
1619           default: {
1620             UNREACHABLE();
1621           }
1622         }
1623       } else {
1624         __ Push(i.InputRegister(0));
1625         frame_access_state()->IncreaseSPDelta(1);
1626       }
1627       break;
1628     case kMipsPeek: {
1629       int reverse_slot = i.InputInt32(0);
1630       int offset =
1631           FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
1632       if (instr->OutputAt(0)->IsFPRegister()) {
1633         LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
1634         if (op->representation() == MachineRepresentation::kFloat64) {
1635           __ Ldc1(i.OutputDoubleRegister(), MemOperand(fp, offset));
1636         } else if (op->representation() == MachineRepresentation::kFloat32) {
1637           __ lwc1(i.OutputSingleRegister(0), MemOperand(fp, offset));
1638         } else {
1639           DCHECK_EQ(op->representation(), MachineRepresentation::kSimd128);
1640           __ ld_b(i.OutputSimd128Register(), MemOperand(fp, offset));
1641         }
1642       } else {
1643         __ lw(i.OutputRegister(0), MemOperand(fp, offset));
1644       }
1645       break;
1646     }
1647     case kMipsStackClaim: {
1648       __ Subu(sp, sp, Operand(i.InputInt32(0)));
1649       frame_access_state()->IncreaseSPDelta(i.InputInt32(0) /
1650                                             kSystemPointerSize);
1651       break;
1652     }
1653     case kMipsStoreToStackSlot: {
1654       if (instr->InputAt(0)->IsFPRegister()) {
1655         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1656         if (op->representation() == MachineRepresentation::kFloat64) {
1657           __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1658         } else if (op->representation() == MachineRepresentation::kFloat32) {
1659           __ swc1(i.InputSingleRegister(0), MemOperand(sp, i.InputInt32(1)));
1660         } else {
1661           DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1662           CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1663           __ st_b(i.InputSimd128Register(0), MemOperand(sp, i.InputInt32(1)));
1664         }
1665       } else {
1666         __ sw(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1667       }
1668       break;
1669     }
1670     case kMipsByteSwap32: {
1671       __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 4);
1672       break;
1673     }
1674     case kMipsS128Load8Splat: {
1675       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1676       __ lb(kScratchReg, i.MemoryOperand());
1677       __ fill_b(i.OutputSimd128Register(), kScratchReg);
1678       break;
1679     }
1680     case kMipsS128Load16Splat: {
1681       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1682       __ lh(kScratchReg, i.MemoryOperand());
1683       __ fill_h(i.OutputSimd128Register(), kScratchReg);
1684       break;
1685     }
1686     case kMipsS128Load32Splat: {
1687       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1688       __ Lw(kScratchReg, i.MemoryOperand());
1689       __ fill_w(i.OutputSimd128Register(), kScratchReg);
1690       break;
1691     }
1692     case kMipsS128Load64Splat: {
1693       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1694       Simd128Register dst = i.OutputSimd128Register();
1695       MemOperand memLow = i.MemoryOperand();
1696       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1697       __ Lw(kScratchReg, memLow);
1698       __ fill_w(dst, kScratchReg);
1699       __ Lw(kScratchReg, memHigh);
1700       __ fill_w(kSimd128ScratchReg, kScratchReg);
1701       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1702       break;
1703     }
1704     case kMipsS128Load8x8S: {
1705       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1706       Simd128Register dst = i.OutputSimd128Register();
1707       MemOperand memLow = i.MemoryOperand();
1708       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1709       __ Lw(kScratchReg, memLow);
1710       __ fill_w(dst, kScratchReg);
1711       __ Lw(kScratchReg, memHigh);
1712       __ fill_w(kSimd128ScratchReg, kScratchReg);
1713       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1714       __ clti_s_b(kSimd128ScratchReg, dst, 0);
1715       __ ilvr_b(dst, kSimd128ScratchReg, dst);
1716       break;
1717     }
1718     case kMipsS128Load8x8U: {
1719       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1720       Simd128Register dst = i.OutputSimd128Register();
1721       MemOperand memLow = i.MemoryOperand();
1722       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1723       __ Lw(kScratchReg, memLow);
1724       __ fill_w(dst, kScratchReg);
1725       __ Lw(kScratchReg, memHigh);
1726       __ fill_w(kSimd128ScratchReg, kScratchReg);
1727       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1728       __ ilvr_b(dst, kSimd128RegZero, dst);
1729       break;
1730     }
1731     case kMipsS128Load16x4S: {
1732       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1733       Simd128Register dst = i.OutputSimd128Register();
1734       MemOperand memLow = i.MemoryOperand();
1735       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1736       __ Lw(kScratchReg, memLow);
1737       __ fill_w(dst, kScratchReg);
1738       __ Lw(kScratchReg, memHigh);
1739       __ fill_w(kSimd128ScratchReg, kScratchReg);
1740       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1741       __ clti_s_h(kSimd128ScratchReg, dst, 0);
1742       __ ilvr_h(dst, kSimd128ScratchReg, dst);
1743       break;
1744     }
1745     case kMipsS128Load16x4U: {
1746       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1747       Simd128Register dst = i.OutputSimd128Register();
1748       MemOperand memLow = i.MemoryOperand();
1749       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1750       __ Lw(kScratchReg, memLow);
1751       __ fill_w(dst, kScratchReg);
1752       __ Lw(kScratchReg, memHigh);
1753       __ fill_w(kSimd128ScratchReg, kScratchReg);
1754       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1755       __ ilvr_h(dst, kSimd128RegZero, dst);
1756       break;
1757     }
1758     case kMipsS128Load32x2S: {
1759       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1760       Simd128Register dst = i.OutputSimd128Register();
1761       MemOperand memLow = i.MemoryOperand();
1762       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1763       __ Lw(kScratchReg, memLow);
1764       __ fill_w(dst, kScratchReg);
1765       __ Lw(kScratchReg, memHigh);
1766       __ fill_w(kSimd128ScratchReg, kScratchReg);
1767       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1768       __ clti_s_w(kSimd128ScratchReg, dst, 0);
1769       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1770       break;
1771     }
1772     case kMipsS128Load32x2U: {
1773       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1774       Simd128Register dst = i.OutputSimd128Register();
1775       MemOperand memLow = i.MemoryOperand();
1776       MemOperand memHigh = MemOperand(memLow.rm(), memLow.offset() + 4);
1777       __ Lw(kScratchReg, memLow);
1778       __ fill_w(dst, kScratchReg);
1779       __ Lw(kScratchReg, memHigh);
1780       __ fill_w(kSimd128ScratchReg, kScratchReg);
1781       __ ilvr_w(dst, kSimd128ScratchReg, dst);
1782       __ ilvr_w(dst, kSimd128RegZero, dst);
1783       break;
1784     }
1785     case kAtomicLoadInt8:
1786       ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
1787       break;
1788     case kAtomicLoadUint8:
1789       ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
1790       break;
1791     case kAtomicLoadInt16:
1792       ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
1793       break;
1794     case kAtomicLoadUint16:
1795       ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
1796       break;
1797     case kAtomicLoadWord32:
1798       ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
1799       break;
1800     case kAtomicStoreWord8:
1801       ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
1802       break;
1803     case kAtomicStoreWord16:
1804       ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
1805       break;
1806     case kAtomicStoreWord32:
1807       ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
1808       break;
1809     case kAtomicExchangeInt8:
1810       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 8);
1811       break;
1812     case kAtomicExchangeUint8:
1813       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 8);
1814       break;
1815     case kAtomicExchangeInt16:
1816       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 16);
1817       break;
1818     case kAtomicExchangeUint16:
1819       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 16);
1820       break;
1821     case kAtomicExchangeWord32:
1822       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER();
1823       break;
1824     case kAtomicCompareExchangeInt8:
1825       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 8);
1826       break;
1827     case kAtomicCompareExchangeUint8:
1828       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 8);
1829       break;
1830     case kAtomicCompareExchangeInt16:
1831       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 16);
1832       break;
1833     case kAtomicCompareExchangeUint16:
1834       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 16);
1835       break;
1836     case kAtomicCompareExchangeWord32:
1837       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER();
1838       break;
1839 #define ATOMIC_BINOP_CASE(op, inst)             \
1840   case kAtomic##op##Int8:                       \
1841     ASSEMBLE_ATOMIC_BINOP_EXT(true, 8, inst);   \
1842     break;                                      \
1843   case kAtomic##op##Uint8:                      \
1844     ASSEMBLE_ATOMIC_BINOP_EXT(false, 8, inst);  \
1845     break;                                      \
1846   case kAtomic##op##Int16:                      \
1847     ASSEMBLE_ATOMIC_BINOP_EXT(true, 16, inst);  \
1848     break;                                      \
1849   case kAtomic##op##Uint16:                     \
1850     ASSEMBLE_ATOMIC_BINOP_EXT(false, 16, inst); \
1851     break;                                      \
1852   case kAtomic##op##Word32:                     \
1853     ASSEMBLE_ATOMIC_BINOP(inst);                \
1854     break;
1855       ATOMIC_BINOP_CASE(Add, Addu)
1856       ATOMIC_BINOP_CASE(Sub, Subu)
1857       ATOMIC_BINOP_CASE(And, And)
1858       ATOMIC_BINOP_CASE(Or, Or)
1859       ATOMIC_BINOP_CASE(Xor, Xor)
1860 #undef ATOMIC_BINOP_CASE
1861     case kMipsWord32AtomicPairLoad: {
1862       if (IsMipsArchVariant(kMips32r6)) {
1863         if (instr->OutputCount() > 0) {
1864           Register second_output = instr->OutputCount() == 2
1865                                        ? i.OutputRegister(1)
1866                                        : i.TempRegister(1);
1867           __ Addu(a0, i.InputRegister(0), i.InputRegister(1));
1868           __ llx(second_output, MemOperand(a0, 4));
1869           __ ll(i.OutputRegister(0), MemOperand(a0, 0));
1870           __ sync();
1871         }
1872       } else {
1873         FrameScope scope(tasm(), StackFrame::MANUAL);
1874         __ Addu(a0, i.InputRegister(0), i.InputRegister(1));
1875         __ PushCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1876         __ PrepareCallCFunction(1, 0, kScratchReg);
1877         __ CallCFunction(ExternalReference::atomic_pair_load_function(), 1, 0);
1878         __ PopCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1879       }
1880       break;
1881     }
1882     case kMipsWord32AtomicPairStore: {
1883       if (IsMipsArchVariant(kMips32r6)) {
1884         Label store;
1885         __ Addu(a0, i.InputRegister(0), i.InputRegister(1));
1886         __ sync();
1887         __ bind(&store);
1888         __ llx(i.TempRegister(2), MemOperand(a0, 4));
1889         __ ll(i.TempRegister(1), MemOperand(a0, 0));
1890         __ Move(i.TempRegister(1), i.InputRegister(2));
1891         __ scx(i.InputRegister(3), MemOperand(a0, 4));
1892         __ sc(i.TempRegister(1), MemOperand(a0, 0));
1893         __ BranchShort(&store, eq, i.TempRegister(1), Operand(zero_reg));
1894         __ sync();
1895       } else {
1896         FrameScope scope(tasm(), StackFrame::MANUAL);
1897         __ Addu(a0, i.InputRegister(0), i.InputRegister(1));
1898         __ PushCallerSaved(SaveFPRegsMode::kIgnore);
1899         __ PrepareCallCFunction(3, 0, kScratchReg);
1900         __ CallCFunction(ExternalReference::atomic_pair_store_function(), 3, 0);
1901         __ PopCallerSaved(SaveFPRegsMode::kIgnore);
1902       }
1903       break;
1904     }
1905 #define ATOMIC64_BINOP_ARITH_CASE(op, instr, external) \
1906   case kMipsWord32AtomicPair##op:                      \
1907     ASSEMBLE_ATOMIC64_ARITH_BINOP(instr, external);    \
1908     break;
1909       ATOMIC64_BINOP_ARITH_CASE(Add, AddPair, atomic_pair_add_function)
1910       ATOMIC64_BINOP_ARITH_CASE(Sub, SubPair, atomic_pair_sub_function)
1911 #undef ATOMIC64_BINOP_ARITH_CASE
1912 #define ATOMIC64_BINOP_LOGIC_CASE(op, instr, external) \
1913   case kMipsWord32AtomicPair##op:                      \
1914     ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr, external);    \
1915     break;
1916       ATOMIC64_BINOP_LOGIC_CASE(And, AndPair, atomic_pair_and_function)
1917       ATOMIC64_BINOP_LOGIC_CASE(Or, OrPair, atomic_pair_or_function)
1918       ATOMIC64_BINOP_LOGIC_CASE(Xor, XorPair, atomic_pair_xor_function)
1919 #undef ATOMIC64_BINOP_LOGIC_CASE
1920     case kMipsWord32AtomicPairExchange:
1921       if (IsMipsArchVariant(kMips32r6)) {
1922         Label binop;
1923         Register oldval_low =
1924             instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1);
1925         Register oldval_high =
1926             instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2);
1927         __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1928         __ sync();
1929         __ bind(&binop);
1930         __ llx(oldval_high, MemOperand(i.TempRegister(0), 4));
1931         __ ll(oldval_low, MemOperand(i.TempRegister(0), 0));
1932         __ Move(i.TempRegister(1), i.InputRegister(2));
1933         __ scx(i.InputRegister(3), MemOperand(i.TempRegister(0), 4));
1934         __ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));
1935         __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));
1936         __ sync();
1937       } else {
1938         FrameScope scope(tasm(), StackFrame::MANUAL);
1939         __ PushCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1940         __ PrepareCallCFunction(3, 0, kScratchReg);
1941         __ Addu(a0, i.InputRegister(0), i.InputRegister(1));
1942         __ CallCFunction(ExternalReference::atomic_pair_exchange_function(), 3,
1943                          0);
1944         __ PopCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1945       }
1946       break;
1947     case kMipsWord32AtomicPairCompareExchange: {
1948       if (IsMipsArchVariant(kMips32r6)) {
1949         Label compareExchange, exit;
1950         Register oldval_low =
1951             instr->OutputCount() >= 1 ? i.OutputRegister(0) : kScratchReg;
1952         Register oldval_high =
1953             instr->OutputCount() >= 2 ? i.OutputRegister(1) : kScratchReg2;
1954         __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1955         __ sync();
1956         __ bind(&compareExchange);
1957         __ llx(oldval_high, MemOperand(i.TempRegister(0), 4));
1958         __ ll(oldval_low, MemOperand(i.TempRegister(0), 0));
1959         __ BranchShort(&exit, ne, i.InputRegister(2), Operand(oldval_low));
1960         __ BranchShort(&exit, ne, i.InputRegister(3), Operand(oldval_high));
1961         __ mov(kScratchReg, i.InputRegister(4));
1962         __ scx(i.InputRegister(5), MemOperand(i.TempRegister(0), 4));
1963         __ sc(kScratchReg, MemOperand(i.TempRegister(0), 0));
1964         __ BranchShort(&compareExchange, eq, kScratchReg, Operand(zero_reg));
1965         __ bind(&exit);
1966         __ sync();
1967       } else {
1968         FrameScope scope(tasm(), StackFrame::MANUAL);
1969         __ PushCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1970         __ PrepareCallCFunction(5, 0, kScratchReg);
1971         __ addu(a0, i.InputRegister(0), i.InputRegister(1));
1972         __ sw(i.InputRegister(5), MemOperand(sp, 16));
1973         __ CallCFunction(
1974             ExternalReference::atomic_pair_compare_exchange_function(), 5, 0);
1975         __ PopCallerSaved(SaveFPRegsMode::kIgnore, v0, v1);
1976       }
1977       break;
1978     }
1979     case kMipsS128Zero: {
1980       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1981       __ xor_v(i.OutputSimd128Register(), i.OutputSimd128Register(),
1982                i.OutputSimd128Register());
1983       break;
1984     }
1985     case kMipsI32x4Splat: {
1986       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1987       __ fill_w(i.OutputSimd128Register(), i.InputRegister(0));
1988       break;
1989     }
1990     case kMipsI32x4ExtractLane: {
1991       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1992       __ copy_s_w(i.OutputRegister(), i.InputSimd128Register(0),
1993                   i.InputInt8(1));
1994       break;
1995     }
1996     case kMipsI32x4ReplaceLane: {
1997       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1998       Simd128Register src = i.InputSimd128Register(0);
1999       Simd128Register dst = i.OutputSimd128Register();
2000       if (src != dst) {
2001         __ move_v(dst, src);
2002       }
2003       __ insert_w(dst, i.InputInt8(1), i.InputRegister(2));
2004       break;
2005     }
2006     case kMipsI32x4Add: {
2007       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2008       __ addv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2009                 i.InputSimd128Register(1));
2010       break;
2011     }
2012     case kMipsI32x4Sub: {
2013       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2014       __ subv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2015                 i.InputSimd128Register(1));
2016       break;
2017     }
2018     case kMipsI32x4ExtAddPairwiseI16x8S: {
2019       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2020       __ hadd_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2021                   i.InputSimd128Register(0));
2022       break;
2023     }
2024     case kMipsI32x4ExtAddPairwiseI16x8U: {
2025       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2026       __ hadd_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2027                   i.InputSimd128Register(0));
2028       break;
2029     }
2030     case kMipsF64x2Abs: {
2031       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2032       __ bclri_d(i.OutputSimd128Register(), i.InputSimd128Register(0), 63);
2033       break;
2034     }
2035     case kMipsF64x2Neg: {
2036       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2037       __ bnegi_d(i.OutputSimd128Register(), i.InputSimd128Register(0), 63);
2038       break;
2039     }
2040     case kMipsF64x2Sqrt: {
2041       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2042       __ fsqrt_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2043       break;
2044     }
2045     case kMipsF64x2Add: {
2046       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2047       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fadd_d);
2048       break;
2049     }
2050     case kMipsF64x2Sub: {
2051       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2052       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fsub_d);
2053       break;
2054     }
2055     case kMipsF64x2Mul: {
2056       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2057       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fmul_d);
2058       break;
2059     }
2060     case kMipsF64x2Div: {
2061       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2062       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fdiv_d);
2063       break;
2064     }
2065     case kMipsF64x2Min: {
2066       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2067       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fmin_d);
2068       break;
2069     }
2070     case kMipsF64x2Max: {
2071       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2072       ASSEMBLE_F64X2_ARITHMETIC_BINOP(fmax_d);
2073       break;
2074     }
2075     case kMipsF64x2Eq: {
2076       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2077       __ fceq_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2078                 i.InputSimd128Register(1));
2079       break;
2080     }
2081     case kMipsF64x2Ne: {
2082       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2083       __ fcne_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2084                 i.InputSimd128Register(1));
2085       break;
2086     }
2087     case kMipsF64x2Lt: {
2088       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2089       __ fclt_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2090                 i.InputSimd128Register(1));
2091       break;
2092     }
2093     case kMipsF64x2Le: {
2094       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2095       __ fcle_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2096                 i.InputSimd128Register(1));
2097       break;
2098     }
2099     case kMipsF64x2Splat: {
2100       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2101       Simd128Register dst = i.OutputSimd128Register();
2102       __ FmoveLow(kScratchReg, i.InputDoubleRegister(0));
2103       __ insert_w(dst, 0, kScratchReg);
2104       __ insert_w(dst, 2, kScratchReg);
2105       __ FmoveHigh(kScratchReg, i.InputDoubleRegister(0));
2106       __ insert_w(dst, 1, kScratchReg);
2107       __ insert_w(dst, 3, kScratchReg);
2108       break;
2109     }
2110     case kMipsF64x2ExtractLane: {
2111       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2112       __ copy_u_w(kScratchReg, i.InputSimd128Register(0), i.InputInt8(1) * 2);
2113       __ FmoveLow(i.OutputDoubleRegister(), kScratchReg);
2114       __ copy_u_w(kScratchReg, i.InputSimd128Register(0),
2115                   i.InputInt8(1) * 2 + 1);
2116       __ FmoveHigh(i.OutputDoubleRegister(), kScratchReg);
2117       break;
2118     }
2119     case kMipsF64x2ReplaceLane: {
2120       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2121       Simd128Register src = i.InputSimd128Register(0);
2122       Simd128Register dst = i.OutputSimd128Register();
2123       if (src != dst) {
2124         __ move_v(dst, src);
2125       }
2126       __ FmoveLow(kScratchReg, i.InputDoubleRegister(2));
2127       __ insert_w(dst, i.InputInt8(1) * 2, kScratchReg);
2128       __ FmoveHigh(kScratchReg, i.InputDoubleRegister(2));
2129       __ insert_w(dst, i.InputInt8(1) * 2 + 1, kScratchReg);
2130       break;
2131     }
2132     case kMipsF64x2Pmin: {
2133       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2134       Simd128Register dst = i.OutputSimd128Register();
2135       Simd128Register lhs = i.InputSimd128Register(0);
2136       Simd128Register rhs = i.InputSimd128Register(1);
2137       // dst = rhs < lhs ? rhs : lhs
2138       __ fclt_d(dst, rhs, lhs);
2139       __ bsel_v(dst, lhs, rhs);
2140       break;
2141     }
2142     case kMipsF64x2Pmax: {
2143       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2144       Simd128Register dst = i.OutputSimd128Register();
2145       Simd128Register lhs = i.InputSimd128Register(0);
2146       Simd128Register rhs = i.InputSimd128Register(1);
2147       // dst = lhs < rhs ? rhs : lhs
2148       __ fclt_d(dst, lhs, rhs);
2149       __ bsel_v(dst, lhs, rhs);
2150       break;
2151     }
2152     case kMipsF64x2Ceil: {
2153       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2154       __ cfcmsa(kScratchReg, MSACSR);
2155       __ li(kScratchReg2, kRoundToPlusInf);
2156       __ ctcmsa(MSACSR, kScratchReg2);
2157       __ frint_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2158       __ ctcmsa(MSACSR, kScratchReg);
2159       break;
2160     }
2161     case kMipsF64x2Floor: {
2162       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2163       __ cfcmsa(kScratchReg, MSACSR);
2164       __ li(kScratchReg2, kRoundToMinusInf);
2165       __ ctcmsa(MSACSR, kScratchReg2);
2166       __ frint_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2167       __ ctcmsa(MSACSR, kScratchReg);
2168       break;
2169     }
2170     case kMipsF64x2Trunc: {
2171       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2172       __ cfcmsa(kScratchReg, MSACSR);
2173       __ li(kScratchReg2, kRoundToZero);
2174       __ ctcmsa(MSACSR, kScratchReg2);
2175       __ frint_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2176       __ ctcmsa(MSACSR, kScratchReg);
2177       break;
2178     }
2179     case kMipsF64x2NearestInt: {
2180       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2181       __ cfcmsa(kScratchReg, MSACSR);
2182       // kRoundToNearest == 0
2183       __ ctcmsa(MSACSR, zero_reg);
2184       __ frint_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2185       __ ctcmsa(MSACSR, kScratchReg);
2186       break;
2187     }
2188     case kMipsF64x2ConvertLowI32x4S: {
2189       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2190       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2191       __ ilvr_w(kSimd128RegZero, kSimd128RegZero, i.InputSimd128Register(0));
2192       __ slli_d(kSimd128RegZero, kSimd128RegZero, 32);
2193       __ srai_d(kSimd128RegZero, kSimd128RegZero, 32);
2194       __ ffint_s_d(i.OutputSimd128Register(), kSimd128RegZero);
2195       break;
2196     }
2197     case kMipsF64x2ConvertLowI32x4U: {
2198       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2199       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2200       __ ilvr_w(kSimd128RegZero, kSimd128RegZero, i.InputSimd128Register(0));
2201       __ ffint_u_d(i.OutputSimd128Register(), kSimd128RegZero);
2202       break;
2203     }
2204     case kMipsF64x2PromoteLowF32x4: {
2205       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2206       __ fexupr_d(i.OutputSimd128Register(), i.InputSimd128Register(0));
2207       break;
2208     }
2209     case kMipsI64x2Add: {
2210       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2211       __ addv_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2212                 i.InputSimd128Register(1));
2213       break;
2214     }
2215     case kMipsI64x2Sub: {
2216       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2217       __ subv_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2218                 i.InputSimd128Register(1));
2219       break;
2220     }
2221     case kMipsI64x2Mul: {
2222       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2223       __ mulv_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2224                 i.InputSimd128Register(1));
2225       break;
2226     }
2227     case kMipsI64x2Neg: {
2228       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2229       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2230       __ subv_d(i.OutputSimd128Register(), kSimd128RegZero,
2231                 i.InputSimd128Register(0));
2232       break;
2233     }
2234     case kMipsI64x2Shl: {
2235       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2236       __ slli_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2237                 i.InputInt6(1));
2238       break;
2239     }
2240     case kMipsI64x2ShrS: {
2241       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2242       __ srai_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2243                 i.InputInt6(1));
2244       break;
2245     }
2246     case kMipsI64x2ShrU: {
2247       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2248       __ srli_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2249                 i.InputInt6(1));
2250       break;
2251     }
2252     case kMipsI64x2BitMask: {
2253       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2254       Register dst = i.OutputRegister();
2255       Simd128Register src = i.InputSimd128Register(0);
2256       Simd128Register scratch0 = kSimd128RegZero;
2257       Simd128Register scratch1 = kSimd128ScratchReg;
2258       __ srli_d(scratch0, src, 63);
2259       __ shf_w(scratch1, scratch0, 0x02);
2260       __ slli_d(scratch1, scratch1, 1);
2261       __ or_v(scratch0, scratch0, scratch1);
2262       __ copy_u_b(dst, scratch0, 0);
2263       break;
2264     }
2265     case kMipsI64x2Eq: {
2266       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2267       __ ceq_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2268                i.InputSimd128Register(1));
2269       break;
2270     }
2271     case kMipsI64x2Ne: {
2272       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2273       __ ceq_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2274                i.InputSimd128Register(1));
2275       __ nor_v(i.OutputSimd128Register(), i.OutputSimd128Register(),
2276                i.OutputSimd128Register());
2277       break;
2278     }
2279     case kMipsI64x2GtS: {
2280       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2281       __ clt_s_d(i.OutputSimd128Register(), i.InputSimd128Register(1),
2282                  i.InputSimd128Register(0));
2283       break;
2284     }
2285     case kMipsI64x2GeS: {
2286       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2287       __ cle_s_d(i.OutputSimd128Register(), i.InputSimd128Register(1),
2288                  i.InputSimd128Register(0));
2289       break;
2290     }
2291     case kMipsI64x2Abs: {
2292       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2293       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2294       __ adds_a_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
2295                   kSimd128RegZero);
2296       break;
2297     }
2298     case kMipsI64x2SConvertI32x4Low: {
2299       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2300       Simd128Register dst = i.OutputSimd128Register();
2301       Simd128Register src = i.InputSimd128Register(0);
2302       __ ilvr_w(kSimd128ScratchReg, src, src);
2303       __ slli_d(dst, kSimd128ScratchReg, 32);
2304       __ srai_d(dst, dst, 32);
2305       break;
2306     }
2307     case kMipsI64x2SConvertI32x4High: {
2308       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2309       Simd128Register dst = i.OutputSimd128Register();
2310       Simd128Register src = i.InputSimd128Register(0);
2311       __ ilvl_w(kSimd128ScratchReg, src, src);
2312       __ slli_d(dst, kSimd128ScratchReg, 32);
2313       __ srai_d(dst, dst, 32);
2314       break;
2315     }
2316     case kMipsI64x2UConvertI32x4Low: {
2317       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2318       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2319       __ ilvr_w(i.OutputSimd128Register(), kSimd128RegZero,
2320                 i.InputSimd128Register(0));
2321       break;
2322     }
2323     case kMipsI64x2UConvertI32x4High: {
2324       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2325       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2326       __ ilvl_w(i.OutputSimd128Register(), kSimd128RegZero,
2327                 i.InputSimd128Register(0));
2328       break;
2329     }
2330     case kMipsI64x2ExtMulLowI32x4S:
2331       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_w, dotp_s_d);
2332       break;
2333     case kMipsI64x2ExtMulHighI32x4S:
2334       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_w, dotp_s_d);
2335       break;
2336     case kMipsI64x2ExtMulLowI32x4U:
2337       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_w, dotp_u_d);
2338       break;
2339     case kMipsI64x2ExtMulHighI32x4U:
2340       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_w, dotp_u_d);
2341       break;
2342     case kMipsI32x4ExtMulLowI16x8S:
2343       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_h, dotp_s_w);
2344       break;
2345     case kMipsI32x4ExtMulHighI16x8S:
2346       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_h, dotp_s_w);
2347       break;
2348     case kMipsI32x4ExtMulLowI16x8U:
2349       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_h, dotp_u_w);
2350       break;
2351     case kMipsI32x4ExtMulHighI16x8U:
2352       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_h, dotp_u_w);
2353       break;
2354     case kMipsI16x8ExtMulLowI8x16S:
2355       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_b, dotp_s_h);
2356       break;
2357     case kMipsI16x8ExtMulHighI8x16S:
2358       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_b, dotp_s_h);
2359       break;
2360     case kMipsI16x8ExtMulLowI8x16U:
2361       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvr_b, dotp_u_h);
2362       break;
2363     case kMipsI16x8ExtMulHighI8x16U:
2364       ASSEMBLE_SIMD_EXTENDED_MULTIPLY(ilvl_b, dotp_u_h);
2365       break;
2366     case kMipsF32x4Splat: {
2367       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2368       __ FmoveLow(kScratchReg, i.InputSingleRegister(0));
2369       __ fill_w(i.OutputSimd128Register(), kScratchReg);
2370       break;
2371     }
2372     case kMipsF32x4ExtractLane: {
2373       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2374       __ copy_u_w(kScratchReg, i.InputSimd128Register(0), i.InputInt8(1));
2375       __ FmoveLow(i.OutputSingleRegister(), kScratchReg);
2376       break;
2377     }
2378     case kMipsF32x4ReplaceLane: {
2379       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2380       Simd128Register src = i.InputSimd128Register(0);
2381       Simd128Register dst = i.OutputSimd128Register();
2382       if (src != dst) {
2383         __ move_v(dst, src);
2384       }
2385       __ FmoveLow(kScratchReg, i.InputSingleRegister(2));
2386       __ insert_w(dst, i.InputInt8(1), kScratchReg);
2387       break;
2388     }
2389     case kMipsF32x4SConvertI32x4: {
2390       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2391       __ ffint_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2392       break;
2393     }
2394     case kMipsF32x4UConvertI32x4: {
2395       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2396       __ ffint_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2397       break;
2398     }
2399     case kMipsF32x4DemoteF64x2Zero: {
2400       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2401       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2402       __ fexdo_w(i.OutputSimd128Register(), kSimd128RegZero,
2403                  i.InputSimd128Register(0));
2404       break;
2405     }
2406     case kMipsI32x4Mul: {
2407       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2408       __ mulv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2409                 i.InputSimd128Register(1));
2410       break;
2411     }
2412     case kMipsI32x4MaxS: {
2413       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2414       __ max_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2415                  i.InputSimd128Register(1));
2416       break;
2417     }
2418     case kMipsI32x4MinS: {
2419       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2420       __ min_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2421                  i.InputSimd128Register(1));
2422       break;
2423     }
2424     case kMipsI32x4Eq: {
2425       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2426       __ ceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2427                i.InputSimd128Register(1));
2428       break;
2429     }
2430     case kMipsI32x4Ne: {
2431       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2432       Simd128Register dst = i.OutputSimd128Register();
2433       __ ceq_w(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
2434       __ nor_v(dst, dst, dst);
2435       break;
2436     }
2437     case kMipsI32x4Shl: {
2438       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2439       __ slli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2440                 i.InputInt5(1));
2441       break;
2442     }
2443     case kMipsI32x4ShrS: {
2444       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2445       __ srai_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2446                 i.InputInt5(1));
2447       break;
2448     }
2449     case kMipsI32x4ShrU: {
2450       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2451       __ srli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2452                 i.InputInt5(1));
2453       break;
2454     }
2455     case kMipsI32x4MaxU: {
2456       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2457       __ max_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2458                  i.InputSimd128Register(1));
2459       break;
2460     }
2461     case kMipsI32x4MinU: {
2462       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2463       __ min_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2464                  i.InputSimd128Register(1));
2465       break;
2466     }
2467     case kMipsS128Select: {
2468       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2469       DCHECK(i.OutputSimd128Register() == i.InputSimd128Register(0));
2470       __ bsel_v(i.OutputSimd128Register(), i.InputSimd128Register(2),
2471                 i.InputSimd128Register(1));
2472       break;
2473     }
2474     case kMipsS128AndNot: {
2475       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2476       Simd128Register dst = i.OutputSimd128Register();
2477       __ nor_v(dst, i.InputSimd128Register(1), i.InputSimd128Register(1));
2478       __ and_v(dst, dst, i.InputSimd128Register(0));
2479       break;
2480     }
2481     case kMipsF32x4Abs: {
2482       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2483       __ bclri_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
2484       break;
2485     }
2486     case kMipsF32x4Neg: {
2487       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2488       __ bnegi_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
2489       break;
2490     }
2491     case kMipsF32x4Sqrt: {
2492       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2493       __ fsqrt_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2494       break;
2495     }
2496     case kMipsF32x4RecipApprox: {
2497       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2498       __ frcp_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2499       break;
2500     }
2501     case kMipsF32x4RecipSqrtApprox: {
2502       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2503       __ frsqrt_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2504       break;
2505     }
2506     case kMipsF32x4Add: {
2507       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2508       __ fadd_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2509                 i.InputSimd128Register(1));
2510       break;
2511     }
2512     case kMipsF32x4Sub: {
2513       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2514       __ fsub_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2515                 i.InputSimd128Register(1));
2516       break;
2517     }
2518     case kMipsF32x4Mul: {
2519       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2520       __ fmul_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2521                 i.InputSimd128Register(1));
2522       break;
2523     }
2524     case kMipsF32x4Div: {
2525       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2526       __ fdiv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2527                 i.InputSimd128Register(1));
2528       break;
2529     }
2530     case kMipsF32x4Max: {
2531       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2532       __ fmax_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2533                 i.InputSimd128Register(1));
2534       break;
2535     }
2536     case kMipsF32x4Min: {
2537       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2538       __ fmin_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2539                 i.InputSimd128Register(1));
2540       break;
2541     }
2542     case kMipsF32x4Eq: {
2543       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2544       __ fceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2545                 i.InputSimd128Register(1));
2546       break;
2547     }
2548     case kMipsF32x4Ne: {
2549       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2550       __ fcne_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2551                 i.InputSimd128Register(1));
2552       break;
2553     }
2554     case kMipsF32x4Lt: {
2555       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2556       __ fclt_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2557                 i.InputSimd128Register(1));
2558       break;
2559     }
2560     case kMipsF32x4Le: {
2561       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2562       __ fcle_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2563                 i.InputSimd128Register(1));
2564       break;
2565     }
2566     case kMipsF32x4Pmin: {
2567       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2568       Simd128Register dst = i.OutputSimd128Register();
2569       Simd128Register lhs = i.InputSimd128Register(0);
2570       Simd128Register rhs = i.InputSimd128Register(1);
2571       // dst = rhs < lhs ? rhs : lhs
2572       __ fclt_w(dst, rhs, lhs);
2573       __ bsel_v(dst, lhs, rhs);
2574       break;
2575     }
2576     case kMipsF32x4Pmax: {
2577       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2578       Simd128Register dst = i.OutputSimd128Register();
2579       Simd128Register lhs = i.InputSimd128Register(0);
2580       Simd128Register rhs = i.InputSimd128Register(1);
2581       // dst = lhs < rhs ? rhs : lhs
2582       __ fclt_w(dst, lhs, rhs);
2583       __ bsel_v(dst, lhs, rhs);
2584       break;
2585     }
2586     case kMipsF32x4Ceil: {
2587       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2588       __ cfcmsa(kScratchReg, MSACSR);
2589       __ li(kScratchReg2, kRoundToPlusInf);
2590       __ ctcmsa(MSACSR, kScratchReg2);
2591       __ frint_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2592       __ ctcmsa(MSACSR, kScratchReg);
2593       break;
2594     }
2595     case kMipsF32x4Floor: {
2596       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2597       __ cfcmsa(kScratchReg, MSACSR);
2598       __ li(kScratchReg2, kRoundToMinusInf);
2599       __ ctcmsa(MSACSR, kScratchReg2);
2600       __ frint_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2601       __ ctcmsa(MSACSR, kScratchReg);
2602       break;
2603     }
2604     case kMipsF32x4Trunc: {
2605       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2606       __ cfcmsa(kScratchReg, MSACSR);
2607       __ li(kScratchReg2, kRoundToZero);
2608       __ ctcmsa(MSACSR, kScratchReg2);
2609       __ frint_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2610       __ ctcmsa(MSACSR, kScratchReg);
2611       break;
2612     }
2613     case kMipsF32x4NearestInt: {
2614       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2615       __ cfcmsa(kScratchReg, MSACSR);
2616       // kRoundToNearest == 0
2617       __ ctcmsa(MSACSR, zero_reg);
2618       __ frint_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2619       __ ctcmsa(MSACSR, kScratchReg);
2620       break;
2621     }
2622     case kMipsI32x4SConvertF32x4: {
2623       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2624       __ ftrunc_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2625       break;
2626     }
2627     case kMipsI32x4UConvertF32x4: {
2628       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2629       __ ftrunc_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
2630       break;
2631     }
2632     case kMipsI32x4Neg: {
2633       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2634       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2635       __ subv_w(i.OutputSimd128Register(), kSimd128RegZero,
2636                 i.InputSimd128Register(0));
2637       break;
2638     }
2639     case kMipsI32x4GtS: {
2640       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2641       __ clt_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2642                  i.InputSimd128Register(0));
2643       break;
2644     }
2645     case kMipsI32x4GeS: {
2646       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2647       __ cle_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2648                  i.InputSimd128Register(0));
2649       break;
2650     }
2651     case kMipsI32x4GtU: {
2652       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2653       __ clt_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2654                  i.InputSimd128Register(0));
2655       break;
2656     }
2657     case kMipsI32x4GeU: {
2658       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2659       __ cle_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
2660                  i.InputSimd128Register(0));
2661       break;
2662     }
2663     case kMipsI32x4Abs: {
2664       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2665       __ asub_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2666                   kSimd128RegZero);
2667       break;
2668     }
2669     case kMipsI32x4BitMask: {
2670       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2671       Register dst = i.OutputRegister();
2672       Simd128Register src = i.InputSimd128Register(0);
2673       Simd128Register scratch0 = kSimd128RegZero;
2674       Simd128Register scratch1 = kSimd128ScratchReg;
2675       __ srli_w(scratch0, src, 31);
2676       __ srli_d(scratch1, scratch0, 31);
2677       __ or_v(scratch0, scratch0, scratch1);
2678       __ shf_w(scratch1, scratch0, 0x0E);
2679       __ slli_d(scratch1, scratch1, 2);
2680       __ or_v(scratch0, scratch0, scratch1);
2681       __ copy_u_b(dst, scratch0, 0);
2682       break;
2683     }
2684     case kMipsI32x4DotI16x8S: {
2685       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2686       __ dotp_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
2687                   i.InputSimd128Register(1));
2688       break;
2689     }
2690     case kMipsI32x4TruncSatF64x2SZero: {
2691       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2692       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2693       __ ftrunc_s_d(kSimd128ScratchReg, i.InputSimd128Register(0));
2694       __ sat_s_d(kSimd128ScratchReg, kSimd128ScratchReg, 31);
2695       __ pckev_w(i.OutputSimd128Register(), kSimd128RegZero,
2696                  kSimd128ScratchReg);
2697       break;
2698     }
2699     case kMipsI32x4TruncSatF64x2UZero: {
2700       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2701       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2702       __ ftrunc_u_d(kSimd128ScratchReg, i.InputSimd128Register(0));
2703       __ sat_u_d(kSimd128ScratchReg, kSimd128ScratchReg, 31);
2704       __ pckev_w(i.OutputSimd128Register(), kSimd128RegZero,
2705                  kSimd128ScratchReg);
2706       break;
2707     }
2708     case kMipsI16x8Splat: {
2709       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2710       __ fill_h(i.OutputSimd128Register(), i.InputRegister(0));
2711       break;
2712     }
2713     case kMipsI16x8ExtractLaneU: {
2714       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2715       __ copy_u_h(i.OutputRegister(), i.InputSimd128Register(0),
2716                   i.InputInt8(1));
2717       break;
2718     }
2719     case kMipsI16x8ExtractLaneS: {
2720       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2721       __ copy_s_h(i.OutputRegister(), i.InputSimd128Register(0),
2722                   i.InputInt8(1));
2723       break;
2724     }
2725     case kMipsI16x8ReplaceLane: {
2726       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2727       Simd128Register src = i.InputSimd128Register(0);
2728       Simd128Register dst = i.OutputSimd128Register();
2729       if (src != dst) {
2730         __ move_v(dst, src);
2731       }
2732       __ insert_h(dst, i.InputInt8(1), i.InputRegister(2));
2733       break;
2734     }
2735     case kMipsI16x8Neg: {
2736       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2737       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2738       __ subv_h(i.OutputSimd128Register(), kSimd128RegZero,
2739                 i.InputSimd128Register(0));
2740       break;
2741     }
2742     case kMipsI16x8Shl: {
2743       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2744       __ slli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2745                 i.InputInt4(1));
2746       break;
2747     }
2748     case kMipsI16x8ShrS: {
2749       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2750       __ srai_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2751                 i.InputInt4(1));
2752       break;
2753     }
2754     case kMipsI16x8ShrU: {
2755       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2756       __ srli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2757                 i.InputInt4(1));
2758       break;
2759     }
2760     case kMipsI16x8Add: {
2761       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2762       __ addv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2763                 i.InputSimd128Register(1));
2764       break;
2765     }
2766     case kMipsI16x8AddSatS: {
2767       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2768       __ adds_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2769                   i.InputSimd128Register(1));
2770       break;
2771     }
2772     case kMipsI16x8Sub: {
2773       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2774       __ subv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2775                 i.InputSimd128Register(1));
2776       break;
2777     }
2778     case kMipsI16x8SubSatS: {
2779       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2780       __ subs_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2781                   i.InputSimd128Register(1));
2782       break;
2783     }
2784     case kMipsI16x8Mul: {
2785       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2786       __ mulv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2787                 i.InputSimd128Register(1));
2788       break;
2789     }
2790     case kMipsI16x8MaxS: {
2791       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2792       __ max_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2793                  i.InputSimd128Register(1));
2794       break;
2795     }
2796     case kMipsI16x8MinS: {
2797       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2798       __ min_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2799                  i.InputSimd128Register(1));
2800       break;
2801     }
2802     case kMipsI16x8Eq: {
2803       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2804       __ ceq_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2805                i.InputSimd128Register(1));
2806       break;
2807     }
2808     case kMipsI16x8Ne: {
2809       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2810       Simd128Register dst = i.OutputSimd128Register();
2811       __ ceq_h(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
2812       __ nor_v(dst, dst, dst);
2813       break;
2814     }
2815     case kMipsI16x8GtS: {
2816       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2817       __ clt_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2818                  i.InputSimd128Register(0));
2819       break;
2820     }
2821     case kMipsI16x8GeS: {
2822       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2823       __ cle_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2824                  i.InputSimd128Register(0));
2825       break;
2826     }
2827     case kMipsI16x8AddSatU: {
2828       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2829       __ adds_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2830                   i.InputSimd128Register(1));
2831       break;
2832     }
2833     case kMipsI16x8SubSatU: {
2834       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2835       __ subs_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2836                   i.InputSimd128Register(1));
2837       break;
2838     }
2839     case kMipsI16x8MaxU: {
2840       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2841       __ max_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2842                  i.InputSimd128Register(1));
2843       break;
2844     }
2845     case kMipsI16x8MinU: {
2846       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2847       __ min_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2848                  i.InputSimd128Register(1));
2849       break;
2850     }
2851     case kMipsI16x8GtU: {
2852       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2853       __ clt_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2854                  i.InputSimd128Register(0));
2855       break;
2856     }
2857     case kMipsI16x8GeU: {
2858       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2859       __ cle_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2860                  i.InputSimd128Register(0));
2861       break;
2862     }
2863     case kMipsI16x8RoundingAverageU: {
2864       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2865       __ aver_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
2866                   i.InputSimd128Register(0));
2867       break;
2868     }
2869     case kMipsI16x8Abs: {
2870       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2871       __ asub_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2872                   kSimd128RegZero);
2873       break;
2874     }
2875     case kMipsI16x8BitMask: {
2876       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2877       Register dst = i.OutputRegister();
2878       Simd128Register src = i.InputSimd128Register(0);
2879       Simd128Register scratch0 = kSimd128RegZero;
2880       Simd128Register scratch1 = kSimd128ScratchReg;
2881       __ srli_h(scratch0, src, 15);
2882       __ srli_w(scratch1, scratch0, 15);
2883       __ or_v(scratch0, scratch0, scratch1);
2884       __ srli_d(scratch1, scratch0, 30);
2885       __ or_v(scratch0, scratch0, scratch1);
2886       __ shf_w(scratch1, scratch0, 0x0E);
2887       __ slli_d(scratch1, scratch1, 4);
2888       __ or_v(scratch0, scratch0, scratch1);
2889       __ copy_u_b(dst, scratch0, 0);
2890       break;
2891     }
2892     case kMipsI16x8Q15MulRSatS: {
2893       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2894       __ mulr_q_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2895                   i.InputSimd128Register(1));
2896       break;
2897     }
2898     case kMipsI16x8ExtAddPairwiseI8x16S: {
2899       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2900       __ hadd_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2901                   i.InputSimd128Register(0));
2902       break;
2903     }
2904     case kMipsI16x8ExtAddPairwiseI8x16U: {
2905       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2906       __ hadd_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
2907                   i.InputSimd128Register(0));
2908       break;
2909     }
2910     case kMipsI8x16Splat: {
2911       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2912       __ fill_b(i.OutputSimd128Register(), i.InputRegister(0));
2913       break;
2914     }
2915     case kMipsI8x16ExtractLaneU: {
2916       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2917       __ copy_u_b(i.OutputRegister(), i.InputSimd128Register(0),
2918                   i.InputInt8(1));
2919       break;
2920     }
2921     case kMipsI8x16ExtractLaneS: {
2922       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2923       __ copy_s_b(i.OutputRegister(), i.InputSimd128Register(0),
2924                   i.InputInt8(1));
2925       break;
2926     }
2927     case kMipsI8x16ReplaceLane: {
2928       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2929       Simd128Register src = i.InputSimd128Register(0);
2930       Simd128Register dst = i.OutputSimd128Register();
2931       if (src != dst) {
2932         __ move_v(dst, src);
2933       }
2934       __ insert_b(dst, i.InputInt8(1), i.InputRegister(2));
2935       break;
2936     }
2937     case kMipsI8x16Neg: {
2938       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2939       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
2940       __ subv_b(i.OutputSimd128Register(), kSimd128RegZero,
2941                 i.InputSimd128Register(0));
2942       break;
2943     }
2944     case kMipsI8x16Shl: {
2945       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2946       __ slli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2947                 i.InputInt3(1));
2948       break;
2949     }
2950     case kMipsI8x16ShrS: {
2951       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2952       __ srai_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2953                 i.InputInt3(1));
2954       break;
2955     }
2956     case kMipsI8x16Add: {
2957       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2958       __ addv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2959                 i.InputSimd128Register(1));
2960       break;
2961     }
2962     case kMipsI8x16AddSatS: {
2963       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2964       __ adds_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2965                   i.InputSimd128Register(1));
2966       break;
2967     }
2968     case kMipsI8x16Sub: {
2969       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2970       __ subv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2971                 i.InputSimd128Register(1));
2972       break;
2973     }
2974     case kMipsI8x16SubSatS: {
2975       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2976       __ subs_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2977                   i.InputSimd128Register(1));
2978       break;
2979     }
2980     case kMipsI8x16MaxS: {
2981       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2982       __ max_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2983                  i.InputSimd128Register(1));
2984       break;
2985     }
2986     case kMipsI8x16MinS: {
2987       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2988       __ min_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2989                  i.InputSimd128Register(1));
2990       break;
2991     }
2992     case kMipsI8x16Eq: {
2993       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2994       __ ceq_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
2995                i.InputSimd128Register(1));
2996       break;
2997     }
2998     case kMipsI8x16Ne: {
2999       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3000       Simd128Register dst = i.OutputSimd128Register();
3001       __ ceq_b(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
3002       __ nor_v(dst, dst, dst);
3003       break;
3004     }
3005     case kMipsI8x16GtS: {
3006       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3007       __ clt_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
3008                  i.InputSimd128Register(0));
3009       break;
3010     }
3011     case kMipsI8x16GeS: {
3012       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3013       __ cle_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
3014                  i.InputSimd128Register(0));
3015       break;
3016     }
3017     case kMipsI8x16ShrU: {
3018       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3019       __ srli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3020                 i.InputInt3(1));
3021       break;
3022     }
3023     case kMipsI8x16AddSatU: {
3024       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3025       __ adds_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3026                   i.InputSimd128Register(1));
3027       break;
3028     }
3029     case kMipsI8x16SubSatU: {
3030       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3031       __ subs_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3032                   i.InputSimd128Register(1));
3033       break;
3034     }
3035     case kMipsI8x16MaxU: {
3036       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3037       __ max_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3038                  i.InputSimd128Register(1));
3039       break;
3040     }
3041     case kMipsI8x16MinU: {
3042       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3043       __ min_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3044                  i.InputSimd128Register(1));
3045       break;
3046     }
3047     case kMipsI8x16GtU: {
3048       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3049       __ clt_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
3050                  i.InputSimd128Register(0));
3051       break;
3052     }
3053     case kMipsI8x16GeU: {
3054       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3055       __ cle_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
3056                  i.InputSimd128Register(0));
3057       break;
3058     }
3059     case kMipsI8x16RoundingAverageU: {
3060       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3061       __ aver_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
3062                   i.InputSimd128Register(0));
3063       break;
3064     }
3065     case kMipsI8x16Abs: {
3066       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3067       __ asub_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
3068                   kSimd128RegZero);
3069       break;
3070     }
3071     case kMipsI8x16Popcnt: {
3072       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3073       __ pcnt_b(i.OutputSimd128Register(), i.InputSimd128Register(0));
3074       break;
3075     }
3076     case kMipsI8x16BitMask: {
3077       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3078       Register dst = i.OutputRegister();
3079       Simd128Register src = i.InputSimd128Register(0);
3080       Simd128Register scratch0 = kSimd128RegZero;
3081       Simd128Register scratch1 = kSimd128ScratchReg;
3082       __ srli_b(scratch0, src, 7);
3083       __ srli_h(scratch1, scratch0, 7);
3084       __ or_v(scratch0, scratch0, scratch1);
3085       __ srli_w(scratch1, scratch0, 14);
3086       __ or_v(scratch0, scratch0, scratch1);
3087       __ srli_d(scratch1, scratch0, 28);
3088       __ or_v(scratch0, scratch0, scratch1);
3089       __ shf_w(scratch1, scratch0, 0x0E);
3090       __ ilvev_b(scratch0, scratch1, scratch0);
3091       __ copy_u_h(dst, scratch0, 0);
3092       break;
3093     }
3094     case kMipsS128And: {
3095       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3096       __ and_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3097                i.InputSimd128Register(1));
3098       break;
3099     }
3100     case kMipsS128Or: {
3101       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3102       __ or_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3103               i.InputSimd128Register(1));
3104       break;
3105     }
3106     case kMipsS128Xor: {
3107       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3108       __ xor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3109                i.InputSimd128Register(1));
3110       break;
3111     }
3112     case kMipsS128Not: {
3113       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3114       __ nor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3115                i.InputSimd128Register(0));
3116       break;
3117     }
3118     case kMipsV128AnyTrue: {
3119       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3120       Register dst = i.OutputRegister();
3121       Label all_false;
3122 
3123       __ BranchMSA(&all_false, MSA_BRANCH_V, all_zero,
3124                    i.InputSimd128Register(0), USE_DELAY_SLOT);
3125       __ li(dst, 0);  // branch delay slot
3126       __ li(dst, -1);
3127       __ bind(&all_false);
3128       break;
3129     }
3130     case kMipsI64x2AllTrue: {
3131       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3132       Register dst = i.OutputRegister();
3133       Label all_true;
3134       __ BranchMSA(&all_true, MSA_BRANCH_D, all_not_zero,
3135                    i.InputSimd128Register(0), USE_DELAY_SLOT);
3136       __ li(dst, -1);  // branch delay slot
3137       __ li(dst, 0);
3138       __ bind(&all_true);
3139       break;
3140     }
3141     case kMipsI32x4AllTrue: {
3142       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3143       Register dst = i.OutputRegister();
3144       Label all_true;
3145       __ BranchMSA(&all_true, MSA_BRANCH_W, all_not_zero,
3146                    i.InputSimd128Register(0), USE_DELAY_SLOT);
3147       __ li(dst, -1);  // branch delay slot
3148       __ li(dst, 0);
3149       __ bind(&all_true);
3150       break;
3151     }
3152     case kMipsI16x8AllTrue: {
3153       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3154       Register dst = i.OutputRegister();
3155       Label all_true;
3156       __ BranchMSA(&all_true, MSA_BRANCH_H, all_not_zero,
3157                    i.InputSimd128Register(0), USE_DELAY_SLOT);
3158       __ li(dst, -1);  // branch delay slot
3159       __ li(dst, 0);
3160       __ bind(&all_true);
3161       break;
3162     }
3163     case kMipsI8x16AllTrue: {
3164       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3165       Register dst = i.OutputRegister();
3166       Label all_true;
3167       __ BranchMSA(&all_true, MSA_BRANCH_B, all_not_zero,
3168                    i.InputSimd128Register(0), USE_DELAY_SLOT);
3169       __ li(dst, -1);  // branch delay slot
3170       __ li(dst, 0);
3171       __ bind(&all_true);
3172       break;
3173     }
3174     case kMipsMsaLd: {
3175       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3176       __ ld_b(i.OutputSimd128Register(), i.MemoryOperand());
3177       break;
3178     }
3179     case kMipsMsaSt: {
3180       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3181       __ st_b(i.InputSimd128Register(2), i.MemoryOperand());
3182       break;
3183     }
3184     case kMipsS32x4InterleaveRight: {
3185       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3186       Simd128Register dst = i.OutputSimd128Register(),
3187                       src0 = i.InputSimd128Register(0),
3188                       src1 = i.InputSimd128Register(1);
3189       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3190       // dst = [5, 1, 4, 0]
3191       __ ilvr_w(dst, src1, src0);
3192       break;
3193     }
3194     case kMipsS32x4InterleaveLeft: {
3195       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3196       Simd128Register dst = i.OutputSimd128Register(),
3197                       src0 = i.InputSimd128Register(0),
3198                       src1 = i.InputSimd128Register(1);
3199       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3200       // dst = [7, 3, 6, 2]
3201       __ ilvl_w(dst, src1, src0);
3202       break;
3203     }
3204     case kMipsS32x4PackEven: {
3205       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3206       Simd128Register dst = i.OutputSimd128Register(),
3207                       src0 = i.InputSimd128Register(0),
3208                       src1 = i.InputSimd128Register(1);
3209       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3210       // dst = [6, 4, 2, 0]
3211       __ pckev_w(dst, src1, src0);
3212       break;
3213     }
3214     case kMipsS32x4PackOdd: {
3215       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3216       Simd128Register dst = i.OutputSimd128Register(),
3217                       src0 = i.InputSimd128Register(0),
3218                       src1 = i.InputSimd128Register(1);
3219       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3220       // dst = [7, 5, 3, 1]
3221       __ pckod_w(dst, src1, src0);
3222       break;
3223     }
3224     case kMipsS32x4InterleaveEven: {
3225       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3226       Simd128Register dst = i.OutputSimd128Register(),
3227                       src0 = i.InputSimd128Register(0),
3228                       src1 = i.InputSimd128Register(1);
3229       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3230       // dst = [6, 2, 4, 0]
3231       __ ilvev_w(dst, src1, src0);
3232       break;
3233     }
3234     case kMipsS32x4InterleaveOdd: {
3235       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3236       Simd128Register dst = i.OutputSimd128Register(),
3237                       src0 = i.InputSimd128Register(0),
3238                       src1 = i.InputSimd128Register(1);
3239       // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
3240       // dst = [7, 3, 5, 1]
3241       __ ilvod_w(dst, src1, src0);
3242       break;
3243     }
3244     case kMipsS32x4Shuffle: {
3245       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3246       Simd128Register dst = i.OutputSimd128Register(),
3247                       src0 = i.InputSimd128Register(0),
3248                       src1 = i.InputSimd128Register(1);
3249 
3250       int32_t shuffle = i.InputInt32(2);
3251 
3252       if (src0 == src1) {
3253         // Unary S32x4 shuffles are handled with shf.w instruction
3254         unsigned lane = shuffle & 0xFF;
3255         if (FLAG_debug_code) {
3256           // range of all four lanes, for unary instruction,
3257           // should belong to the same range, which can be one of these:
3258           // [0, 3] or [4, 7]
3259           if (lane >= 4) {
3260             int32_t shuffle_helper = shuffle;
3261             for (int i = 0; i < 4; ++i) {
3262               lane = shuffle_helper & 0xFF;
3263               CHECK_GE(lane, 4);
3264               shuffle_helper >>= 8;
3265             }
3266           }
3267         }
3268         uint32_t i8 = 0;
3269         for (int i = 0; i < 4; i++) {
3270           lane = shuffle & 0xFF;
3271           if (lane >= 4) {
3272             lane -= 4;
3273           }
3274           DCHECK_GT(4, lane);
3275           i8 |= lane << (2 * i);
3276           shuffle >>= 8;
3277         }
3278         __ shf_w(dst, src0, i8);
3279       } else {
3280         // For binary shuffles use vshf.w instruction
3281         if (dst == src0) {
3282           __ move_v(kSimd128ScratchReg, src0);
3283           src0 = kSimd128ScratchReg;
3284         } else if (dst == src1) {
3285           __ move_v(kSimd128ScratchReg, src1);
3286           src1 = kSimd128ScratchReg;
3287         }
3288 
3289         __ li(kScratchReg, i.InputInt32(2));
3290         __ insert_w(dst, 0, kScratchReg);
3291         __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
3292         __ ilvr_b(dst, kSimd128RegZero, dst);
3293         __ ilvr_h(dst, kSimd128RegZero, dst);
3294         __ vshf_w(dst, src1, src0);
3295       }
3296       break;
3297     }
3298     case kMipsS16x8InterleaveRight: {
3299       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3300       Simd128Register dst = i.OutputSimd128Register(),
3301                       src0 = i.InputSimd128Register(0),
3302                       src1 = i.InputSimd128Register(1);
3303       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3304       // dst = [11, 3, 10, 2, 9, 1, 8, 0]
3305       __ ilvr_h(dst, src1, src0);
3306       break;
3307     }
3308     case kMipsS16x8InterleaveLeft: {
3309       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3310       Simd128Register dst = i.OutputSimd128Register(),
3311                       src0 = i.InputSimd128Register(0),
3312                       src1 = i.InputSimd128Register(1);
3313       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3314       // dst = [15, 7, 14, 6, 13, 5, 12, 4]
3315       __ ilvl_h(dst, src1, src0);
3316       break;
3317     }
3318     case kMipsS16x8PackEven: {
3319       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3320       Simd128Register dst = i.OutputSimd128Register(),
3321                       src0 = i.InputSimd128Register(0),
3322                       src1 = i.InputSimd128Register(1);
3323       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3324       // dst = [14, 12, 10, 8, 6, 4, 2, 0]
3325       __ pckev_h(dst, src1, src0);
3326       break;
3327     }
3328     case kMipsS16x8PackOdd: {
3329       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3330       Simd128Register dst = i.OutputSimd128Register(),
3331                       src0 = i.InputSimd128Register(0),
3332                       src1 = i.InputSimd128Register(1);
3333       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3334       // dst = [15, 13, 11, 9, 7, 5, 3, 1]
3335       __ pckod_h(dst, src1, src0);
3336       break;
3337     }
3338     case kMipsS16x8InterleaveEven: {
3339       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3340       Simd128Register dst = i.OutputSimd128Register(),
3341                       src0 = i.InputSimd128Register(0),
3342                       src1 = i.InputSimd128Register(1);
3343       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3344       // dst = [14, 6, 12, 4, 10, 2, 8, 0]
3345       __ ilvev_h(dst, src1, src0);
3346       break;
3347     }
3348     case kMipsS16x8InterleaveOdd: {
3349       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3350       Simd128Register dst = i.OutputSimd128Register(),
3351                       src0 = i.InputSimd128Register(0),
3352                       src1 = i.InputSimd128Register(1);
3353       // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
3354       // dst = [15, 7, ... 11, 3, 9, 1]
3355       __ ilvod_h(dst, src1, src0);
3356       break;
3357     }
3358     case kMipsS16x4Reverse: {
3359       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3360       // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [4, 5, 6, 7, 0, 1, 2, 3]
3361       // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
3362       __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
3363       break;
3364     }
3365     case kMipsS16x2Reverse: {
3366       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3367       // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [6, 7, 4, 5, 3, 2, 0, 1]
3368       // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
3369       __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
3370       break;
3371     }
3372     case kMipsS8x16InterleaveRight: {
3373       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3374       Simd128Register dst = i.OutputSimd128Register(),
3375                       src0 = i.InputSimd128Register(0),
3376                       src1 = i.InputSimd128Register(1);
3377       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3378       // dst = [23, 7, ... 17, 1, 16, 0]
3379       __ ilvr_b(dst, src1, src0);
3380       break;
3381     }
3382     case kMipsS8x16InterleaveLeft: {
3383       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3384       Simd128Register dst = i.OutputSimd128Register(),
3385                       src0 = i.InputSimd128Register(0),
3386                       src1 = i.InputSimd128Register(1);
3387       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3388       // dst = [31, 15, ... 25, 9, 24, 8]
3389       __ ilvl_b(dst, src1, src0);
3390       break;
3391     }
3392     case kMipsS8x16PackEven: {
3393       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3394       Simd128Register dst = i.OutputSimd128Register(),
3395                       src0 = i.InputSimd128Register(0),
3396                       src1 = i.InputSimd128Register(1);
3397       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3398       // dst = [30, 28, ... 6, 4, 2, 0]
3399       __ pckev_b(dst, src1, src0);
3400       break;
3401     }
3402     case kMipsS8x16PackOdd: {
3403       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3404       Simd128Register dst = i.OutputSimd128Register(),
3405                       src0 = i.InputSimd128Register(0),
3406                       src1 = i.InputSimd128Register(1);
3407       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3408       // dst = [31, 29, ... 7, 5, 3, 1]
3409       __ pckod_b(dst, src1, src0);
3410       break;
3411     }
3412     case kMipsS8x16InterleaveEven: {
3413       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3414       Simd128Register dst = i.OutputSimd128Register(),
3415                       src0 = i.InputSimd128Register(0),
3416                       src1 = i.InputSimd128Register(1);
3417       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3418       // dst = [30, 14, ... 18, 2, 16, 0]
3419       __ ilvev_b(dst, src1, src0);
3420       break;
3421     }
3422     case kMipsS8x16InterleaveOdd: {
3423       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3424       Simd128Register dst = i.OutputSimd128Register(),
3425                       src0 = i.InputSimd128Register(0),
3426                       src1 = i.InputSimd128Register(1);
3427       // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
3428       // dst = [31, 15, ... 19, 3, 17, 1]
3429       __ ilvod_b(dst, src1, src0);
3430       break;
3431     }
3432     case kMipsS8x16Concat: {
3433       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3434       Simd128Register dst = i.OutputSimd128Register();
3435       DCHECK(dst == i.InputSimd128Register(0));
3436       __ sldi_b(dst, i.InputSimd128Register(1), i.InputInt4(2));
3437       break;
3438     }
3439     case kMipsI8x16Shuffle: {
3440       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3441       Simd128Register dst = i.OutputSimd128Register(),
3442                       src0 = i.InputSimd128Register(0),
3443                       src1 = i.InputSimd128Register(1);
3444 
3445       if (dst == src0) {
3446         __ move_v(kSimd128ScratchReg, src0);
3447         src0 = kSimd128ScratchReg;
3448       } else if (dst == src1) {
3449         __ move_v(kSimd128ScratchReg, src1);
3450         src1 = kSimd128ScratchReg;
3451       }
3452 
3453       __ li(kScratchReg, i.InputInt32(2));
3454       __ insert_w(dst, 0, kScratchReg);
3455       __ li(kScratchReg, i.InputInt32(3));
3456       __ insert_w(dst, 1, kScratchReg);
3457       __ li(kScratchReg, i.InputInt32(4));
3458       __ insert_w(dst, 2, kScratchReg);
3459       __ li(kScratchReg, i.InputInt32(5));
3460       __ insert_w(dst, 3, kScratchReg);
3461       __ vshf_b(dst, src1, src0);
3462       break;
3463     }
3464     case kMipsI8x16Swizzle: {
3465       Simd128Register dst = i.OutputSimd128Register(),
3466                       tbl = i.InputSimd128Register(0),
3467                       ctl = i.InputSimd128Register(1);
3468       DCHECK(dst != ctl && dst != tbl);
3469       Simd128Register zeroReg = i.TempSimd128Register(0);
3470       __ fill_w(zeroReg, zero_reg);
3471       __ move_v(dst, ctl);
3472       __ vshf_b(dst, tbl, zeroReg);
3473       break;
3474     }
3475     case kMipsS8x8Reverse: {
3476       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3477       // src = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
3478       // dst = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]
3479       // [A B C D] => [B A D C]: shf.w imm: 2 3 0 1 = 10110001 = 0xB1
3480       // C: [7, 6, 5, 4] => A': [4, 5, 6, 7]: shf.b imm: 00011011 = 0x1B
3481       __ shf_w(kSimd128ScratchReg, i.InputSimd128Register(0), 0xB1);
3482       __ shf_b(i.OutputSimd128Register(), kSimd128ScratchReg, 0x1B);
3483       break;
3484     }
3485     case kMipsS8x4Reverse: {
3486       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3487       // src = [15, 14, ... 3, 2, 1, 0], dst = [12, 13, 14, 15, ... 0, 1, 2, 3]
3488       // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
3489       __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
3490       break;
3491     }
3492     case kMipsS8x2Reverse: {
3493       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3494       // src = [15, 14, ... 3, 2, 1, 0], dst = [14, 15, 12, 13, ... 2, 3, 0, 1]
3495       // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
3496       __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
3497       break;
3498     }
3499     case kMipsI32x4SConvertI16x8Low: {
3500       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3501       Simd128Register dst = i.OutputSimd128Register();
3502       Simd128Register src = i.InputSimd128Register(0);
3503       __ ilvr_h(kSimd128ScratchReg, src, src);
3504       __ slli_w(dst, kSimd128ScratchReg, 16);
3505       __ srai_w(dst, dst, 16);
3506       break;
3507     }
3508     case kMipsI32x4SConvertI16x8High: {
3509       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3510       Simd128Register dst = i.OutputSimd128Register();
3511       Simd128Register src = i.InputSimd128Register(0);
3512       __ ilvl_h(kSimd128ScratchReg, src, src);
3513       __ slli_w(dst, kSimd128ScratchReg, 16);
3514       __ srai_w(dst, dst, 16);
3515       break;
3516     }
3517     case kMipsI32x4UConvertI16x8Low: {
3518       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3519       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
3520       __ ilvr_h(i.OutputSimd128Register(), kSimd128RegZero,
3521                 i.InputSimd128Register(0));
3522       break;
3523     }
3524     case kMipsI32x4UConvertI16x8High: {
3525       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3526       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
3527       __ ilvl_h(i.OutputSimd128Register(), kSimd128RegZero,
3528                 i.InputSimd128Register(0));
3529       break;
3530     }
3531     case kMipsI16x8SConvertI8x16Low: {
3532       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3533       Simd128Register dst = i.OutputSimd128Register();
3534       Simd128Register src = i.InputSimd128Register(0);
3535       __ ilvr_b(kSimd128ScratchReg, src, src);
3536       __ slli_h(dst, kSimd128ScratchReg, 8);
3537       __ srai_h(dst, dst, 8);
3538       break;
3539     }
3540     case kMipsI16x8SConvertI8x16High: {
3541       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3542       Simd128Register dst = i.OutputSimd128Register();
3543       Simd128Register src = i.InputSimd128Register(0);
3544       __ ilvl_b(kSimd128ScratchReg, src, src);
3545       __ slli_h(dst, kSimd128ScratchReg, 8);
3546       __ srai_h(dst, dst, 8);
3547       break;
3548     }
3549     case kMipsI16x8SConvertI32x4: {
3550       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3551       Simd128Register dst = i.OutputSimd128Register();
3552       Simd128Register src0 = i.InputSimd128Register(0);
3553       Simd128Register src1 = i.InputSimd128Register(1);
3554       __ sat_s_w(kSimd128ScratchReg, src0, 15);
3555       __ sat_s_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
3556       __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
3557       break;
3558     }
3559     case kMipsI16x8UConvertI32x4: {
3560       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3561       Simd128Register dst = i.OutputSimd128Register();
3562       Simd128Register src0 = i.InputSimd128Register(0);
3563       Simd128Register src1 = i.InputSimd128Register(1);
3564       __ sat_u_w(kSimd128ScratchReg, src0, 15);
3565       __ sat_u_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
3566       __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
3567       break;
3568     }
3569     case kMipsI16x8UConvertI8x16Low: {
3570       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3571       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
3572       __ ilvr_b(i.OutputSimd128Register(), kSimd128RegZero,
3573                 i.InputSimd128Register(0));
3574       break;
3575     }
3576     case kMipsI16x8UConvertI8x16High: {
3577       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3578       __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
3579       __ ilvl_b(i.OutputSimd128Register(), kSimd128RegZero,
3580                 i.InputSimd128Register(0));
3581       break;
3582     }
3583     case kMipsI8x16SConvertI16x8: {
3584       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3585       Simd128Register dst = i.OutputSimd128Register();
3586       Simd128Register src0 = i.InputSimd128Register(0);
3587       Simd128Register src1 = i.InputSimd128Register(1);
3588       __ sat_s_h(kSimd128ScratchReg, src0, 7);
3589       __ sat_s_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
3590       __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
3591       break;
3592     }
3593     case kMipsI8x16UConvertI16x8: {
3594       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
3595       Simd128Register dst = i.OutputSimd128Register();
3596       Simd128Register src0 = i.InputSimd128Register(0);
3597       Simd128Register src1 = i.InputSimd128Register(1);
3598       __ sat_u_h(kSimd128ScratchReg, src0, 7);
3599       __ sat_u_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
3600       __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
3601       break;
3602     }
3603   }
3604   return kSuccess;
3605 }
3606 
AssembleBranchToLabels(CodeGenerator * gen,TurboAssembler * tasm,Instruction * instr,FlagsCondition condition,Label * tlabel,Label * flabel,bool fallthru)3607 void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
3608                             Instruction* instr, FlagsCondition condition,
3609                             Label* tlabel, Label* flabel, bool fallthru) {
3610 #undef __
3611 #define __ tasm->
3612 
3613   Condition cc = kNoCondition;
3614   // MIPS does not have condition code flags, so compare and branch are
3615   // implemented differently than on the other arch's. The compare operations
3616   // emit mips pseudo-instructions, which are handled here by branch
3617   // instructions that do the actual comparison. Essential that the input
3618   // registers to compare pseudo-op are not modified before this branch op, as
3619   // they are tested here.
3620 
3621   MipsOperandConverter i(gen, instr);
3622   if (instr->arch_opcode() == kMipsTst) {
3623     cc = FlagsConditionToConditionTst(condition);
3624     __ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
3625   } else if (instr->arch_opcode() == kMipsAddOvf ||
3626              instr->arch_opcode() == kMipsSubOvf) {
3627     // Overflow occurs if overflow register is negative
3628     switch (condition) {
3629       case kOverflow:
3630         __ Branch(tlabel, lt, kScratchReg, Operand(zero_reg));
3631         break;
3632       case kNotOverflow:
3633         __ Branch(tlabel, ge, kScratchReg, Operand(zero_reg));
3634         break;
3635       default:
3636         UNSUPPORTED_COND(instr->arch_opcode(), condition);
3637     }
3638   } else if (instr->arch_opcode() == kMipsMulOvf) {
3639     // Overflow occurs if overflow register is not zero
3640     switch (condition) {
3641       case kOverflow:
3642         __ Branch(tlabel, ne, kScratchReg, Operand(zero_reg));
3643         break;
3644       case kNotOverflow:
3645         __ Branch(tlabel, eq, kScratchReg, Operand(zero_reg));
3646         break;
3647       default:
3648         UNSUPPORTED_COND(kMipsMulOvf, condition);
3649     }
3650   } else if (instr->arch_opcode() == kMipsCmp) {
3651     cc = FlagsConditionToConditionCmp(condition);
3652     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
3653   } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
3654     cc = FlagsConditionToConditionCmp(condition);
3655     DCHECK((cc == ls) || (cc == hi));
3656     if (cc == ls) {
3657       __ xori(i.TempRegister(0), i.TempRegister(0), 1);
3658     }
3659     __ Branch(tlabel, ne, i.TempRegister(0), Operand(zero_reg));
3660   } else if (instr->arch_opcode() == kMipsCmpS ||
3661              instr->arch_opcode() == kMipsCmpD) {
3662     bool predicate;
3663     FlagsConditionToConditionCmpFPU(&predicate, condition);
3664     if (predicate) {
3665       __ BranchTrueF(tlabel);
3666     } else {
3667       __ BranchFalseF(tlabel);
3668     }
3669   } else {
3670     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
3671            instr->arch_opcode());
3672     UNIMPLEMENTED();
3673   }
3674   if (!fallthru) __ Branch(flabel);  // no fallthru to flabel.
3675 #undef __
3676 #define __ tasm()->
3677 }
3678 
3679 // Assembles branches after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)3680 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
3681   Label* tlabel = branch->true_label;
3682   Label* flabel = branch->false_label;
3683   AssembleBranchToLabels(this, tasm(), instr, branch->condition, tlabel, flabel,
3684                          branch->fallthru);
3685 }
3686 
AssembleArchDeoptBranch(Instruction * instr,BranchInfo * branch)3687 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
3688                                             BranchInfo* branch) {
3689   AssembleArchBranch(instr, branch);
3690 }
3691 
AssembleArchJump(RpoNumber target)3692 void CodeGenerator::AssembleArchJump(RpoNumber target) {
3693   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
3694 }
3695 
3696 #if V8_ENABLE_WEBASSEMBLY
AssembleArchTrap(Instruction * instr,FlagsCondition condition)3697 void CodeGenerator::AssembleArchTrap(Instruction* instr,
3698                                      FlagsCondition condition) {
3699   class OutOfLineTrap final : public OutOfLineCode {
3700    public:
3701     OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
3702         : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
3703 
3704     void Generate() final {
3705       MipsOperandConverter i(gen_, instr_);
3706       TrapId trap_id =
3707           static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
3708       GenerateCallToTrap(trap_id);
3709     }
3710 
3711    private:
3712     void GenerateCallToTrap(TrapId trap_id) {
3713       if (trap_id == TrapId::kInvalid) {
3714         // We cannot test calls to the runtime in cctest/test-run-wasm.
3715         // Therefore we emit a call to C here instead of a call to the runtime.
3716         // We use the context register as the scratch register, because we do
3717         // not have a context here.
3718         __ PrepareCallCFunction(0, 0, cp);
3719         __ CallCFunction(
3720             ExternalReference::wasm_call_trap_callback_for_testing(), 0);
3721         __ LeaveFrame(StackFrame::WASM);
3722         auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
3723         int pop_count = static_cast<int>(call_descriptor->ParameterSlotCount());
3724         __ Drop(pop_count);
3725         __ Ret();
3726       } else {
3727         gen_->AssembleSourcePosition(instr_);
3728         // A direct call to a wasm runtime stub defined in this module.
3729         // Just encode the stub index. This will be patched when the code
3730         // is added to the native module and copied into wasm code space.
3731         __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
3732         ReferenceMap* reference_map =
3733             gen_->zone()->New<ReferenceMap>(gen_->zone());
3734         gen_->RecordSafepoint(reference_map);
3735         if (FLAG_debug_code) {
3736           __ stop();
3737         }
3738       }
3739     }
3740 
3741     Instruction* instr_;
3742     CodeGenerator* gen_;
3743   };
3744   auto ool = zone()->New<OutOfLineTrap>(this, instr);
3745   Label* tlabel = ool->entry();
3746   AssembleBranchToLabels(this, tasm(), instr, condition, tlabel, nullptr, true);
3747 }
3748 #endif  // V8_ENABLE_WEBASSEMBLY
3749 
3750 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)3751 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
3752                                         FlagsCondition condition) {
3753   MipsOperandConverter i(this, instr);
3754 
3755   // Materialize a full 32-bit 1 or 0 value. The result register is always the
3756   // last output of the instruction.
3757   DCHECK_NE(0u, instr->OutputCount());
3758   Register result = i.OutputRegister(instr->OutputCount() - 1);
3759   Condition cc = kNoCondition;
3760   // MIPS does not have condition code flags, so compare and branch are
3761   // implemented differently than on the other arch's. The compare operations
3762   // emit mips pseudo-instructions, which are checked and handled here.
3763 
3764   if (instr->arch_opcode() == kMipsTst) {
3765     cc = FlagsConditionToConditionTst(condition);
3766     if (cc == eq) {
3767       __ Sltu(result, kScratchReg, 1);
3768     } else {
3769       __ Sltu(result, zero_reg, kScratchReg);
3770     }
3771     return;
3772   } else if (instr->arch_opcode() == kMipsAddOvf ||
3773              instr->arch_opcode() == kMipsSubOvf) {
3774     // Overflow occurs if overflow register is negative
3775     __ slt(result, kScratchReg, zero_reg);
3776   } else if (instr->arch_opcode() == kMipsMulOvf) {
3777     // Overflow occurs if overflow register is not zero
3778     __ Sgtu(result, kScratchReg, zero_reg);
3779   } else if (instr->arch_opcode() == kMipsCmp) {
3780     cc = FlagsConditionToConditionCmp(condition);
3781     switch (cc) {
3782       case eq:
3783       case ne: {
3784         Register left = i.InputRegister(0);
3785         Operand right = i.InputOperand(1);
3786         if (instr->InputAt(1)->IsImmediate()) {
3787           if (is_int16(-right.immediate())) {
3788             if (right.immediate() == 0) {
3789               if (cc == eq) {
3790                 __ Sltu(result, left, 1);
3791               } else {
3792                 __ Sltu(result, zero_reg, left);
3793               }
3794             } else {
3795               __ Addu(result, left, -right.immediate());
3796               if (cc == eq) {
3797                 __ Sltu(result, result, 1);
3798               } else {
3799                 __ Sltu(result, zero_reg, result);
3800               }
3801             }
3802           } else {
3803             if (is_uint16(right.immediate())) {
3804               __ Xor(result, left, right);
3805             } else {
3806               __ li(kScratchReg, right);
3807               __ Xor(result, left, kScratchReg);
3808             }
3809             if (cc == eq) {
3810               __ Sltu(result, result, 1);
3811             } else {
3812               __ Sltu(result, zero_reg, result);
3813             }
3814           }
3815         } else {
3816           __ Xor(result, left, right);
3817           if (cc == eq) {
3818             __ Sltu(result, result, 1);
3819           } else {
3820             __ Sltu(result, zero_reg, result);
3821           }
3822         }
3823       } break;
3824       case lt:
3825       case ge: {
3826         Register left = i.InputRegister(0);
3827         Operand right = i.InputOperand(1);
3828         __ Slt(result, left, right);
3829         if (cc == ge) {
3830           __ xori(result, result, 1);
3831         }
3832       } break;
3833       case gt:
3834       case le: {
3835         Register left = i.InputRegister(1);
3836         Operand right = i.InputOperand(0);
3837         __ Slt(result, left, right);
3838         if (cc == le) {
3839           __ xori(result, result, 1);
3840         }
3841       } break;
3842       case lo:
3843       case hs: {
3844         Register left = i.InputRegister(0);
3845         Operand right = i.InputOperand(1);
3846         __ Sltu(result, left, right);
3847         if (cc == hs) {
3848           __ xori(result, result, 1);
3849         }
3850       } break;
3851       case hi:
3852       case ls: {
3853         Register left = i.InputRegister(1);
3854         Operand right = i.InputOperand(0);
3855         __ Sltu(result, left, right);
3856         if (cc == ls) {
3857           __ xori(result, result, 1);
3858         }
3859       } break;
3860       default:
3861         UNREACHABLE();
3862     }
3863     return;
3864   } else if (instr->arch_opcode() == kMipsCmpD ||
3865              instr->arch_opcode() == kMipsCmpS) {
3866     FPURegister left = i.InputOrZeroDoubleRegister(0);
3867     FPURegister right = i.InputOrZeroDoubleRegister(1);
3868     if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
3869         !__ IsDoubleZeroRegSet()) {
3870       __ Move(kDoubleRegZero, 0.0);
3871     }
3872     bool predicate;
3873     FlagsConditionToConditionCmpFPU(&predicate, condition);
3874     if (!IsMipsArchVariant(kMips32r6)) {
3875       __ li(result, Operand(1));
3876       if (predicate) {
3877         __ Movf(result, zero_reg);
3878       } else {
3879         __ Movt(result, zero_reg);
3880       }
3881     } else {
3882       __ mfc1(result, kDoubleCompareReg);
3883       if (predicate) {
3884         __ And(result, result, 1);  // cmp returns all 1's/0's, use only LSB.
3885       } else {
3886         __ Addu(result, result, 1);  // Toggle result for not equal.
3887       }
3888     }
3889     return;
3890   } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
3891     cc = FlagsConditionToConditionCmp(condition);
3892     DCHECK((cc == ls) || (cc == hi));
3893     if (cc == ls) {
3894       __ xori(i.OutputRegister(), i.TempRegister(0), 1);
3895     }
3896     return;
3897   } else {
3898     PrintF("AssembleArchBoolean Unimplemented arch_opcode is : %d\n",
3899            instr->arch_opcode());
3900     TRACE_UNIMPL();
3901     UNIMPLEMENTED();
3902   }
3903 }
3904 
AssembleArchBinarySearchSwitch(Instruction * instr)3905 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
3906   MipsOperandConverter i(this, instr);
3907   Register input = i.InputRegister(0);
3908   std::vector<std::pair<int32_t, Label*>> cases;
3909   for (size_t index = 2; index < instr->InputCount(); index += 2) {
3910     cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
3911   }
3912   AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
3913                                       cases.data() + cases.size());
3914 }
3915 
AssembleArchTableSwitch(Instruction * instr)3916 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
3917   MipsOperandConverter i(this, instr);
3918   Register input = i.InputRegister(0);
3919   size_t const case_count = instr->InputCount() - 2;
3920   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
3921   __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
3922     return GetLabel(i.InputRpo(index + 2));
3923   });
3924 }
3925 
AssembleArchSelect(Instruction * instr,FlagsCondition condition)3926 void CodeGenerator::AssembleArchSelect(Instruction* instr,
3927                                        FlagsCondition condition) {
3928   UNIMPLEMENTED();
3929 }
3930 
FinishFrame(Frame * frame)3931 void CodeGenerator::FinishFrame(Frame* frame) {
3932   auto call_descriptor = linkage()->GetIncomingDescriptor();
3933 
3934   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3935   if (saves_fpu != 0) {
3936     frame->AlignSavedCalleeRegisterSlots();
3937   }
3938 
3939   if (saves_fpu != 0) {
3940     int count = base::bits::CountPopulation(saves_fpu);
3941     DCHECK_EQ(kNumCalleeSavedFPU, count);
3942     frame->AllocateSavedCalleeRegisterSlots(count *
3943                                             (kDoubleSize / kSystemPointerSize));
3944   }
3945 
3946   const RegList saves = call_descriptor->CalleeSavedRegisters();
3947   if (saves != 0) {
3948     int count = base::bits::CountPopulation(saves);
3949     frame->AllocateSavedCalleeRegisterSlots(count);
3950   }
3951 }
3952 
AssembleConstructFrame()3953 void CodeGenerator::AssembleConstructFrame() {
3954   auto call_descriptor = linkage()->GetIncomingDescriptor();
3955   if (frame_access_state()->has_frame()) {
3956     if (call_descriptor->IsCFunctionCall()) {
3957 #if V8_ENABLE_WEBASSEMBLY
3958       if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) {
3959         __ StubPrologue(StackFrame::C_WASM_ENTRY);
3960         // Reserve stack space for saving the c_entry_fp later.
3961         __ Subu(sp, sp, Operand(kSystemPointerSize));
3962 #else
3963       // For balance.
3964       if (false) {
3965 #endif  // V8_ENABLE_WEBASSEMBLY
3966       } else {
3967         __ Push(ra, fp);
3968         __ mov(fp, sp);
3969       }
3970     } else if (call_descriptor->IsJSFunctionCall()) {
3971       __ Prologue();
3972     } else {
3973       __ StubPrologue(info()->GetOutputStackFrameType());
3974 #if V8_ENABLE_WEBASSEMBLY
3975       if (call_descriptor->IsWasmFunctionCall()) {
3976         __ Push(kWasmInstanceRegister);
3977       } else if (call_descriptor->IsWasmImportWrapper() ||
3978                  call_descriptor->IsWasmCapiFunction()) {
3979         // Wasm import wrappers are passed a tuple in the place of the instance.
3980         // Unpack the tuple into the instance and the target callable.
3981         // This must be done here in the codegen because it cannot be expressed
3982         // properly in the graph.
3983         __ lw(kJSFunctionRegister,
3984               FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue2Offset));
3985         __ lw(kWasmInstanceRegister,
3986               FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset));
3987         __ Push(kWasmInstanceRegister);
3988         if (call_descriptor->IsWasmCapiFunction()) {
3989           // Reserve space for saving the PC later.
3990           __ Subu(sp, sp, Operand(kSystemPointerSize));
3991         }
3992       }
3993 #endif  // V8_ENABLE_WEBASSEMBLY
3994     }
3995   }
3996 
3997   int required_slots =
3998       frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount();
3999 
4000   if (info()->is_osr()) {
4001     // TurboFan OSR-compiled functions cannot be entered directly.
4002     __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
4003 
4004     // Unoptimized code jumps directly to this entrypoint while the unoptimized
4005     // frame is still on the stack. Optimized code uses OSR values directly from
4006     // the unoptimized frame. Thus, all that needs to be done is to allocate the
4007     // remaining stack slots.
4008     __ RecordComment("-- OSR entrypoint --");
4009     osr_pc_offset_ = __ pc_offset();
4010     required_slots -= osr_helper()->UnoptimizedFrameSlots();
4011   }
4012 
4013   const RegList saves = call_descriptor->CalleeSavedRegisters();
4014   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
4015 
4016   if (required_slots > 0) {
4017     DCHECK(frame_access_state()->has_frame());
4018 #if V8_ENABLE_WEBASSEMBLY
4019     if (info()->IsWasm() && required_slots * kSystemPointerSize > 4 * KB) {
4020       // For WebAssembly functions with big frames we have to do the stack
4021       // overflow check before we construct the frame. Otherwise we may not
4022       // have enough space on the stack to call the runtime for the stack
4023       // overflow.
4024       Label done;
4025 
4026       // If the frame is bigger than the stack, we throw the stack overflow
4027       // exception unconditionally. Thereby we can avoid the integer overflow
4028       // check in the condition code.
4029       if (required_slots * kSystemPointerSize < FLAG_stack_size * KB) {
4030         __ Lw(
4031              kScratchReg,
4032              FieldMemOperand(kWasmInstanceRegister,
4033                              WasmInstanceObject::kRealStackLimitAddressOffset));
4034         __ Lw(kScratchReg, MemOperand(kScratchReg));
4035         __ Addu(kScratchReg, kScratchReg,
4036                       Operand(required_slots * kSystemPointerSize));
4037         __ Branch(&done, uge, sp, Operand(kScratchReg));
4038       }
4039 
4040       __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
4041       // The call does not return, hence we can ignore any references and just
4042       // define an empty safepoint.
4043       ReferenceMap* reference_map = zone()->New<ReferenceMap>(zone());
4044       RecordSafepoint(reference_map);
4045       if (FLAG_debug_code) __ stop();
4046 
4047       __ bind(&done);
4048     }
4049 #endif  // V8_ENABLE_WEBASSEMBLY
4050   }
4051 
4052   const int returns = frame()->GetReturnSlotCount();
4053 
4054   // Skip callee-saved and return slots, which are pushed below.
4055   required_slots -= base::bits::CountPopulation(saves);
4056   required_slots -= 2 * base::bits::CountPopulation(saves_fpu);
4057   required_slots -= returns;
4058   if (required_slots > 0) {
4059     __ Subu(sp, sp, Operand(required_slots * kSystemPointerSize));
4060   }
4061 
4062   // Save callee-saved FPU registers.
4063   if (saves_fpu != 0) {
4064     __ MultiPushFPU(saves_fpu);
4065   }
4066 
4067   if (saves != 0) {
4068     // Save callee-saved registers.
4069     __ MultiPush(saves);
4070   }
4071 
4072   if (returns != 0) {
4073     // Create space for returns.
4074     __ Subu(sp, sp, Operand(returns * kSystemPointerSize));
4075   }
4076 }
4077 
4078 void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
4079   auto call_descriptor = linkage()->GetIncomingDescriptor();
4080 
4081   const int returns = frame()->GetReturnSlotCount();
4082   if (returns != 0) {
4083     __ Addu(sp, sp, Operand(returns * kSystemPointerSize));
4084   }
4085 
4086   // Restore GP registers.
4087   const RegList saves = call_descriptor->CalleeSavedRegisters();
4088   if (saves != 0) {
4089     __ MultiPop(saves);
4090   }
4091 
4092   // Restore FPU registers.
4093   const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
4094   if (saves_fpu != 0) {
4095     __ MultiPopFPU(saves_fpu);
4096   }
4097 
4098   MipsOperandConverter g(this, nullptr);
4099   const int parameter_slots =
4100       static_cast<int>(call_descriptor->ParameterSlotCount());
4101 
4102   // {aditional_pop_count} is only greater than zero if {parameter_slots = 0}.
4103   // Check RawMachineAssembler::PopAndReturn.
4104   if (parameter_slots != 0) {
4105     if (additional_pop_count->IsImmediate()) {
4106       DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
4107     } else if (FLAG_debug_code) {
4108       __ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue,
4109                 g.ToRegister(additional_pop_count),
4110                 Operand(static_cast<int64_t>(0)));
4111     }
4112   }
4113   // Functions with JS linkage have at least one parameter (the receiver).
4114   // If {parameter_slots} == 0, it means it is a builtin with
4115   // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
4116   // itself.
4117   const bool drop_jsargs = frame_access_state()->has_frame() &&
4118                            call_descriptor->IsJSFunctionCall() &&
4119                            parameter_slots != 0;
4120 
4121   if (call_descriptor->IsCFunctionCall()) {
4122     AssembleDeconstructFrame();
4123   } else if (frame_access_state()->has_frame()) {
4124     // Canonicalize JSFunction return sites for now unless they have an variable
4125     // number of stack slot pops.
4126     if (additional_pop_count->IsImmediate() &&
4127         g.ToConstant(additional_pop_count).ToInt32() == 0) {
4128       if (return_label_.is_bound()) {
4129         __ Branch(&return_label_);
4130         return;
4131       } else {
4132         __ bind(&return_label_);
4133       }
4134     }
4135     if (drop_jsargs) {
4136       // Get the actual argument count
4137       __ Lw(t0, MemOperand(fp, StandardFrameConstants::kArgCOffset));
4138     }
4139     AssembleDeconstructFrame();
4140   }
4141 
4142   if (drop_jsargs) {
4143     // We must pop all arguments from the stack (including the receiver). This
4144     // number of arguments is given by max(1 + argc_reg, parameter_slots).
4145     __ Addu(t0, t0, Operand(1));  // Also pop the receiver.
4146     if (parameter_slots > 1) {
4147       __ li(kScratchReg, parameter_slots);
4148       __ slt(kScratchReg2, t0, kScratchReg);
4149       __ movn(t0, kScratchReg, kScratchReg2);
4150     }
4151     __ sll(t0, t0, kSystemPointerSizeLog2);
4152     __ Addu(sp, sp, t0);
4153   } else if (additional_pop_count->IsImmediate()) {
4154     DCHECK_EQ(Constant::kInt32, g.ToConstant(additional_pop_count).type());
4155     int additional_count = g.ToConstant(additional_pop_count).ToInt32();
4156     __ Drop(parameter_slots + additional_count);
4157   } else {
4158     Register pop_reg = g.ToRegister(additional_pop_count);
4159     __ Drop(parameter_slots);
4160     __ sll(pop_reg, pop_reg, kSystemPointerSizeLog2);
4161     __ Addu(sp, sp, pop_reg);
4162   }
4163   __ Ret();
4164 }
4165 
4166 void CodeGenerator::FinishCode() {}
4167 
4168 void CodeGenerator::PrepareForDeoptimizationExits(
4169     ZoneDeque<DeoptimizationExit*>* exits) {}
4170 
4171 void CodeGenerator::AssembleMove(InstructionOperand* source,
4172                                  InstructionOperand* destination) {
4173   MipsOperandConverter g(this, nullptr);
4174   // Dispatch on the source and destination operand kinds.  Not all
4175   // combinations are possible.
4176   if (source->IsRegister()) {
4177     DCHECK(destination->IsRegister() || destination->IsStackSlot());
4178     Register src = g.ToRegister(source);
4179     if (destination->IsRegister()) {
4180       __ mov(g.ToRegister(destination), src);
4181     } else {
4182       __ sw(src, g.ToMemOperand(destination));
4183     }
4184   } else if (source->IsStackSlot()) {
4185     DCHECK(destination->IsRegister() || destination->IsStackSlot());
4186     MemOperand src = g.ToMemOperand(source);
4187     if (destination->IsRegister()) {
4188       __ lw(g.ToRegister(destination), src);
4189     } else {
4190       Register temp = kScratchReg;
4191       __ lw(temp, src);
4192       __ sw(temp, g.ToMemOperand(destination));
4193     }
4194   } else if (source->IsConstant()) {
4195     Constant src = g.ToConstant(source);
4196     if (destination->IsRegister() || destination->IsStackSlot()) {
4197       Register dst =
4198           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
4199       switch (src.type()) {
4200         case Constant::kInt32:
4201 #if V8_ENABLE_WEBASSEMBLY
4202           if (RelocInfo::IsWasmReference(src.rmode()))
4203             __ li(dst, Operand(src.ToInt32(), src.rmode()));
4204           else
4205 #endif  // V8_ENABLE_WEBASSEMBLY
4206             __ li(dst, Operand(src.ToInt32()));
4207           break;
4208         case Constant::kFloat32:
4209           __ li(dst, Operand::EmbeddedNumber(src.ToFloat32()));
4210           break;
4211         case Constant::kInt64:
4212           UNREACHABLE();
4213         case Constant::kFloat64:
4214           __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
4215           break;
4216         case Constant::kExternalReference:
4217           __ li(dst, src.ToExternalReference());
4218           break;
4219         case Constant::kDelayedStringConstant:
4220           __ li(dst, src.ToDelayedStringConstant());
4221           break;
4222         case Constant::kHeapObject: {
4223           Handle<HeapObject> src_object = src.ToHeapObject();
4224           RootIndex index;
4225           if (IsMaterializableFromRoot(src_object, &index)) {
4226             __ LoadRoot(dst, index);
4227           } else {
4228             __ li(dst, src_object);
4229           }
4230           break;
4231         }
4232         case Constant::kCompressedHeapObject:
4233           UNREACHABLE();
4234         case Constant::kRpoNumber:
4235           UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips.
4236       }
4237       if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
4238     } else if (src.type() == Constant::kFloat32) {
4239       if (destination->IsFPStackSlot()) {
4240         MemOperand dst = g.ToMemOperand(destination);
4241         if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
4242           __ sw(zero_reg, dst);
4243         } else {
4244           __ li(kScratchReg, Operand(bit_cast<int32_t>(src.ToFloat32())));
4245           __ sw(kScratchReg, dst);
4246         }
4247       } else {
4248         DCHECK(destination->IsFPRegister());
4249         FloatRegister dst = g.ToSingleRegister(destination);
4250         __ Move(dst, src.ToFloat32());
4251       }
4252     } else {
4253       DCHECK_EQ(Constant::kFloat64, src.type());
4254       DoubleRegister dst = destination->IsFPRegister()
4255                                ? g.ToDoubleRegister(destination)
4256                                : kScratchDoubleReg;
4257       __ Move(dst, src.ToFloat64().value());
4258       if (destination->IsFPStackSlot()) {
4259         __ Sdc1(dst, g.ToMemOperand(destination));
4260       }
4261     }
4262   } else if (source->IsFPRegister()) {
4263     MachineRepresentation rep = LocationOperand::cast(source)->representation();
4264     if (rep == MachineRepresentation::kSimd128) {
4265       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4266       MSARegister src = g.ToSimd128Register(source);
4267       if (destination->IsSimd128Register()) {
4268         MSARegister dst = g.ToSimd128Register(destination);
4269         __ move_v(dst, src);
4270       } else {
4271         DCHECK(destination->IsSimd128StackSlot());
4272         __ st_b(src, g.ToMemOperand(destination));
4273       }
4274     } else {
4275       FPURegister src = g.ToDoubleRegister(source);
4276       if (destination->IsFPRegister()) {
4277         FPURegister dst = g.ToDoubleRegister(destination);
4278         __ Move(dst, src);
4279       } else {
4280         DCHECK(destination->IsFPStackSlot());
4281         MachineRepresentation rep =
4282             LocationOperand::cast(source)->representation();
4283         if (rep == MachineRepresentation::kFloat64) {
4284           __ Sdc1(src, g.ToMemOperand(destination));
4285         } else if (rep == MachineRepresentation::kFloat32) {
4286           __ swc1(src, g.ToMemOperand(destination));
4287         } else {
4288           UNREACHABLE();
4289         }
4290       }
4291     }
4292   } else if (source->IsFPStackSlot()) {
4293     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
4294     MemOperand src = g.ToMemOperand(source);
4295     MachineRepresentation rep = LocationOperand::cast(source)->representation();
4296     if (destination->IsFPRegister()) {
4297       if (rep == MachineRepresentation::kFloat64) {
4298         __ Ldc1(g.ToDoubleRegister(destination), src);
4299       } else if (rep == MachineRepresentation::kFloat32) {
4300         __ lwc1(g.ToDoubleRegister(destination), src);
4301       } else {
4302         DCHECK_EQ(MachineRepresentation::kSimd128, rep);
4303         CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4304         __ ld_b(g.ToSimd128Register(destination), src);
4305       }
4306     } else {
4307       FPURegister temp = kScratchDoubleReg;
4308       if (rep == MachineRepresentation::kFloat64) {
4309         __ Ldc1(temp, src);
4310         __ Sdc1(temp, g.ToMemOperand(destination));
4311       } else if (rep == MachineRepresentation::kFloat32) {
4312         __ lwc1(temp, src);
4313         __ swc1(temp, g.ToMemOperand(destination));
4314       } else {
4315         DCHECK_EQ(MachineRepresentation::kSimd128, rep);
4316         CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4317         MSARegister temp = kSimd128ScratchReg;
4318         __ ld_b(temp, src);
4319         __ st_b(temp, g.ToMemOperand(destination));
4320       }
4321     }
4322   } else {
4323     UNREACHABLE();
4324   }
4325 }
4326 
4327 void CodeGenerator::AssembleSwap(InstructionOperand* source,
4328                                  InstructionOperand* destination) {
4329   MipsOperandConverter g(this, nullptr);
4330   // Dispatch on the source and destination operand kinds.  Not all
4331   // combinations are possible.
4332   if (source->IsRegister()) {
4333     // Register-register.
4334     Register temp = kScratchReg;
4335     Register src = g.ToRegister(source);
4336     if (destination->IsRegister()) {
4337       Register dst = g.ToRegister(destination);
4338       __ Move(temp, src);
4339       __ Move(src, dst);
4340       __ Move(dst, temp);
4341     } else {
4342       DCHECK(destination->IsStackSlot());
4343       MemOperand dst = g.ToMemOperand(destination);
4344       __ mov(temp, src);
4345       __ lw(src, dst);
4346       __ sw(temp, dst);
4347     }
4348   } else if (source->IsStackSlot()) {
4349     DCHECK(destination->IsStackSlot());
4350     Register temp_0 = kScratchReg;
4351     Register temp_1 = kScratchReg2;
4352     MemOperand src = g.ToMemOperand(source);
4353     MemOperand dst = g.ToMemOperand(destination);
4354     __ lw(temp_0, src);
4355     __ lw(temp_1, dst);
4356     __ sw(temp_0, dst);
4357     __ sw(temp_1, src);
4358   } else if (source->IsFPRegister()) {
4359     if (destination->IsFPRegister()) {
4360       MachineRepresentation rep =
4361           LocationOperand::cast(source)->representation();
4362       if (rep == MachineRepresentation::kSimd128) {
4363         CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4364         MSARegister temp = kSimd128ScratchReg;
4365         MSARegister src = g.ToSimd128Register(source);
4366         MSARegister dst = g.ToSimd128Register(destination);
4367         __ move_v(temp, src);
4368         __ move_v(src, dst);
4369         __ move_v(dst, temp);
4370       } else {
4371         FPURegister temp = kScratchDoubleReg;
4372         FPURegister src = g.ToDoubleRegister(source);
4373         FPURegister dst = g.ToDoubleRegister(destination);
4374         __ Move(temp, src);
4375         __ Move(src, dst);
4376         __ Move(dst, temp);
4377       }
4378     } else {
4379       DCHECK(destination->IsFPStackSlot());
4380       MemOperand dst = g.ToMemOperand(destination);
4381       MachineRepresentation rep =
4382           LocationOperand::cast(source)->representation();
4383       if (rep == MachineRepresentation::kFloat64) {
4384         FPURegister temp = kScratchDoubleReg;
4385         FPURegister src = g.ToDoubleRegister(source);
4386         __ Move(temp, src);
4387         __ Ldc1(src, dst);
4388         __ Sdc1(temp, dst);
4389       } else if (rep == MachineRepresentation::kFloat32) {
4390         FPURegister temp = kScratchDoubleReg;
4391         FPURegister src = g.ToFloatRegister(source);
4392         __ Move(temp, src);
4393         __ lwc1(src, dst);
4394         __ swc1(temp, dst);
4395       } else {
4396         DCHECK_EQ(MachineRepresentation::kSimd128, rep);
4397         CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4398         MSARegister temp = kSimd128ScratchReg;
4399         MSARegister src = g.ToSimd128Register(source);
4400         __ move_v(temp, src);
4401         __ ld_b(src, dst);
4402         __ st_b(temp, dst);
4403       }
4404     }
4405   } else if (source->IsFPStackSlot()) {
4406     DCHECK(destination->IsFPStackSlot());
4407     Register temp_0 = kScratchReg;
4408     FPURegister temp_1 = kScratchDoubleReg;
4409     MemOperand src0 = g.ToMemOperand(source);
4410     MemOperand dst0 = g.ToMemOperand(destination);
4411     MachineRepresentation rep = LocationOperand::cast(source)->representation();
4412     if (rep == MachineRepresentation::kFloat64) {
4413       MemOperand src1(src0.rm(), src0.offset() + kIntSize);
4414       MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
4415       __ Ldc1(temp_1, dst0);  // Save destination in temp_1.
4416       __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
4417       __ sw(temp_0, dst0);
4418       __ lw(temp_0, src1);
4419       __ sw(temp_0, dst1);
4420       __ Sdc1(temp_1, src0);
4421     } else if (rep == MachineRepresentation::kFloat32) {
4422       __ lwc1(temp_1, dst0);  // Save destination in temp_1.
4423       __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
4424       __ sw(temp_0, dst0);
4425       __ swc1(temp_1, src0);
4426     } else {
4427       DCHECK_EQ(MachineRepresentation::kSimd128, rep);
4428       MemOperand src1(src0.rm(), src0.offset() + kIntSize);
4429       MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
4430       MemOperand src2(src0.rm(), src0.offset() + 2 * kIntSize);
4431       MemOperand dst2(dst0.rm(), dst0.offset() + 2 * kIntSize);
4432       MemOperand src3(src0.rm(), src0.offset() + 3 * kIntSize);
4433       MemOperand dst3(dst0.rm(), dst0.offset() + 3 * kIntSize);
4434       CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
4435       MSARegister temp_1 = kSimd128ScratchReg;
4436       __ ld_b(temp_1, dst0);  // Save destination in temp_1.
4437       __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
4438       __ sw(temp_0, dst0);
4439       __ lw(temp_0, src1);
4440       __ sw(temp_0, dst1);
4441       __ lw(temp_0, src2);
4442       __ sw(temp_0, dst2);
4443       __ lw(temp_0, src3);
4444       __ sw(temp_0, dst3);
4445       __ st_b(temp_1, src0);
4446     }
4447   } else {
4448     // No other combinations are possible.
4449     UNREACHABLE();
4450   }
4451 }
4452 
4453 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
4454   // On 32-bit MIPS we emit the jump tables inline.
4455   UNREACHABLE();
4456 }
4457 
4458 #undef __
4459 #undef ASSEMBLE_F64X2_ARITHMETIC_BINOP
4460 #undef ASSEMBLE_SIMD_EXTENDED_MULTIPLY
4461 
4462 }  // namespace compiler
4463 }  // namespace internal
4464 }  // namespace v8
4465