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