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