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