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