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/compiler/code-generator.h"
6#include "src/compilation-info.h"
7#include "src/compiler/code-generator-impl.h"
8#include "src/compiler/gap-resolver.h"
9#include "src/compiler/node-matchers.h"
10#include "src/compiler/osr.h"
11#include "src/mips/macro-assembler-mips.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17#define __ masm()->
18
19
20// TODO(plind): Possibly avoid using these lithium names.
21#define kScratchReg kLithiumScratchReg
22#define kScratchReg2 kLithiumScratchReg2
23#define kScratchDoubleReg kLithiumScratchDouble
24
25
26// TODO(plind): consider renaming these macros.
27#define TRACE_MSG(msg)                                                      \
28  PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
29         __LINE__)
30
31#define TRACE_UNIMPL()                                                       \
32  PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
33         __LINE__)
34
35
36// Adds Mips-specific methods to convert InstructionOperands.
37class MipsOperandConverter final : public InstructionOperandConverter {
38 public:
39  MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
40      : InstructionOperandConverter(gen, instr) {}
41
42  FloatRegister OutputSingleRegister(size_t index = 0) {
43    return ToSingleRegister(instr_->OutputAt(index));
44  }
45
46  FloatRegister InputSingleRegister(size_t index) {
47    return ToSingleRegister(instr_->InputAt(index));
48  }
49
50  FloatRegister ToSingleRegister(InstructionOperand* op) {
51    // Single (Float) and Double register namespace is same on MIPS,
52    // both are typedefs of FPURegister.
53    return ToDoubleRegister(op);
54  }
55
56  Register InputOrZeroRegister(size_t index) {
57    if (instr_->InputAt(index)->IsImmediate()) {
58      DCHECK((InputInt32(index) == 0));
59      return zero_reg;
60    }
61    return InputRegister(index);
62  }
63
64  DoubleRegister InputOrZeroDoubleRegister(size_t index) {
65    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
66
67    return InputDoubleRegister(index);
68  }
69
70  DoubleRegister InputOrZeroSingleRegister(size_t index) {
71    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
72
73    return InputSingleRegister(index);
74  }
75
76  Operand InputImmediate(size_t index) {
77    Constant constant = ToConstant(instr_->InputAt(index));
78    switch (constant.type()) {
79      case Constant::kInt32:
80        return Operand(constant.ToInt32());
81      case Constant::kInt64:
82        return Operand(constant.ToInt64());
83      case Constant::kFloat32:
84        return Operand(
85            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
86      case Constant::kFloat64:
87        return Operand(
88            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
89      case Constant::kExternalReference:
90      case Constant::kHeapObject:
91        // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
92        //    maybe not done on arm due to const pool ??
93        break;
94      case Constant::kRpoNumber:
95        UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
96        break;
97    }
98    UNREACHABLE();
99    return Operand(zero_reg);
100  }
101
102  Operand InputOperand(size_t index) {
103    InstructionOperand* op = instr_->InputAt(index);
104    if (op->IsRegister()) {
105      return Operand(ToRegister(op));
106    }
107    return InputImmediate(index);
108  }
109
110  MemOperand MemoryOperand(size_t* first_index) {
111    const size_t index = *first_index;
112    switch (AddressingModeField::decode(instr_->opcode())) {
113      case kMode_None:
114        break;
115      case kMode_MRI:
116        *first_index += 2;
117        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
118      case kMode_MRR:
119        // TODO(plind): r6 address mode, to be implemented ...
120        UNREACHABLE();
121    }
122    UNREACHABLE();
123    return MemOperand(no_reg);
124  }
125
126  MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
127
128  MemOperand ToMemOperand(InstructionOperand* op) const {
129    DCHECK_NOT_NULL(op);
130    DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
131    return SlotToMemOperand(AllocatedOperand::cast(op)->index());
132  }
133
134  MemOperand SlotToMemOperand(int slot) const {
135    FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
136    return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
137  }
138};
139
140
141static inline bool HasRegisterInput(Instruction* instr, size_t index) {
142  return instr->InputAt(index)->IsRegister();
143}
144
145
146namespace {
147
148class OutOfLineLoadSingle final : public OutOfLineCode {
149 public:
150  OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
151      : OutOfLineCode(gen), result_(result) {}
152
153  void Generate() final {
154    __ Move(result_, std::numeric_limits<float>::quiet_NaN());
155  }
156
157 private:
158  FloatRegister const result_;
159};
160
161
162class OutOfLineLoadDouble final : public OutOfLineCode {
163 public:
164  OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
165      : OutOfLineCode(gen), result_(result) {}
166
167  void Generate() final {
168    __ Move(result_, std::numeric_limits<double>::quiet_NaN());
169  }
170
171 private:
172  DoubleRegister const result_;
173};
174
175
176class OutOfLineLoadInteger final : public OutOfLineCode {
177 public:
178  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
179      : OutOfLineCode(gen), result_(result) {}
180
181  void Generate() final { __ mov(result_, zero_reg); }
182
183 private:
184  Register const result_;
185};
186
187
188class OutOfLineRound : public OutOfLineCode {
189 public:
190  OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
191      : OutOfLineCode(gen), result_(result) {}
192
193  void Generate() final {
194    // Handle rounding to zero case where sign has to be preserved.
195    // High bits of double input already in kScratchReg.
196    __ dsrl(at, kScratchReg, 31);
197    __ dsll(at, at, 31);
198    __ mthc1(at, result_);
199  }
200
201 private:
202  DoubleRegister const result_;
203};
204
205
206class OutOfLineRound32 : public OutOfLineCode {
207 public:
208  OutOfLineRound32(CodeGenerator* gen, DoubleRegister result)
209      : OutOfLineCode(gen), result_(result) {}
210
211  void Generate() final {
212    // Handle rounding to zero case where sign has to be preserved.
213    // High bits of float input already in kScratchReg.
214    __ srl(at, kScratchReg, 31);
215    __ sll(at, at, 31);
216    __ mtc1(at, result_);
217  }
218
219 private:
220  DoubleRegister const result_;
221};
222
223
224class OutOfLineRecordWrite final : public OutOfLineCode {
225 public:
226  OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
227                       Register value, Register scratch0, Register scratch1,
228                       RecordWriteMode mode)
229      : OutOfLineCode(gen),
230        object_(object),
231        index_(index),
232        value_(value),
233        scratch0_(scratch0),
234        scratch1_(scratch1),
235        mode_(mode),
236        must_save_lr_(!gen->frame_access_state()->has_frame()) {}
237
238  void Generate() final {
239    if (mode_ > RecordWriteMode::kValueIsPointer) {
240      __ JumpIfSmi(value_, exit());
241    }
242    __ CheckPageFlag(value_, scratch0_,
243                     MemoryChunk::kPointersToHereAreInterestingMask, eq,
244                     exit());
245    RememberedSetAction const remembered_set_action =
246        mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
247                                             : OMIT_REMEMBERED_SET;
248    SaveFPRegsMode const save_fp_mode =
249        frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
250    if (must_save_lr_) {
251      // We need to save and restore ra if the frame was elided.
252      __ Push(ra);
253    }
254    RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
255                         remembered_set_action, save_fp_mode);
256    __ Daddu(scratch1_, object_, index_);
257    __ CallStub(&stub);
258    if (must_save_lr_) {
259      __ Pop(ra);
260    }
261  }
262
263 private:
264  Register const object_;
265  Register const index_;
266  Register const value_;
267  Register const scratch0_;
268  Register const scratch1_;
269  RecordWriteMode const mode_;
270  bool must_save_lr_;
271};
272
273#define CREATE_OOL_CLASS(ool_name, masm_ool_name, T)                 \
274  class ool_name final : public OutOfLineCode {                      \
275   public:                                                           \
276    ool_name(CodeGenerator* gen, T dst, T src1, T src2)              \
277        : OutOfLineCode(gen), dst_(dst), src1_(src1), src2_(src2) {} \
278                                                                     \
279    void Generate() final { __ masm_ool_name(dst_, src1_, src2_); }  \
280                                                                     \
281   private:                                                          \
282    T const dst_;                                                    \
283    T const src1_;                                                   \
284    T const src2_;                                                   \
285  }
286
287CREATE_OOL_CLASS(OutOfLineFloat32Max, Float32MaxOutOfLine, FPURegister);
288CREATE_OOL_CLASS(OutOfLineFloat32Min, Float32MinOutOfLine, FPURegister);
289CREATE_OOL_CLASS(OutOfLineFloat64Max, Float64MaxOutOfLine, FPURegister);
290CREATE_OOL_CLASS(OutOfLineFloat64Min, Float64MinOutOfLine, FPURegister);
291
292#undef CREATE_OOL_CLASS
293
294Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
295  switch (condition) {
296    case kEqual:
297      return eq;
298    case kNotEqual:
299      return ne;
300    case kSignedLessThan:
301      return lt;
302    case kSignedGreaterThanOrEqual:
303      return ge;
304    case kSignedLessThanOrEqual:
305      return le;
306    case kSignedGreaterThan:
307      return gt;
308    case kUnsignedLessThan:
309      return lo;
310    case kUnsignedGreaterThanOrEqual:
311      return hs;
312    case kUnsignedLessThanOrEqual:
313      return ls;
314    case kUnsignedGreaterThan:
315      return hi;
316    case kUnorderedEqual:
317    case kUnorderedNotEqual:
318      break;
319    default:
320      break;
321  }
322  UNREACHABLE();
323  return kNoCondition;
324}
325
326
327Condition FlagsConditionToConditionTst(FlagsCondition condition) {
328  switch (condition) {
329    case kNotEqual:
330      return ne;
331    case kEqual:
332      return eq;
333    default:
334      break;
335  }
336  UNREACHABLE();
337  return kNoCondition;
338}
339
340
341Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
342  switch (condition) {
343    case kOverflow:
344      return ne;
345    case kNotOverflow:
346      return eq;
347    default:
348      break;
349  }
350  UNREACHABLE();
351  return kNoCondition;
352}
353
354
355FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
356                                             FlagsCondition condition) {
357  switch (condition) {
358    case kEqual:
359      predicate = true;
360      return EQ;
361    case kNotEqual:
362      predicate = false;
363      return EQ;
364    case kUnsignedLessThan:
365      predicate = true;
366      return OLT;
367    case kUnsignedGreaterThanOrEqual:
368      predicate = false;
369      return ULT;
370    case kUnsignedLessThanOrEqual:
371      predicate = true;
372      return OLE;
373    case kUnsignedGreaterThan:
374      predicate = false;
375      return ULE;
376    case kUnorderedEqual:
377    case kUnorderedNotEqual:
378      predicate = true;
379      break;
380    default:
381      predicate = true;
382      break;
383  }
384  UNREACHABLE();
385  return kNoFPUCondition;
386}
387
388}  // namespace
389#define ASSEMBLE_BOUNDS_CHECK_REGISTER(offset, length, out_of_bounds)         \
390  do {                                                                        \
391    if (!length.is_reg() && base::bits::IsPowerOfTwo64(length.immediate())) { \
392      __ And(kScratchReg, offset, Operand(~(length.immediate() - 1)));        \
393      __ Branch(USE_DELAY_SLOT, out_of_bounds, ne, kScratchReg,               \
394                Operand(zero_reg));                                           \
395    } else {                                                                  \
396      __ Branch(USE_DELAY_SLOT, out_of_bounds, hs, offset, length);           \
397    }                                                                         \
398  } while (0)
399
400#define ASSEMBLE_BOUNDS_CHECK_IMMEDIATE(offset, length, out_of_bounds)        \
401  do {                                                                        \
402    if (!length.is_reg() && base::bits::IsPowerOfTwo64(length.immediate())) { \
403      __ Or(kScratchReg, zero_reg, Operand(offset));                          \
404      __ And(kScratchReg, kScratchReg, Operand(~(length.immediate() - 1)));   \
405      __ Branch(out_of_bounds, ne, kScratchReg, Operand(zero_reg));           \
406    } else {                                                                  \
407      __ Branch(out_of_bounds, ls, length.rm(), Operand(offset));             \
408    }                                                                         \
409  } while (0)
410
411#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                          \
412  do {                                                                         \
413    auto result = i.Output##width##Register();                                 \
414    auto ool = new (zone()) OutOfLineLoad##width(this, result);                \
415    if (instr->InputAt(0)->IsRegister()) {                                     \
416      auto offset = i.InputRegister(0);                                        \
417      ASSEMBLE_BOUNDS_CHECK_REGISTER(offset, i.InputOperand(1), ool->entry()); \
418      __ And(kScratchReg, offset, Operand(0xffffffff));                        \
419      __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg);                  \
420      __ asm_instr(result, MemOperand(kScratchReg, 0));                        \
421    } else {                                                                   \
422      int offset = static_cast<int>(i.InputOperand(0).immediate());            \
423      ASSEMBLE_BOUNDS_CHECK_IMMEDIATE(offset, i.InputOperand(1),               \
424                                      ool->entry());                           \
425      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));            \
426    }                                                                          \
427    __ bind(ool->exit());                                                      \
428  } while (0)
429
430#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                               \
431  do {                                                                         \
432    auto result = i.OutputRegister();                                          \
433    auto ool = new (zone()) OutOfLineLoadInteger(this, result);                \
434    if (instr->InputAt(0)->IsRegister()) {                                     \
435      auto offset = i.InputRegister(0);                                        \
436      ASSEMBLE_BOUNDS_CHECK_REGISTER(offset, i.InputOperand(1), ool->entry()); \
437      __ And(kScratchReg, offset, Operand(0xffffffff));                        \
438      __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg);                  \
439      __ asm_instr(result, MemOperand(kScratchReg, 0));                        \
440    } else {                                                                   \
441      int offset = static_cast<int>(i.InputOperand(0).immediate());            \
442      ASSEMBLE_BOUNDS_CHECK_IMMEDIATE(offset, i.InputOperand(1),               \
443                                      ool->entry());                           \
444      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));            \
445    }                                                                          \
446    __ bind(ool->exit());                                                      \
447  } while (0)
448
449#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                   \
450  do {                                                                   \
451    Label done;                                                          \
452    if (instr->InputAt(0)->IsRegister()) {                               \
453      auto offset = i.InputRegister(0);                                  \
454      auto value = i.InputOrZero##width##Register(2);                    \
455      if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {        \
456        __ Move(kDoubleRegZero, 0.0);                                    \
457      }                                                                  \
458      ASSEMBLE_BOUNDS_CHECK_REGISTER(offset, i.InputOperand(1), &done);  \
459      __ And(kScratchReg, offset, Operand(0xffffffff));                  \
460      __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg);            \
461      __ asm_instr(value, MemOperand(kScratchReg, 0));                   \
462    } else {                                                             \
463      int offset = static_cast<int>(i.InputOperand(0).immediate());      \
464      auto value = i.InputOrZero##width##Register(2);                    \
465      if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {        \
466        __ Move(kDoubleRegZero, 0.0);                                    \
467      }                                                                  \
468      ASSEMBLE_BOUNDS_CHECK_IMMEDIATE(offset, i.InputOperand(1), &done); \
469      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));       \
470    }                                                                    \
471    __ bind(&done);                                                      \
472  } while (0)
473
474#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                        \
475  do {                                                                   \
476    Label done;                                                          \
477    if (instr->InputAt(0)->IsRegister()) {                               \
478      auto offset = i.InputRegister(0);                                  \
479      auto value = i.InputOrZeroRegister(2);                             \
480      ASSEMBLE_BOUNDS_CHECK_REGISTER(offset, i.InputOperand(1), &done);  \
481      __ And(kScratchReg, offset, Operand(0xffffffff));                  \
482      __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg);            \
483      __ asm_instr(value, MemOperand(kScratchReg, 0));                   \
484    } else {                                                             \
485      int offset = static_cast<int>(i.InputOperand(0).immediate());      \
486      auto value = i.InputOrZeroRegister(2);                             \
487      ASSEMBLE_BOUNDS_CHECK_IMMEDIATE(offset, i.InputOperand(1), &done); \
488      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));       \
489    }                                                                    \
490    __ bind(&done);                                                      \
491  } while (0)
492
493#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode)                                  \
494  if (kArchVariant == kMips64r6) {                                             \
495    __ cfc1(kScratchReg, FCSR);                                                \
496    __ li(at, Operand(mode_##mode));                                           \
497    __ ctc1(at, FCSR);                                                         \
498    __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
499    __ ctc1(kScratchReg, FCSR);                                                \
500  } else {                                                                     \
501    auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister());    \
502    Label done;                                                                \
503    __ mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
504    __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
505           HeapNumber::kExponentBits);                                         \
506    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
507              Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
508    __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
509    __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));         \
510    __ dmfc1(at, i.OutputDoubleRegister());                                    \
511    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
512    __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
513    __ bind(ool->exit());                                                      \
514    __ bind(&done);                                                            \
515  }
516
517#define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode)                                   \
518  if (kArchVariant == kMips64r6) {                                            \
519    __ cfc1(kScratchReg, FCSR);                                               \
520    __ li(at, Operand(mode_##mode));                                          \
521    __ ctc1(at, FCSR);                                                        \
522    __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));            \
523    __ ctc1(kScratchReg, FCSR);                                               \
524  } else {                                                                    \
525    int32_t kFloat32ExponentBias = 127;                                       \
526    int32_t kFloat32MantissaBits = 23;                                        \
527    int32_t kFloat32ExponentBits = 8;                                         \
528    auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
529    Label done;                                                               \
530    __ mfc1(kScratchReg, i.InputDoubleRegister(0));                           \
531    __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits);      \
532    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                  \
533              Operand(kFloat32ExponentBias + kFloat32MantissaBits));          \
534    __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
535    __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));        \
536    __ mfc1(at, i.OutputDoubleRegister());                                    \
537    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));       \
538    __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister());           \
539    __ bind(ool->exit());                                                     \
540    __ bind(&done);                                                           \
541  }
542
543#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
544  do {                                                   \
545    __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
546    __ sync();                                           \
547  } while (0)
548
549#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)               \
550  do {                                                         \
551    __ sync();                                                 \
552    __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
553    __ sync();                                                 \
554  } while (0)
555
556#define ASSEMBLE_IEEE754_BINOP(name)                                          \
557  do {                                                                        \
558    FrameScope scope(masm(), StackFrame::MANUAL);                             \
559    __ PrepareCallCFunction(0, 2, kScratchReg);                               \
560    __ MovToFloatParameters(i.InputDoubleRegister(0),                         \
561                            i.InputDoubleRegister(1));                        \
562    __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
563                     0, 2);                                                   \
564    /* Move the result in the double result register. */                      \
565    __ MovFromFloatResult(i.OutputDoubleRegister());                          \
566  } while (0)
567
568#define ASSEMBLE_IEEE754_UNOP(name)                                           \
569  do {                                                                        \
570    FrameScope scope(masm(), StackFrame::MANUAL);                             \
571    __ PrepareCallCFunction(0, 1, kScratchReg);                               \
572    __ MovToFloatParameter(i.InputDoubleRegister(0));                         \
573    __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
574                     0, 1);                                                   \
575    /* Move the result in the double result register. */                      \
576    __ MovFromFloatResult(i.OutputDoubleRegister());                          \
577  } while (0)
578
579void CodeGenerator::AssembleDeconstructFrame() {
580  __ mov(sp, fp);
581  __ Pop(ra, fp);
582}
583
584void CodeGenerator::AssemblePrepareTailCall() {
585  if (frame_access_state()->has_frame()) {
586    __ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
587    __ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
588  }
589  frame_access_state()->SetFrameAccessToSP();
590}
591
592void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
593                                                     Register scratch1,
594                                                     Register scratch2,
595                                                     Register scratch3) {
596  DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
597  Label done;
598
599  // Check if current frame is an arguments adaptor frame.
600  __ ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset));
601  __ Branch(&done, ne, scratch3,
602            Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
603
604  // Load arguments count from current arguments adaptor frame (note, it
605  // does not include receiver).
606  Register caller_args_count_reg = scratch1;
607  __ ld(caller_args_count_reg,
608        MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
609  __ SmiUntag(caller_args_count_reg);
610
611  ParameterCount callee_args_count(args_reg);
612  __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
613                        scratch3);
614  __ bind(&done);
615}
616
617namespace {
618
619void AdjustStackPointerForTailCall(MacroAssembler* masm,
620                                   FrameAccessState* state,
621                                   int new_slot_above_sp,
622                                   bool allow_shrinkage = true) {
623  int current_sp_offset = state->GetSPToFPSlotCount() +
624                          StandardFrameConstants::kFixedSlotCountAboveFp;
625  int stack_slot_delta = new_slot_above_sp - current_sp_offset;
626  if (stack_slot_delta > 0) {
627    masm->Dsubu(sp, sp, stack_slot_delta * kPointerSize);
628    state->IncreaseSPDelta(stack_slot_delta);
629  } else if (allow_shrinkage && stack_slot_delta < 0) {
630    masm->Daddu(sp, sp, -stack_slot_delta * kPointerSize);
631    state->IncreaseSPDelta(stack_slot_delta);
632  }
633}
634
635}  // namespace
636
637void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
638                                              int first_unused_stack_slot) {
639  AdjustStackPointerForTailCall(masm(), frame_access_state(),
640                                first_unused_stack_slot, false);
641}
642
643void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
644                                             int first_unused_stack_slot) {
645  AdjustStackPointerForTailCall(masm(), frame_access_state(),
646                                first_unused_stack_slot);
647}
648
649// Assembles an instruction after register allocation, producing machine code.
650CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
651    Instruction* instr) {
652  MipsOperandConverter i(this, instr);
653  InstructionCode opcode = instr->opcode();
654  ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
655  switch (arch_opcode) {
656    case kArchCallCodeObject: {
657      EnsureSpaceForLazyDeopt();
658      if (instr->InputAt(0)->IsImmediate()) {
659        __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
660                RelocInfo::CODE_TARGET);
661      } else {
662        __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
663        __ Call(at);
664      }
665      RecordCallPosition(instr);
666      frame_access_state()->ClearSPDelta();
667      break;
668    }
669    case kArchTailCallCodeObjectFromJSFunction:
670    case kArchTailCallCodeObject: {
671      if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
672        AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
673                                         i.TempRegister(0), i.TempRegister(1),
674                                         i.TempRegister(2));
675      }
676      if (instr->InputAt(0)->IsImmediate()) {
677        __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
678                RelocInfo::CODE_TARGET);
679      } else {
680        __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
681        __ Jump(at);
682      }
683      frame_access_state()->ClearSPDelta();
684      frame_access_state()->SetFrameAccessToDefault();
685      break;
686    }
687    case kArchTailCallAddress: {
688      CHECK(!instr->InputAt(0)->IsImmediate());
689      __ Jump(i.InputRegister(0));
690      frame_access_state()->ClearSPDelta();
691      frame_access_state()->SetFrameAccessToDefault();
692      break;
693    }
694    case kArchCallJSFunction: {
695      EnsureSpaceForLazyDeopt();
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, kWrongFunctionContext, cp, Operand(kScratchReg));
701      }
702      __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
703      __ Call(at);
704      RecordCallPosition(instr);
705      frame_access_state()->ClearSPDelta();
706      break;
707    }
708    case kArchTailCallJSFunctionFromJSFunction: {
709      Register func = i.InputRegister(0);
710      if (FLAG_debug_code) {
711        // Check the function's context matches the context argument.
712        __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
713        __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
714      }
715      AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
716                                       i.TempRegister(0), i.TempRegister(1),
717                                       i.TempRegister(2));
718      __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
719      __ Jump(at);
720      frame_access_state()->ClearSPDelta();
721      frame_access_state()->SetFrameAccessToDefault();
722      break;
723    }
724    case kArchPrepareCallCFunction: {
725      int const num_parameters = MiscField::decode(instr->opcode());
726      __ PrepareCallCFunction(num_parameters, kScratchReg);
727      // Frame alignment requires using FP-relative frame addressing.
728      frame_access_state()->SetFrameAccessToFP();
729      break;
730    }
731    case kArchPrepareTailCall:
732      AssemblePrepareTailCall();
733      break;
734    case kArchCallCFunction: {
735      int const num_parameters = MiscField::decode(instr->opcode());
736      if (instr->InputAt(0)->IsImmediate()) {
737        ExternalReference ref = i.InputExternalReference(0);
738        __ CallCFunction(ref, num_parameters);
739      } else {
740        Register func = i.InputRegister(0);
741        __ CallCFunction(func, num_parameters);
742      }
743      frame_access_state()->SetFrameAccessToDefault();
744      frame_access_state()->ClearSPDelta();
745      break;
746    }
747    case kArchJmp:
748      AssembleArchJump(i.InputRpo(0));
749      break;
750    case kArchLookupSwitch:
751      AssembleArchLookupSwitch(instr);
752      break;
753    case kArchTableSwitch:
754      AssembleArchTableSwitch(instr);
755      break;
756    case kArchDebugBreak:
757      __ stop("kArchDebugBreak");
758      break;
759    case kArchComment: {
760      Address comment_string = i.InputExternalReference(0).address();
761      __ RecordComment(reinterpret_cast<const char*>(comment_string));
762      break;
763    }
764    case kArchNop:
765    case kArchThrowTerminator:
766      // don't emit code for nops.
767      break;
768    case kArchDeoptimize: {
769      int deopt_state_id =
770          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
771      CodeGenResult result =
772          AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
773      if (result != kSuccess) return result;
774      break;
775    }
776    case kArchRet:
777      AssembleReturn(instr->InputAt(0));
778      break;
779    case kArchStackPointer:
780      __ mov(i.OutputRegister(), sp);
781      break;
782    case kArchFramePointer:
783      __ mov(i.OutputRegister(), fp);
784      break;
785    case kArchParentFramePointer:
786      if (frame_access_state()->has_frame()) {
787        __ ld(i.OutputRegister(), MemOperand(fp, 0));
788      } else {
789        __ mov(i.OutputRegister(), fp);
790      }
791      break;
792    case kArchTruncateDoubleToI:
793      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
794      break;
795    case kArchStoreWithWriteBarrier: {
796      RecordWriteMode mode =
797          static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
798      Register object = i.InputRegister(0);
799      Register index = i.InputRegister(1);
800      Register value = i.InputRegister(2);
801      Register scratch0 = i.TempRegister(0);
802      Register scratch1 = i.TempRegister(1);
803      auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
804                                                   scratch0, scratch1, mode);
805      __ Daddu(at, object, index);
806      __ sd(value, MemOperand(at));
807      __ CheckPageFlag(object, scratch0,
808                       MemoryChunk::kPointersFromHereAreInterestingMask, ne,
809                       ool->entry());
810      __ bind(ool->exit());
811      break;
812    }
813    case kArchStackSlot: {
814      FrameOffset offset =
815          frame_access_state()->GetFrameOffset(i.InputInt32(0));
816      __ Daddu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
817               Operand(offset.offset()));
818      break;
819    }
820    case kIeee754Float64Acos:
821      ASSEMBLE_IEEE754_UNOP(acos);
822      break;
823    case kIeee754Float64Acosh:
824      ASSEMBLE_IEEE754_UNOP(acosh);
825      break;
826    case kIeee754Float64Asin:
827      ASSEMBLE_IEEE754_UNOP(asin);
828      break;
829    case kIeee754Float64Asinh:
830      ASSEMBLE_IEEE754_UNOP(asinh);
831      break;
832    case kIeee754Float64Atan:
833      ASSEMBLE_IEEE754_UNOP(atan);
834      break;
835    case kIeee754Float64Atanh:
836      ASSEMBLE_IEEE754_UNOP(atanh);
837      break;
838    case kIeee754Float64Atan2:
839      ASSEMBLE_IEEE754_BINOP(atan2);
840      break;
841    case kIeee754Float64Cos:
842      ASSEMBLE_IEEE754_UNOP(cos);
843      break;
844    case kIeee754Float64Cosh:
845      ASSEMBLE_IEEE754_UNOP(cosh);
846      break;
847    case kIeee754Float64Cbrt:
848      ASSEMBLE_IEEE754_UNOP(cbrt);
849      break;
850    case kIeee754Float64Exp:
851      ASSEMBLE_IEEE754_UNOP(exp);
852      break;
853    case kIeee754Float64Expm1:
854      ASSEMBLE_IEEE754_UNOP(expm1);
855      break;
856    case kIeee754Float64Log:
857      ASSEMBLE_IEEE754_UNOP(log);
858      break;
859    case kIeee754Float64Log1p:
860      ASSEMBLE_IEEE754_UNOP(log1p);
861      break;
862    case kIeee754Float64Log2:
863      ASSEMBLE_IEEE754_UNOP(log2);
864      break;
865    case kIeee754Float64Log10:
866      ASSEMBLE_IEEE754_UNOP(log10);
867      break;
868    case kIeee754Float64Pow: {
869      MathPowStub stub(isolate(), MathPowStub::DOUBLE);
870      __ CallStub(&stub);
871      break;
872    }
873    case kIeee754Float64Sin:
874      ASSEMBLE_IEEE754_UNOP(sin);
875      break;
876    case kIeee754Float64Sinh:
877      ASSEMBLE_IEEE754_UNOP(sinh);
878      break;
879    case kIeee754Float64Tan:
880      ASSEMBLE_IEEE754_UNOP(tan);
881      break;
882    case kIeee754Float64Tanh:
883      ASSEMBLE_IEEE754_UNOP(tanh);
884      break;
885    case kMips64Add:
886      __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
887      break;
888    case kMips64Dadd:
889      __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
890      break;
891    case kMips64DaddOvf:
892      // Pseudo-instruction used for overflow/branch. No opcode emitted here.
893      break;
894    case kMips64Sub:
895      __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
896      break;
897    case kMips64Dsub:
898      __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
899      break;
900    case kMips64DsubOvf:
901      // Pseudo-instruction used for overflow/branch. No opcode emitted here.
902      break;
903    case kMips64Mul:
904      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
905      break;
906    case kMips64MulOvf:
907      // Pseudo-instruction used for overflow/branch. No opcode emitted here.
908      break;
909    case kMips64MulHigh:
910      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
911      break;
912    case kMips64MulHighU:
913      __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
914      break;
915    case kMips64DMulHigh:
916      __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
917      break;
918    case kMips64Div:
919      __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
920      if (kArchVariant == kMips64r6) {
921        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
922      } else {
923        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
924      }
925      break;
926    case kMips64DivU:
927      __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
928      if (kArchVariant == kMips64r6) {
929        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
930      } else {
931        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
932      }
933      break;
934    case kMips64Mod:
935      __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
936      break;
937    case kMips64ModU:
938      __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
939      break;
940    case kMips64Dmul:
941      __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
942      break;
943    case kMips64Ddiv:
944      __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
945      if (kArchVariant == kMips64r6) {
946        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
947      } else {
948        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
949      }
950      break;
951    case kMips64DdivU:
952      __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
953      if (kArchVariant == kMips64r6) {
954        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
955      } else {
956        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
957      }
958      break;
959    case kMips64Dmod:
960      __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
961      break;
962    case kMips64DmodU:
963      __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
964      break;
965    case kMips64Dlsa:
966      DCHECK(instr->InputAt(2)->IsImmediate());
967      __ Dlsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
968              i.InputInt8(2));
969      break;
970    case kMips64Lsa:
971      DCHECK(instr->InputAt(2)->IsImmediate());
972      __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
973             i.InputInt8(2));
974      break;
975    case kMips64And:
976      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
977      break;
978    case kMips64And32:
979      if (instr->InputAt(1)->IsRegister()) {
980        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
981        __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
982        __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
983      } else {
984        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
985        __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
986      }
987      break;
988    case kMips64Or:
989      __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
990      break;
991    case kMips64Or32:
992      if (instr->InputAt(1)->IsRegister()) {
993        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
994        __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
995        __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
996      } else {
997        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
998        __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
999      }
1000      break;
1001    case kMips64Nor:
1002      if (instr->InputAt(1)->IsRegister()) {
1003        __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1004      } else {
1005        DCHECK(i.InputOperand(1).immediate() == 0);
1006        __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1007      }
1008      break;
1009    case kMips64Nor32:
1010      if (instr->InputAt(1)->IsRegister()) {
1011        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1012        __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1013        __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1014      } else {
1015        DCHECK(i.InputOperand(1).immediate() == 0);
1016        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1017        __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1018      }
1019      break;
1020    case kMips64Xor:
1021      __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1022      break;
1023    case kMips64Xor32:
1024      if (instr->InputAt(1)->IsRegister()) {
1025        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1026        __ sll(i.InputRegister(1), i.InputRegister(1), 0x0);
1027        __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1028      } else {
1029        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1030        __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1031      }
1032      break;
1033    case kMips64Clz:
1034      __ Clz(i.OutputRegister(), i.InputRegister(0));
1035      break;
1036    case kMips64Dclz:
1037      __ dclz(i.OutputRegister(), i.InputRegister(0));
1038      break;
1039    case kMips64Ctz: {
1040      Register reg1 = kScratchReg;
1041      Register reg2 = kScratchReg2;
1042      Label skip_for_zero;
1043      Label end;
1044      // Branch if the operand is zero
1045      __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
1046      // Find the number of bits before the last bit set to 1.
1047      __ Subu(reg2, zero_reg, i.InputRegister(0));
1048      __ And(reg2, reg2, i.InputRegister(0));
1049      __ clz(reg2, reg2);
1050      // Get the number of bits after the last bit set to 1.
1051      __ li(reg1, 0x1F);
1052      __ Subu(i.OutputRegister(), reg1, reg2);
1053      __ Branch(&end);
1054      __ bind(&skip_for_zero);
1055      // If the operand is zero, return word length as the result.
1056      __ li(i.OutputRegister(), 0x20);
1057      __ bind(&end);
1058    } break;
1059    case kMips64Dctz: {
1060      Register reg1 = kScratchReg;
1061      Register reg2 = kScratchReg2;
1062      Label skip_for_zero;
1063      Label end;
1064      // Branch if the operand is zero
1065      __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
1066      // Find the number of bits before the last bit set to 1.
1067      __ Dsubu(reg2, zero_reg, i.InputRegister(0));
1068      __ And(reg2, reg2, i.InputRegister(0));
1069      __ dclz(reg2, reg2);
1070      // Get the number of bits after the last bit set to 1.
1071      __ li(reg1, 0x3F);
1072      __ Subu(i.OutputRegister(), reg1, reg2);
1073      __ Branch(&end);
1074      __ bind(&skip_for_zero);
1075      // If the operand is zero, return word length as the result.
1076      __ li(i.OutputRegister(), 0x40);
1077      __ bind(&end);
1078    } break;
1079    case kMips64Popcnt: {
1080      Register reg1 = kScratchReg;
1081      Register reg2 = kScratchReg2;
1082      uint32_t m1 = 0x55555555;
1083      uint32_t m2 = 0x33333333;
1084      uint32_t m4 = 0x0f0f0f0f;
1085      uint32_t m8 = 0x00ff00ff;
1086      uint32_t m16 = 0x0000ffff;
1087
1088      // Put count of ones in every 2 bits into those 2 bits.
1089      __ li(at, m1);
1090      __ dsrl(reg1, i.InputRegister(0), 1);
1091      __ And(reg2, i.InputRegister(0), at);
1092      __ And(reg1, reg1, at);
1093      __ Daddu(reg1, reg1, reg2);
1094
1095      // Put count of ones in every 4 bits into those 4 bits.
1096      __ li(at, m2);
1097      __ dsrl(reg2, reg1, 2);
1098      __ And(reg2, reg2, at);
1099      __ And(reg1, reg1, at);
1100      __ Daddu(reg1, reg1, reg2);
1101
1102      // Put count of ones in every 8 bits into those 8 bits.
1103      __ li(at, m4);
1104      __ dsrl(reg2, reg1, 4);
1105      __ And(reg2, reg2, at);
1106      __ And(reg1, reg1, at);
1107      __ Daddu(reg1, reg1, reg2);
1108
1109      // Put count of ones in every 16 bits into those 16 bits.
1110      __ li(at, m8);
1111      __ dsrl(reg2, reg1, 8);
1112      __ And(reg2, reg2, at);
1113      __ And(reg1, reg1, at);
1114      __ Daddu(reg1, reg1, reg2);
1115
1116      // Calculate total number of ones.
1117      __ li(at, m16);
1118      __ dsrl(reg2, reg1, 16);
1119      __ And(reg2, reg2, at);
1120      __ And(reg1, reg1, at);
1121      __ Daddu(i.OutputRegister(), reg1, reg2);
1122    } break;
1123    case kMips64Dpopcnt: {
1124      Register reg1 = kScratchReg;
1125      Register reg2 = kScratchReg2;
1126      uint64_t m1 = 0x5555555555555555;
1127      uint64_t m2 = 0x3333333333333333;
1128      uint64_t m4 = 0x0f0f0f0f0f0f0f0f;
1129      uint64_t m8 = 0x00ff00ff00ff00ff;
1130      uint64_t m16 = 0x0000ffff0000ffff;
1131      uint64_t m32 = 0x00000000ffffffff;
1132
1133      // Put count of ones in every 2 bits into those 2 bits.
1134      __ li(at, m1);
1135      __ dsrl(reg1, i.InputRegister(0), 1);
1136      __ and_(reg2, i.InputRegister(0), at);
1137      __ and_(reg1, reg1, at);
1138      __ Daddu(reg1, reg1, reg2);
1139
1140      // Put count of ones in every 4 bits into those 4 bits.
1141      __ li(at, m2);
1142      __ dsrl(reg2, reg1, 2);
1143      __ and_(reg2, reg2, at);
1144      __ and_(reg1, reg1, at);
1145      __ Daddu(reg1, reg1, reg2);
1146
1147      // Put count of ones in every 8 bits into those 8 bits.
1148      __ li(at, m4);
1149      __ dsrl(reg2, reg1, 4);
1150      __ and_(reg2, reg2, at);
1151      __ and_(reg1, reg1, at);
1152      __ Daddu(reg1, reg1, reg2);
1153
1154      // Put count of ones in every 16 bits into those 16 bits.
1155      __ li(at, m8);
1156      __ dsrl(reg2, reg1, 8);
1157      __ and_(reg2, reg2, at);
1158      __ and_(reg1, reg1, at);
1159      __ Daddu(reg1, reg1, reg2);
1160
1161      // Put count of ones in every 32 bits into those 32 bits.
1162      __ li(at, m16);
1163      __ dsrl(reg2, reg1, 16);
1164      __ and_(reg2, reg2, at);
1165      __ and_(reg1, reg1, at);
1166      __ Daddu(reg1, reg1, reg2);
1167
1168      // Calculate total number of ones.
1169      __ li(at, m32);
1170      __ dsrl32(reg2, reg1, 0);
1171      __ and_(reg2, reg2, at);
1172      __ and_(reg1, reg1, at);
1173      __ Daddu(i.OutputRegister(), reg1, reg2);
1174    } break;
1175    case kMips64Shl:
1176      if (instr->InputAt(1)->IsRegister()) {
1177        __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1178      } else {
1179        int64_t imm = i.InputOperand(1).immediate();
1180        __ sll(i.OutputRegister(), i.InputRegister(0),
1181               static_cast<uint16_t>(imm));
1182      }
1183      break;
1184    case kMips64Shr:
1185      if (instr->InputAt(1)->IsRegister()) {
1186        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1187        __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1188      } else {
1189        int64_t imm = i.InputOperand(1).immediate();
1190        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1191        __ srl(i.OutputRegister(), i.InputRegister(0),
1192               static_cast<uint16_t>(imm));
1193      }
1194      break;
1195    case kMips64Sar:
1196      if (instr->InputAt(1)->IsRegister()) {
1197        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1198        __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1199      } else {
1200        int64_t imm = i.InputOperand(1).immediate();
1201        __ sll(i.InputRegister(0), i.InputRegister(0), 0x0);
1202        __ sra(i.OutputRegister(), i.InputRegister(0),
1203               static_cast<uint16_t>(imm));
1204      }
1205      break;
1206    case kMips64Ext:
1207      __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1208             i.InputInt8(2));
1209      break;
1210    case kMips64Ins:
1211      if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1212        __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1213      } else {
1214        __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1215               i.InputInt8(2));
1216      }
1217      break;
1218    case kMips64Dext: {
1219      int16_t pos = i.InputInt8(1);
1220      int16_t size = i.InputInt8(2);
1221      if (size > 0 && size <= 32 && pos >= 0 && pos < 32) {
1222        __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1223                i.InputInt8(2));
1224      } else if (size > 32 && size <= 64 && pos > 0 && pos < 32) {
1225        __ Dextm(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1226                 i.InputInt8(2));
1227      } else {
1228        DCHECK(size > 0 && size <= 32 && pos >= 32 && pos < 64);
1229        __ Dextu(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1230                 i.InputInt8(2));
1231      }
1232      break;
1233    }
1234    case kMips64Dins:
1235      if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1236        __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1237      } else {
1238        __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1239                i.InputInt8(2));
1240      }
1241      break;
1242    case kMips64Dshl:
1243      if (instr->InputAt(1)->IsRegister()) {
1244        __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1245      } else {
1246        int64_t imm = i.InputOperand(1).immediate();
1247        if (imm < 32) {
1248          __ dsll(i.OutputRegister(), i.InputRegister(0),
1249                  static_cast<uint16_t>(imm));
1250        } else {
1251          __ dsll32(i.OutputRegister(), i.InputRegister(0),
1252                    static_cast<uint16_t>(imm - 32));
1253        }
1254      }
1255      break;
1256    case kMips64Dshr:
1257      if (instr->InputAt(1)->IsRegister()) {
1258        __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1259      } else {
1260        int64_t imm = i.InputOperand(1).immediate();
1261        if (imm < 32) {
1262          __ dsrl(i.OutputRegister(), i.InputRegister(0),
1263                  static_cast<uint16_t>(imm));
1264        } else {
1265          __ dsrl32(i.OutputRegister(), i.InputRegister(0),
1266                    static_cast<uint16_t>(imm - 32));
1267        }
1268      }
1269      break;
1270    case kMips64Dsar:
1271      if (instr->InputAt(1)->IsRegister()) {
1272        __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1273      } else {
1274        int64_t imm = i.InputOperand(1).immediate();
1275        if (imm < 32) {
1276          __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
1277        } else {
1278          __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
1279        }
1280      }
1281      break;
1282    case kMips64Ror:
1283      __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1284      break;
1285    case kMips64Dror:
1286      __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1287      break;
1288    case kMips64Tst:
1289      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1290      break;
1291    case kMips64Cmp:
1292      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1293      break;
1294    case kMips64Mov:
1295      // TODO(plind): Should we combine mov/li like this, or use separate instr?
1296      //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1297      if (HasRegisterInput(instr, 0)) {
1298        __ mov(i.OutputRegister(), i.InputRegister(0));
1299      } else {
1300        __ li(i.OutputRegister(), i.InputOperand(0));
1301      }
1302      break;
1303
1304    case kMips64CmpS:
1305      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
1306      break;
1307    case kMips64AddS:
1308      // TODO(plind): add special case: combine mult & add.
1309      __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1310               i.InputDoubleRegister(1));
1311      break;
1312    case kMips64SubS:
1313      __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1314               i.InputDoubleRegister(1));
1315      break;
1316    case kMips64MulS:
1317      // TODO(plind): add special case: right op is -1.0, see arm port.
1318      __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1319               i.InputDoubleRegister(1));
1320      break;
1321    case kMips64DivS:
1322      __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1323               i.InputDoubleRegister(1));
1324      break;
1325    case kMips64ModS: {
1326      // TODO(bmeurer): We should really get rid of this special instruction,
1327      // and generate a CallAddress instruction instead.
1328      FrameScope scope(masm(), StackFrame::MANUAL);
1329      __ PrepareCallCFunction(0, 2, kScratchReg);
1330      __ MovToFloatParameters(i.InputDoubleRegister(0),
1331                              i.InputDoubleRegister(1));
1332      // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
1333      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1334                       0, 2);
1335      // Move the result in the double result register.
1336      __ MovFromFloatResult(i.OutputSingleRegister());
1337      break;
1338    }
1339    case kMips64AbsS:
1340      __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1341      break;
1342    case kMips64NegS:
1343      __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1344      break;
1345    case kMips64SqrtS: {
1346      __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1347      break;
1348    }
1349    case kMips64MaxS:
1350      __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1351               i.InputDoubleRegister(1));
1352      break;
1353    case kMips64MinS:
1354      __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1355               i.InputDoubleRegister(1));
1356      break;
1357    case kMips64CmpD:
1358      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
1359      break;
1360    case kMips64AddD:
1361      // TODO(plind): add special case: combine mult & add.
1362      __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1363               i.InputDoubleRegister(1));
1364      break;
1365    case kMips64SubD:
1366      __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1367               i.InputDoubleRegister(1));
1368      break;
1369    case kMips64MaddS:
1370      __ Madd_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
1371                i.InputFloatRegister(1), i.InputFloatRegister(2),
1372                kScratchDoubleReg);
1373      break;
1374    case kMips64MaddD:
1375      __ Madd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1376                i.InputDoubleRegister(1), i.InputDoubleRegister(2),
1377                kScratchDoubleReg);
1378      break;
1379    case kMips64MsubS:
1380      __ Msub_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
1381                i.InputFloatRegister(1), i.InputFloatRegister(2),
1382                kScratchDoubleReg);
1383      break;
1384    case kMips64MsubD:
1385      __ Msub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1386                i.InputDoubleRegister(1), i.InputDoubleRegister(2),
1387                kScratchDoubleReg);
1388      break;
1389    case kMips64MulD:
1390      // TODO(plind): add special case: right op is -1.0, see arm port.
1391      __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1392               i.InputDoubleRegister(1));
1393      break;
1394    case kMips64DivD:
1395      __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1396               i.InputDoubleRegister(1));
1397      break;
1398    case kMips64ModD: {
1399      // TODO(bmeurer): We should really get rid of this special instruction,
1400      // and generate a CallAddress instruction instead.
1401      FrameScope scope(masm(), StackFrame::MANUAL);
1402      __ PrepareCallCFunction(0, 2, kScratchReg);
1403      __ MovToFloatParameters(i.InputDoubleRegister(0),
1404                              i.InputDoubleRegister(1));
1405      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1406                       0, 2);
1407      // Move the result in the double result register.
1408      __ MovFromFloatResult(i.OutputDoubleRegister());
1409      break;
1410    }
1411    case kMips64AbsD:
1412      __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1413      break;
1414    case kMips64NegD:
1415      __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1416      break;
1417    case kMips64SqrtD: {
1418      __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1419      break;
1420    }
1421    case kMips64MaxD:
1422      __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1423               i.InputDoubleRegister(1));
1424      break;
1425    case kMips64MinD:
1426      __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1427               i.InputDoubleRegister(1));
1428      break;
1429    case kMips64Float64RoundDown: {
1430      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
1431      break;
1432    }
1433    case kMips64Float32RoundDown: {
1434      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
1435      break;
1436    }
1437    case kMips64Float64RoundTruncate: {
1438      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
1439      break;
1440    }
1441    case kMips64Float32RoundTruncate: {
1442      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
1443      break;
1444    }
1445    case kMips64Float64RoundUp: {
1446      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
1447      break;
1448    }
1449    case kMips64Float32RoundUp: {
1450      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
1451      break;
1452    }
1453    case kMips64Float64RoundTiesEven: {
1454      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
1455      break;
1456    }
1457    case kMips64Float32RoundTiesEven: {
1458      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
1459      break;
1460    }
1461    case kMips64Float32Max: {
1462      FPURegister dst = i.OutputSingleRegister();
1463      FPURegister src1 = i.InputSingleRegister(0);
1464      FPURegister src2 = i.InputSingleRegister(1);
1465      auto ool = new (zone()) OutOfLineFloat32Max(this, dst, src1, src2);
1466      __ Float32Max(dst, src1, src2, ool->entry());
1467      __ bind(ool->exit());
1468      break;
1469    }
1470    case kMips64Float64Max: {
1471      FPURegister dst = i.OutputDoubleRegister();
1472      FPURegister src1 = i.InputDoubleRegister(0);
1473      FPURegister src2 = i.InputDoubleRegister(1);
1474      auto ool = new (zone()) OutOfLineFloat64Max(this, dst, src1, src2);
1475      __ Float64Max(dst, src1, src2, ool->entry());
1476      __ bind(ool->exit());
1477      break;
1478    }
1479    case kMips64Float32Min: {
1480      FPURegister dst = i.OutputSingleRegister();
1481      FPURegister src1 = i.InputSingleRegister(0);
1482      FPURegister src2 = i.InputSingleRegister(1);
1483      auto ool = new (zone()) OutOfLineFloat32Min(this, dst, src1, src2);
1484      __ Float32Min(dst, src1, src2, ool->entry());
1485      __ bind(ool->exit());
1486      break;
1487    }
1488    case kMips64Float64Min: {
1489      FPURegister dst = i.OutputDoubleRegister();
1490      FPURegister src1 = i.InputDoubleRegister(0);
1491      FPURegister src2 = i.InputDoubleRegister(1);
1492      auto ool = new (zone()) OutOfLineFloat64Min(this, dst, src1, src2);
1493      __ Float64Min(dst, src1, src2, ool->entry());
1494      __ bind(ool->exit());
1495      break;
1496    }
1497    case kMips64Float64SilenceNaN:
1498      __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1499      break;
1500    case kMips64CvtSD:
1501      __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1502      break;
1503    case kMips64CvtDS:
1504      __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1505      break;
1506    case kMips64CvtDW: {
1507      FPURegister scratch = kScratchDoubleReg;
1508      __ mtc1(i.InputRegister(0), scratch);
1509      __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1510      break;
1511    }
1512    case kMips64CvtSW: {
1513      FPURegister scratch = kScratchDoubleReg;
1514      __ mtc1(i.InputRegister(0), scratch);
1515      __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1516      break;
1517    }
1518    case kMips64CvtSUw: {
1519      __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1520      break;
1521    }
1522    case kMips64CvtSL: {
1523      FPURegister scratch = kScratchDoubleReg;
1524      __ dmtc1(i.InputRegister(0), scratch);
1525      __ cvt_s_l(i.OutputDoubleRegister(), scratch);
1526      break;
1527    }
1528    case kMips64CvtDL: {
1529      FPURegister scratch = kScratchDoubleReg;
1530      __ dmtc1(i.InputRegister(0), scratch);
1531      __ cvt_d_l(i.OutputDoubleRegister(), scratch);
1532      break;
1533    }
1534    case kMips64CvtDUw: {
1535      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1536      break;
1537    }
1538    case kMips64CvtDUl: {
1539      __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1540      break;
1541    }
1542    case kMips64CvtSUl: {
1543      __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1544      break;
1545    }
1546    case kMips64FloorWD: {
1547      FPURegister scratch = kScratchDoubleReg;
1548      __ floor_w_d(scratch, i.InputDoubleRegister(0));
1549      __ mfc1(i.OutputRegister(), scratch);
1550      break;
1551    }
1552    case kMips64CeilWD: {
1553      FPURegister scratch = kScratchDoubleReg;
1554      __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1555      __ mfc1(i.OutputRegister(), scratch);
1556      break;
1557    }
1558    case kMips64RoundWD: {
1559      FPURegister scratch = kScratchDoubleReg;
1560      __ round_w_d(scratch, i.InputDoubleRegister(0));
1561      __ mfc1(i.OutputRegister(), scratch);
1562      break;
1563    }
1564    case kMips64TruncWD: {
1565      FPURegister scratch = kScratchDoubleReg;
1566      // Other arches use round to zero here, so we follow.
1567      __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1568      __ mfc1(i.OutputRegister(), scratch);
1569      break;
1570    }
1571    case kMips64FloorWS: {
1572      FPURegister scratch = kScratchDoubleReg;
1573      __ floor_w_s(scratch, i.InputDoubleRegister(0));
1574      __ mfc1(i.OutputRegister(), scratch);
1575      break;
1576    }
1577    case kMips64CeilWS: {
1578      FPURegister scratch = kScratchDoubleReg;
1579      __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1580      __ mfc1(i.OutputRegister(), scratch);
1581      break;
1582    }
1583    case kMips64RoundWS: {
1584      FPURegister scratch = kScratchDoubleReg;
1585      __ round_w_s(scratch, i.InputDoubleRegister(0));
1586      __ mfc1(i.OutputRegister(), scratch);
1587      break;
1588    }
1589    case kMips64TruncWS: {
1590      FPURegister scratch = kScratchDoubleReg;
1591      __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1592      __ mfc1(i.OutputRegister(), scratch);
1593      // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1594      // because INT32_MIN allows easier out-of-bounds detection.
1595      __ addiu(kScratchReg, i.OutputRegister(), 1);
1596      __ slt(kScratchReg2, kScratchReg, i.OutputRegister());
1597      __ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
1598      break;
1599    }
1600    case kMips64TruncLS: {
1601      FPURegister scratch = kScratchDoubleReg;
1602      Register tmp_fcsr = kScratchReg;
1603      Register result = kScratchReg2;
1604
1605      bool load_status = instr->OutputCount() > 1;
1606      if (load_status) {
1607        // Save FCSR.
1608        __ cfc1(tmp_fcsr, FCSR);
1609        // Clear FPU flags.
1610        __ ctc1(zero_reg, FCSR);
1611      }
1612      // Other arches use round to zero here, so we follow.
1613      __ trunc_l_s(scratch, i.InputDoubleRegister(0));
1614      __ dmfc1(i.OutputRegister(), scratch);
1615      if (load_status) {
1616        __ cfc1(result, FCSR);
1617        // Check for overflow and NaNs.
1618        __ andi(result, result,
1619                (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1620        __ Slt(result, zero_reg, result);
1621        __ xori(result, result, 1);
1622        __ mov(i.OutputRegister(1), result);
1623        // Restore FCSR
1624        __ ctc1(tmp_fcsr, FCSR);
1625      }
1626      break;
1627    }
1628    case kMips64TruncLD: {
1629      FPURegister scratch = kScratchDoubleReg;
1630      Register tmp_fcsr = kScratchReg;
1631      Register result = kScratchReg2;
1632
1633      bool load_status = instr->OutputCount() > 1;
1634      if (load_status) {
1635        // Save FCSR.
1636        __ cfc1(tmp_fcsr, FCSR);
1637        // Clear FPU flags.
1638        __ ctc1(zero_reg, FCSR);
1639      }
1640      // Other arches use round to zero here, so we follow.
1641      __ trunc_l_d(scratch, i.InputDoubleRegister(0));
1642      __ dmfc1(i.OutputRegister(0), scratch);
1643      if (load_status) {
1644        __ cfc1(result, FCSR);
1645        // Check for overflow and NaNs.
1646        __ andi(result, result,
1647                (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1648        __ Slt(result, zero_reg, result);
1649        __ xori(result, result, 1);
1650        __ mov(i.OutputRegister(1), result);
1651        // Restore FCSR
1652        __ ctc1(tmp_fcsr, FCSR);
1653      }
1654      break;
1655    }
1656    case kMips64TruncUwD: {
1657      FPURegister scratch = kScratchDoubleReg;
1658      // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1659      __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1660      break;
1661    }
1662    case kMips64TruncUwS: {
1663      FPURegister scratch = kScratchDoubleReg;
1664      // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1665      __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1666      // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1667      // because 0 allows easier out-of-bounds detection.
1668      __ addiu(kScratchReg, i.OutputRegister(), 1);
1669      __ Movz(i.OutputRegister(), zero_reg, kScratchReg);
1670      break;
1671    }
1672    case kMips64TruncUlS: {
1673      FPURegister scratch = kScratchDoubleReg;
1674      Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1675      // TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function.
1676      __ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch,
1677                    result);
1678      break;
1679    }
1680    case kMips64TruncUlD: {
1681      FPURegister scratch = kScratchDoubleReg;
1682      Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1683      // TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
1684      __ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
1685                    result);
1686      break;
1687    }
1688    case kMips64BitcastDL:
1689      __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0));
1690      break;
1691    case kMips64BitcastLD:
1692      __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister());
1693      break;
1694    case kMips64Float64ExtractLowWord32:
1695      __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1696      break;
1697    case kMips64Float64ExtractHighWord32:
1698      __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1699      break;
1700    case kMips64Float64InsertLowWord32:
1701      __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1702      break;
1703    case kMips64Float64InsertHighWord32:
1704      __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1705      break;
1706    // ... more basic instructions ...
1707
1708    case kMips64Seb:
1709      __ seb(i.OutputRegister(), i.InputRegister(0));
1710      break;
1711    case kMips64Seh:
1712      __ seh(i.OutputRegister(), i.InputRegister(0));
1713      break;
1714    case kMips64Lbu:
1715      __ lbu(i.OutputRegister(), i.MemoryOperand());
1716      break;
1717    case kMips64Lb:
1718      __ lb(i.OutputRegister(), i.MemoryOperand());
1719      break;
1720    case kMips64Sb:
1721      __ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
1722      break;
1723    case kMips64Lhu:
1724      __ lhu(i.OutputRegister(), i.MemoryOperand());
1725      break;
1726    case kMips64Ulhu:
1727      __ Ulhu(i.OutputRegister(), i.MemoryOperand());
1728      break;
1729    case kMips64Lh:
1730      __ lh(i.OutputRegister(), i.MemoryOperand());
1731      break;
1732    case kMips64Ulh:
1733      __ Ulh(i.OutputRegister(), i.MemoryOperand());
1734      break;
1735    case kMips64Sh:
1736      __ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
1737      break;
1738    case kMips64Ush:
1739      __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
1740      break;
1741    case kMips64Lw:
1742      __ lw(i.OutputRegister(), i.MemoryOperand());
1743      break;
1744    case kMips64Ulw:
1745      __ Ulw(i.OutputRegister(), i.MemoryOperand());
1746      break;
1747    case kMips64Lwu:
1748      __ lwu(i.OutputRegister(), i.MemoryOperand());
1749      break;
1750    case kMips64Ulwu:
1751      __ Ulwu(i.OutputRegister(), i.MemoryOperand());
1752      break;
1753    case kMips64Ld:
1754      __ ld(i.OutputRegister(), i.MemoryOperand());
1755      break;
1756    case kMips64Uld:
1757      __ Uld(i.OutputRegister(), i.MemoryOperand());
1758      break;
1759    case kMips64Sw:
1760      __ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
1761      break;
1762    case kMips64Usw:
1763      __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
1764      break;
1765    case kMips64Sd:
1766      __ sd(i.InputOrZeroRegister(2), i.MemoryOperand());
1767      break;
1768    case kMips64Usd:
1769      __ Usd(i.InputOrZeroRegister(2), i.MemoryOperand());
1770      break;
1771    case kMips64Lwc1: {
1772      __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1773      break;
1774    }
1775    case kMips64Ulwc1: {
1776      __ Ulwc1(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg);
1777      break;
1778    }
1779    case kMips64Swc1: {
1780      size_t index = 0;
1781      MemOperand operand = i.MemoryOperand(&index);
1782      FPURegister ft = i.InputOrZeroSingleRegister(index);
1783      if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
1784        __ Move(kDoubleRegZero, 0.0);
1785      }
1786      __ swc1(ft, operand);
1787      break;
1788    }
1789    case kMips64Uswc1: {
1790      size_t index = 0;
1791      MemOperand operand = i.MemoryOperand(&index);
1792      FPURegister ft = i.InputOrZeroSingleRegister(index);
1793      if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
1794        __ Move(kDoubleRegZero, 0.0);
1795      }
1796      __ Uswc1(ft, operand, kScratchReg);
1797      break;
1798    }
1799    case kMips64Ldc1:
1800      __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1801      break;
1802    case kMips64Uldc1:
1803      __ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
1804      break;
1805    case kMips64Sdc1: {
1806      FPURegister ft = i.InputOrZeroDoubleRegister(2);
1807      if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
1808        __ Move(kDoubleRegZero, 0.0);
1809      }
1810      __ sdc1(ft, i.MemoryOperand());
1811      break;
1812    }
1813    case kMips64Usdc1: {
1814      FPURegister ft = i.InputOrZeroDoubleRegister(2);
1815      if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
1816        __ Move(kDoubleRegZero, 0.0);
1817      }
1818      __ Usdc1(ft, i.MemoryOperand(), kScratchReg);
1819      break;
1820    }
1821    case kMips64Push:
1822      if (instr->InputAt(0)->IsFPRegister()) {
1823        __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1824        __ Subu(sp, sp, Operand(kDoubleSize));
1825        frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1826      } else {
1827        __ Push(i.InputRegister(0));
1828        frame_access_state()->IncreaseSPDelta(1);
1829      }
1830      break;
1831    case kMips64StackClaim: {
1832      __ Dsubu(sp, sp, Operand(i.InputInt32(0)));
1833      frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
1834      break;
1835    }
1836    case kMips64StoreToStackSlot: {
1837      if (instr->InputAt(0)->IsFPRegister()) {
1838        __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1839      } else {
1840        __ sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1841      }
1842      break;
1843    }
1844    case kMips64ByteSwap64: {
1845      __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 8);
1846      break;
1847    }
1848    case kMips64ByteSwap32: {
1849      __ ByteSwapUnsigned(i.OutputRegister(0), i.InputRegister(0), 4);
1850      __ dsrl32(i.OutputRegister(0), i.OutputRegister(0), 0);
1851      break;
1852    }
1853    case kCheckedLoadInt8:
1854      ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
1855      break;
1856    case kCheckedLoadUint8:
1857      ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
1858      break;
1859    case kCheckedLoadInt16:
1860      ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
1861      break;
1862    case kCheckedLoadUint16:
1863      ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
1864      break;
1865    case kCheckedLoadWord32:
1866      ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
1867      break;
1868    case kCheckedLoadWord64:
1869      ASSEMBLE_CHECKED_LOAD_INTEGER(ld);
1870      break;
1871    case kCheckedLoadFloat32:
1872      ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
1873      break;
1874    case kCheckedLoadFloat64:
1875      ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
1876      break;
1877    case kCheckedStoreWord8:
1878      ASSEMBLE_CHECKED_STORE_INTEGER(sb);
1879      break;
1880    case kCheckedStoreWord16:
1881      ASSEMBLE_CHECKED_STORE_INTEGER(sh);
1882      break;
1883    case kCheckedStoreWord32:
1884      ASSEMBLE_CHECKED_STORE_INTEGER(sw);
1885      break;
1886    case kCheckedStoreWord64:
1887      ASSEMBLE_CHECKED_STORE_INTEGER(sd);
1888      break;
1889    case kCheckedStoreFloat32:
1890      ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
1891      break;
1892    case kCheckedStoreFloat64:
1893      ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
1894      break;
1895    case kAtomicLoadInt8:
1896      ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
1897      break;
1898    case kAtomicLoadUint8:
1899      ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
1900      break;
1901    case kAtomicLoadInt16:
1902      ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
1903      break;
1904    case kAtomicLoadUint16:
1905      ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
1906      break;
1907    case kAtomicLoadWord32:
1908      ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
1909      break;
1910    case kAtomicStoreWord8:
1911      ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
1912      break;
1913    case kAtomicStoreWord16:
1914      ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
1915      break;
1916    case kAtomicStoreWord32:
1917      ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
1918      break;
1919    case kMips64AssertEqual:
1920      __ Assert(eq, static_cast<BailoutReason>(i.InputOperand(2).immediate()),
1921                i.InputRegister(0), Operand(i.InputRegister(1)));
1922      break;
1923  }
1924  return kSuccess;
1925}  // NOLINT(readability/fn_size)
1926
1927
1928#define UNSUPPORTED_COND(opcode, condition)                                  \
1929  OFStream out(stdout);                                                      \
1930  out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
1931  UNIMPLEMENTED();
1932
1933static bool convertCondition(FlagsCondition condition, Condition& cc) {
1934  switch (condition) {
1935    case kEqual:
1936      cc = eq;
1937      return true;
1938    case kNotEqual:
1939      cc = ne;
1940      return true;
1941    case kUnsignedLessThan:
1942      cc = lt;
1943      return true;
1944    case kUnsignedGreaterThanOrEqual:
1945      cc = uge;
1946      return true;
1947    case kUnsignedLessThanOrEqual:
1948      cc = le;
1949      return true;
1950    case kUnsignedGreaterThan:
1951      cc = ugt;
1952      return true;
1953    default:
1954      break;
1955  }
1956  return false;
1957}
1958
1959void AssembleBranchToLabels(CodeGenerator* gen, MacroAssembler* masm,
1960                            Instruction* instr, FlagsCondition condition,
1961                            Label* tlabel, Label* flabel, bool fallthru) {
1962#undef __
1963#define __ masm->
1964  MipsOperandConverter i(gen, instr);
1965
1966  Condition cc = kNoCondition;
1967  // MIPS does not have condition code flags, so compare and branch are
1968  // implemented differently than on the other arch's. The compare operations
1969  // emit mips psuedo-instructions, which are handled here by branch
1970  // instructions that do the actual comparison. Essential that the input
1971  // registers to compare pseudo-op are not modified before this branch op, as
1972  // they are tested here.
1973
1974  if (instr->arch_opcode() == kMips64Tst) {
1975    cc = FlagsConditionToConditionTst(condition);
1976    __ And(at, i.InputRegister(0), i.InputOperand(1));
1977    __ Branch(tlabel, cc, at, Operand(zero_reg));
1978  } else if (instr->arch_opcode() == kMips64Dadd ||
1979             instr->arch_opcode() == kMips64Dsub) {
1980    cc = FlagsConditionToConditionOvf(condition);
1981    __ dsra32(kScratchReg, i.OutputRegister(), 0);
1982    __ sra(at, i.OutputRegister(), 31);
1983    __ Branch(tlabel, cc, at, Operand(kScratchReg));
1984  } else if (instr->arch_opcode() == kMips64DaddOvf) {
1985    switch (condition) {
1986      case kOverflow:
1987        __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1988                         i.InputOperand(1), tlabel, flabel);
1989        break;
1990      case kNotOverflow:
1991        __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1992                         i.InputOperand(1), flabel, tlabel);
1993        break;
1994      default:
1995        UNSUPPORTED_COND(kMips64DaddOvf, condition);
1996        break;
1997    }
1998  } else if (instr->arch_opcode() == kMips64DsubOvf) {
1999    switch (condition) {
2000      case kOverflow:
2001        __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
2002                         i.InputOperand(1), tlabel, flabel);
2003        break;
2004      case kNotOverflow:
2005        __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
2006                         i.InputOperand(1), flabel, tlabel);
2007        break;
2008      default:
2009        UNSUPPORTED_COND(kMips64DsubOvf, condition);
2010        break;
2011    }
2012  } else if (instr->arch_opcode() == kMips64MulOvf) {
2013    switch (condition) {
2014      case kOverflow: {
2015        __ MulBranchOvf(i.OutputRegister(), i.InputRegister(0),
2016                        i.InputOperand(1), tlabel, flabel, kScratchReg);
2017      } break;
2018      case kNotOverflow: {
2019        __ MulBranchOvf(i.OutputRegister(), i.InputRegister(0),
2020                        i.InputOperand(1), flabel, tlabel, kScratchReg);
2021      } break;
2022      default:
2023        UNSUPPORTED_COND(kMips64MulOvf, condition);
2024        break;
2025    }
2026  } else if (instr->arch_opcode() == kMips64Cmp) {
2027    cc = FlagsConditionToConditionCmp(condition);
2028    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
2029  } else if (instr->arch_opcode() == kMips64CmpS) {
2030    if (!convertCondition(condition, cc)) {
2031      UNSUPPORTED_COND(kMips64CmpS, condition);
2032    }
2033    FPURegister left = i.InputOrZeroSingleRegister(0);
2034    FPURegister right = i.InputOrZeroSingleRegister(1);
2035    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
2036        !__ IsDoubleZeroRegSet()) {
2037      __ Move(kDoubleRegZero, 0.0);
2038    }
2039    __ BranchF32(tlabel, nullptr, cc, left, right);
2040  } else if (instr->arch_opcode() == kMips64CmpD) {
2041    if (!convertCondition(condition, cc)) {
2042      UNSUPPORTED_COND(kMips64CmpD, condition);
2043    }
2044    FPURegister left = i.InputOrZeroDoubleRegister(0);
2045    FPURegister right = i.InputOrZeroDoubleRegister(1);
2046    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
2047        !__ IsDoubleZeroRegSet()) {
2048      __ Move(kDoubleRegZero, 0.0);
2049    }
2050    __ BranchF64(tlabel, nullptr, cc, left, right);
2051  } else {
2052    PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
2053           instr->arch_opcode());
2054    UNIMPLEMENTED();
2055  }
2056  if (!fallthru) __ Branch(flabel);  // no fallthru to flabel.
2057#undef __
2058#define __ masm()->
2059}
2060
2061// Assembles branches after an instruction.
2062void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
2063  Label* tlabel = branch->true_label;
2064  Label* flabel = branch->false_label;
2065
2066  AssembleBranchToLabels(this, masm(), instr, branch->condition, tlabel, flabel,
2067                         branch->fallthru);
2068}
2069
2070
2071void CodeGenerator::AssembleArchJump(RpoNumber target) {
2072  if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
2073}
2074
2075void CodeGenerator::AssembleArchTrap(Instruction* instr,
2076                                     FlagsCondition condition) {
2077  class OutOfLineTrap final : public OutOfLineCode {
2078   public:
2079    OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
2080        : OutOfLineCode(gen),
2081          frame_elided_(frame_elided),
2082          instr_(instr),
2083          gen_(gen) {}
2084    void Generate() final {
2085      MipsOperandConverter i(gen_, instr_);
2086      Builtins::Name trap_id =
2087          static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
2088      bool old_has_frame = __ has_frame();
2089      if (frame_elided_) {
2090        __ set_has_frame(true);
2091        __ EnterFrame(StackFrame::WASM_COMPILED);
2092      }
2093      GenerateCallToTrap(trap_id);
2094      if (frame_elided_) {
2095        __ set_has_frame(old_has_frame);
2096      }
2097    }
2098
2099   private:
2100    void GenerateCallToTrap(Builtins::Name trap_id) {
2101      if (trap_id == Builtins::builtin_count) {
2102        // We cannot test calls to the runtime in cctest/test-run-wasm.
2103        // Therefore we emit a call to C here instead of a call to the runtime.
2104        // We use the context register as the scratch register, because we do
2105        // not have a context here.
2106        __ PrepareCallCFunction(0, 0, cp);
2107        __ CallCFunction(
2108            ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
2109            0);
2110        __ LeaveFrame(StackFrame::WASM_COMPILED);
2111        __ Ret();
2112      } else {
2113        gen_->AssembleSourcePosition(instr_);
2114        __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()),
2115                RelocInfo::CODE_TARGET);
2116        ReferenceMap* reference_map =
2117            new (gen_->zone()) ReferenceMap(gen_->zone());
2118        gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
2119                              Safepoint::kNoLazyDeopt);
2120        if (FLAG_debug_code) {
2121          __ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
2122        }
2123      }
2124    }
2125    bool frame_elided_;
2126    Instruction* instr_;
2127    CodeGenerator* gen_;
2128  };
2129  bool frame_elided = !frame_access_state()->has_frame();
2130  auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
2131  Label* tlabel = ool->entry();
2132  AssembleBranchToLabels(this, masm(), instr, condition, tlabel, nullptr, true);
2133}
2134
2135// Assembles boolean materializations after an instruction.
2136void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2137                                        FlagsCondition condition) {
2138  MipsOperandConverter i(this, instr);
2139  Label done;
2140
2141  // Materialize a full 32-bit 1 or 0 value. The result register is always the
2142  // last output of the instruction.
2143  Label false_value;
2144  DCHECK_NE(0u, instr->OutputCount());
2145  Register result = i.OutputRegister(instr->OutputCount() - 1);
2146  Condition cc = kNoCondition;
2147  // MIPS does not have condition code flags, so compare and branch are
2148  // implemented differently than on the other arch's. The compare operations
2149  // emit mips pseudo-instructions, which are checked and handled here.
2150
2151  if (instr->arch_opcode() == kMips64Tst) {
2152    cc = FlagsConditionToConditionTst(condition);
2153    if (instr->InputAt(1)->IsImmediate() &&
2154        base::bits::IsPowerOfTwo64(i.InputOperand(1).immediate())) {
2155      uint16_t pos =
2156          base::bits::CountTrailingZeros64(i.InputOperand(1).immediate());
2157      __ ExtractBits(result, i.InputRegister(0), pos, 1);
2158    } else {
2159      __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
2160      __ Sltu(result, zero_reg, kScratchReg);
2161    }
2162    if (cc == eq) {
2163      // Sltu produces 0 for equality, invert the result.
2164      __ xori(result, result, 1);
2165    }
2166    return;
2167  } else if (instr->arch_opcode() == kMips64Dadd ||
2168             instr->arch_opcode() == kMips64Dsub) {
2169    cc = FlagsConditionToConditionOvf(condition);
2170    // Check for overflow creates 1 or 0 for result.
2171    __ dsrl32(kScratchReg, i.OutputRegister(), 31);
2172    __ srl(at, i.OutputRegister(), 31);
2173    __ xor_(result, kScratchReg, at);
2174    if (cc == eq)  // Toggle result for not overflow.
2175      __ xori(result, result, 1);
2176    return;
2177  } else if (instr->arch_opcode() == kMips64DaddOvf ||
2178             instr->arch_opcode() == kMips64DsubOvf ||
2179             instr->arch_opcode() == kMips64MulOvf) {
2180    Label flabel, tlabel;
2181    switch (instr->arch_opcode()) {
2182      case kMips64DaddOvf:
2183        __ DaddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
2184                           i.InputOperand(1), &flabel);
2185
2186        break;
2187      case kMips64DsubOvf:
2188        __ DsubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
2189                           i.InputOperand(1), &flabel);
2190        break;
2191      case kMips64MulOvf:
2192        __ MulBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
2193                          i.InputOperand(1), &flabel, kScratchReg);
2194        break;
2195      default:
2196        UNREACHABLE();
2197        break;
2198    }
2199    __ li(result, 1);
2200    __ Branch(&tlabel);
2201    __ bind(&flabel);
2202    __ li(result, 0);
2203    __ bind(&tlabel);
2204  } else if (instr->arch_opcode() == kMips64Cmp) {
2205    cc = FlagsConditionToConditionCmp(condition);
2206    switch (cc) {
2207      case eq:
2208      case ne: {
2209        Register left = i.InputRegister(0);
2210        Operand right = i.InputOperand(1);
2211        Register select;
2212        if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) {
2213          // Pass left operand if right is zero.
2214          select = left;
2215        } else {
2216          __ Dsubu(kScratchReg, left, right);
2217          select = kScratchReg;
2218        }
2219        __ Sltu(result, zero_reg, select);
2220        if (cc == eq) {
2221          // Sltu produces 0 for equality, invert the result.
2222          __ xori(result, result, 1);
2223        }
2224      } break;
2225      case lt:
2226      case ge: {
2227        Register left = i.InputRegister(0);
2228        Operand right = i.InputOperand(1);
2229        __ Slt(result, left, right);
2230        if (cc == ge) {
2231          __ xori(result, result, 1);
2232        }
2233      } break;
2234      case gt:
2235      case le: {
2236        Register left = i.InputRegister(1);
2237        Operand right = i.InputOperand(0);
2238        __ Slt(result, left, right);
2239        if (cc == le) {
2240          __ xori(result, result, 1);
2241        }
2242      } break;
2243      case lo:
2244      case hs: {
2245        Register left = i.InputRegister(0);
2246        Operand right = i.InputOperand(1);
2247        __ Sltu(result, left, right);
2248        if (cc == hs) {
2249          __ xori(result, result, 1);
2250        }
2251      } break;
2252      case hi:
2253      case ls: {
2254        Register left = i.InputRegister(1);
2255        Operand right = i.InputOperand(0);
2256        __ Sltu(result, left, right);
2257        if (cc == ls) {
2258          __ xori(result, result, 1);
2259        }
2260      } break;
2261      default:
2262        UNREACHABLE();
2263    }
2264    return;
2265  } else if (instr->arch_opcode() == kMips64CmpD ||
2266             instr->arch_opcode() == kMips64CmpS) {
2267    FPURegister left = i.InputOrZeroDoubleRegister(0);
2268    FPURegister right = i.InputOrZeroDoubleRegister(1);
2269    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
2270        !__ IsDoubleZeroRegSet()) {
2271      __ Move(kDoubleRegZero, 0.0);
2272    }
2273    bool predicate;
2274    FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
2275    if (kArchVariant != kMips64r6) {
2276      __ li(result, Operand(1));
2277      if (instr->arch_opcode() == kMips64CmpD) {
2278        __ c(cc, D, left, right);
2279      } else {
2280        DCHECK(instr->arch_opcode() == kMips64CmpS);
2281        __ c(cc, S, left, right);
2282      }
2283      if (predicate) {
2284        __ Movf(result, zero_reg);
2285      } else {
2286        __ Movt(result, zero_reg);
2287      }
2288    } else {
2289      if (instr->arch_opcode() == kMips64CmpD) {
2290        __ cmp(cc, L, kDoubleCompareReg, left, right);
2291      } else {
2292        DCHECK(instr->arch_opcode() == kMips64CmpS);
2293        __ cmp(cc, W, kDoubleCompareReg, left, right);
2294      }
2295      __ dmfc1(result, kDoubleCompareReg);
2296      __ andi(result, result, 1);  // Cmp returns all 1's/0's, use only LSB.
2297
2298      if (!predicate)  // Toggle result for not equal.
2299        __ xori(result, result, 1);
2300    }
2301    return;
2302  } else {
2303    PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
2304           instr->arch_opcode());
2305    TRACE_UNIMPL();
2306    UNIMPLEMENTED();
2307  }
2308}
2309
2310
2311void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
2312  MipsOperandConverter i(this, instr);
2313  Register input = i.InputRegister(0);
2314  for (size_t index = 2; index < instr->InputCount(); index += 2) {
2315    __ li(at, Operand(i.InputInt32(index + 0)));
2316    __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
2317  }
2318  __ nop();  // Branch delay slot of the last beq.
2319  AssembleArchJump(i.InputRpo(1));
2320}
2321
2322void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2323  MipsOperandConverter i(this, instr);
2324  Register input = i.InputRegister(0);
2325  size_t const case_count = instr->InputCount() - 2;
2326
2327  __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
2328  __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
2329    return GetLabel(i.InputRpo(index + 2));
2330  });
2331}
2332
2333CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
2334    int deoptimization_id, SourcePosition pos) {
2335  DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
2336  DeoptimizeReason deoptimization_reason =
2337      GetDeoptimizationReason(deoptimization_id);
2338  Deoptimizer::BailoutType bailout_type =
2339      deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
2340                                                   : Deoptimizer::EAGER;
2341  Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
2342      isolate(), deoptimization_id, bailout_type);
2343  if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
2344  __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
2345  __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
2346  return kSuccess;
2347}
2348
2349void CodeGenerator::FinishFrame(Frame* frame) {
2350  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2351
2352  const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2353  if (saves_fpu != 0) {
2354    int count = base::bits::CountPopulation32(saves_fpu);
2355    DCHECK(kNumCalleeSavedFPU == count);
2356    frame->AllocateSavedCalleeRegisterSlots(count *
2357                                            (kDoubleSize / kPointerSize));
2358  }
2359
2360  const RegList saves = descriptor->CalleeSavedRegisters();
2361  if (saves != 0) {
2362    int count = base::bits::CountPopulation32(saves);
2363    DCHECK(kNumCalleeSaved == count + 1);
2364    frame->AllocateSavedCalleeRegisterSlots(count);
2365  }
2366}
2367
2368void CodeGenerator::AssembleConstructFrame() {
2369  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2370  if (frame_access_state()->has_frame()) {
2371    if (descriptor->IsCFunctionCall()) {
2372      __ Push(ra, fp);
2373      __ mov(fp, sp);
2374    } else if (descriptor->IsJSFunctionCall()) {
2375      __ Prologue(this->info()->GeneratePreagedPrologue());
2376      if (descriptor->PushArgumentCount()) {
2377        __ Push(kJavaScriptCallArgCountRegister);
2378      }
2379    } else {
2380      __ StubPrologue(info()->GetOutputStackFrameType());
2381    }
2382  }
2383
2384  int shrink_slots =
2385      frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
2386
2387  if (info()->is_osr()) {
2388    // TurboFan OSR-compiled functions cannot be entered directly.
2389    __ Abort(kShouldNotDirectlyEnterOsrFunction);
2390
2391    // Unoptimized code jumps directly to this entrypoint while the unoptimized
2392    // frame is still on the stack. Optimized code uses OSR values directly from
2393    // the unoptimized frame. Thus, all that needs to be done is to allocate the
2394    // remaining stack slots.
2395    if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2396    osr_pc_offset_ = __ pc_offset();
2397    shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
2398  }
2399
2400  if (shrink_slots > 0) {
2401    __ Dsubu(sp, sp, Operand(shrink_slots * kPointerSize));
2402  }
2403
2404  const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2405  if (saves_fpu != 0) {
2406    // Save callee-saved FPU registers.
2407    __ MultiPushFPU(saves_fpu);
2408    DCHECK(kNumCalleeSavedFPU == base::bits::CountPopulation32(saves_fpu));
2409  }
2410
2411  const RegList saves = descriptor->CalleeSavedRegisters();
2412  if (saves != 0) {
2413    // Save callee-saved registers.
2414    __ MultiPush(saves);
2415    DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1);
2416  }
2417}
2418
2419void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
2420  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2421
2422  // Restore GP registers.
2423  const RegList saves = descriptor->CalleeSavedRegisters();
2424  if (saves != 0) {
2425    __ MultiPop(saves);
2426  }
2427
2428  // Restore FPU registers.
2429  const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2430  if (saves_fpu != 0) {
2431    __ MultiPopFPU(saves_fpu);
2432  }
2433
2434  MipsOperandConverter g(this, nullptr);
2435  if (descriptor->IsCFunctionCall()) {
2436    AssembleDeconstructFrame();
2437  } else if (frame_access_state()->has_frame()) {
2438    // Canonicalize JSFunction return sites for now unless they have an variable
2439    // number of stack slot pops.
2440    if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
2441      if (return_label_.is_bound()) {
2442        __ Branch(&return_label_);
2443        return;
2444      } else {
2445        __ bind(&return_label_);
2446        AssembleDeconstructFrame();
2447      }
2448    } else {
2449      AssembleDeconstructFrame();
2450    }
2451  }
2452  int pop_count = static_cast<int>(descriptor->StackParameterCount());
2453  if (pop->IsImmediate()) {
2454    DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
2455    pop_count += g.ToConstant(pop).ToInt32();
2456  } else {
2457    Register pop_reg = g.ToRegister(pop);
2458    __ dsll(pop_reg, pop_reg, kPointerSizeLog2);
2459    __ Daddu(sp, sp, pop_reg);
2460  }
2461  if (pop_count != 0) {
2462    __ DropAndRet(pop_count);
2463  } else {
2464    __ Ret();
2465  }
2466}
2467
2468
2469void CodeGenerator::AssembleMove(InstructionOperand* source,
2470                                 InstructionOperand* destination) {
2471  MipsOperandConverter g(this, nullptr);
2472  // Dispatch on the source and destination operand kinds.  Not all
2473  // combinations are possible.
2474  if (source->IsRegister()) {
2475    DCHECK(destination->IsRegister() || destination->IsStackSlot());
2476    Register src = g.ToRegister(source);
2477    if (destination->IsRegister()) {
2478      __ mov(g.ToRegister(destination), src);
2479    } else {
2480      __ sd(src, g.ToMemOperand(destination));
2481    }
2482  } else if (source->IsStackSlot()) {
2483    DCHECK(destination->IsRegister() || destination->IsStackSlot());
2484    MemOperand src = g.ToMemOperand(source);
2485    if (destination->IsRegister()) {
2486      __ ld(g.ToRegister(destination), src);
2487    } else {
2488      Register temp = kScratchReg;
2489      __ ld(temp, src);
2490      __ sd(temp, g.ToMemOperand(destination));
2491    }
2492  } else if (source->IsConstant()) {
2493    Constant src = g.ToConstant(source);
2494    if (destination->IsRegister() || destination->IsStackSlot()) {
2495      Register dst =
2496          destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
2497      switch (src.type()) {
2498        case Constant::kInt32:
2499          if (RelocInfo::IsWasmSizeReference(src.rmode())) {
2500            __ li(dst, Operand(src.ToInt32(), src.rmode()));
2501          } else {
2502            __ li(dst, Operand(src.ToInt32()));
2503          }
2504          break;
2505        case Constant::kFloat32:
2506          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
2507          break;
2508        case Constant::kInt64:
2509          if (RelocInfo::IsWasmPtrReference(src.rmode())) {
2510            __ li(dst, Operand(src.ToInt64(), src.rmode()));
2511          } else {
2512            DCHECK(!RelocInfo::IsWasmSizeReference(src.rmode()));
2513            __ li(dst, Operand(src.ToInt64()));
2514          }
2515          break;
2516        case Constant::kFloat64:
2517          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
2518          break;
2519        case Constant::kExternalReference:
2520          __ li(dst, Operand(src.ToExternalReference()));
2521          break;
2522        case Constant::kHeapObject: {
2523          Handle<HeapObject> src_object = src.ToHeapObject();
2524          Heap::RootListIndex index;
2525          if (IsMaterializableFromRoot(src_object, &index)) {
2526            __ LoadRoot(dst, index);
2527          } else {
2528            __ li(dst, src_object);
2529          }
2530          break;
2531        }
2532        case Constant::kRpoNumber:
2533          UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
2534          break;
2535      }
2536      if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
2537    } else if (src.type() == Constant::kFloat32) {
2538      if (destination->IsFPStackSlot()) {
2539        MemOperand dst = g.ToMemOperand(destination);
2540        if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
2541          __ sw(zero_reg, dst);
2542        } else {
2543          __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
2544          __ sw(at, dst);
2545        }
2546      } else {
2547        DCHECK(destination->IsFPRegister());
2548        FloatRegister dst = g.ToSingleRegister(destination);
2549        __ Move(dst, src.ToFloat32());
2550      }
2551    } else {
2552      DCHECK_EQ(Constant::kFloat64, src.type());
2553      DoubleRegister dst = destination->IsFPRegister()
2554                               ? g.ToDoubleRegister(destination)
2555                               : kScratchDoubleReg;
2556      __ Move(dst, src.ToFloat64());
2557      if (destination->IsFPStackSlot()) {
2558        __ sdc1(dst, g.ToMemOperand(destination));
2559      }
2560    }
2561  } else if (source->IsFPRegister()) {
2562    FPURegister src = g.ToDoubleRegister(source);
2563    if (destination->IsFPRegister()) {
2564      FPURegister dst = g.ToDoubleRegister(destination);
2565      __ Move(dst, src);
2566    } else {
2567      DCHECK(destination->IsFPStackSlot());
2568      __ sdc1(src, g.ToMemOperand(destination));
2569    }
2570  } else if (source->IsFPStackSlot()) {
2571    DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
2572    MemOperand src = g.ToMemOperand(source);
2573    if (destination->IsFPRegister()) {
2574      __ ldc1(g.ToDoubleRegister(destination), src);
2575    } else {
2576      FPURegister temp = kScratchDoubleReg;
2577      __ ldc1(temp, src);
2578      __ sdc1(temp, g.ToMemOperand(destination));
2579    }
2580  } else {
2581    UNREACHABLE();
2582  }
2583}
2584
2585
2586void CodeGenerator::AssembleSwap(InstructionOperand* source,
2587                                 InstructionOperand* destination) {
2588  MipsOperandConverter g(this, nullptr);
2589  // Dispatch on the source and destination operand kinds.  Not all
2590  // combinations are possible.
2591  if (source->IsRegister()) {
2592    // Register-register.
2593    Register temp = kScratchReg;
2594    Register src = g.ToRegister(source);
2595    if (destination->IsRegister()) {
2596      Register dst = g.ToRegister(destination);
2597      __ Move(temp, src);
2598      __ Move(src, dst);
2599      __ Move(dst, temp);
2600    } else {
2601      DCHECK(destination->IsStackSlot());
2602      MemOperand dst = g.ToMemOperand(destination);
2603      __ mov(temp, src);
2604      __ ld(src, dst);
2605      __ sd(temp, dst);
2606    }
2607  } else if (source->IsStackSlot()) {
2608    DCHECK(destination->IsStackSlot());
2609    Register temp_0 = kScratchReg;
2610    Register temp_1 = kScratchReg2;
2611    MemOperand src = g.ToMemOperand(source);
2612    MemOperand dst = g.ToMemOperand(destination);
2613    __ ld(temp_0, src);
2614    __ ld(temp_1, dst);
2615    __ sd(temp_0, dst);
2616    __ sd(temp_1, src);
2617  } else if (source->IsFPRegister()) {
2618    FPURegister temp = kScratchDoubleReg;
2619    FPURegister src = g.ToDoubleRegister(source);
2620    if (destination->IsFPRegister()) {
2621      FPURegister dst = g.ToDoubleRegister(destination);
2622      __ Move(temp, src);
2623      __ Move(src, dst);
2624      __ Move(dst, temp);
2625    } else {
2626      DCHECK(destination->IsFPStackSlot());
2627      MemOperand dst = g.ToMemOperand(destination);
2628      __ Move(temp, src);
2629      __ ldc1(src, dst);
2630      __ sdc1(temp, dst);
2631    }
2632  } else if (source->IsFPStackSlot()) {
2633    DCHECK(destination->IsFPStackSlot());
2634    Register temp_0 = kScratchReg;
2635    FPURegister temp_1 = kScratchDoubleReg;
2636    MemOperand src0 = g.ToMemOperand(source);
2637    MemOperand src1(src0.rm(), src0.offset() + kIntSize);
2638    MemOperand dst0 = g.ToMemOperand(destination);
2639    MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
2640    __ ldc1(temp_1, dst0);  // Save destination in temp_1.
2641    __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
2642    __ sw(temp_0, dst0);
2643    __ lw(temp_0, src1);
2644    __ sw(temp_0, dst1);
2645    __ sdc1(temp_1, src0);
2646  } else {
2647    // No other combinations are possible.
2648    UNREACHABLE();
2649  }
2650}
2651
2652
2653void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2654  // On 64-bit MIPS we emit the jump tables inline.
2655  UNREACHABLE();
2656}
2657
2658
2659void CodeGenerator::EnsureSpaceForLazyDeopt() {
2660  if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2661    return;
2662  }
2663
2664  int space_needed = Deoptimizer::patch_size();
2665  // Ensure that we have enough space after the previous lazy-bailout
2666  // instruction for patching the code here.
2667  int current_pc = masm()->pc_offset();
2668  if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2669    // Block tramoline pool emission for duration of padding.
2670    v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
2671        masm());
2672    int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2673    DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
2674    while (padding_size > 0) {
2675      __ nop();
2676      padding_size -= v8::internal::Assembler::kInstrSize;
2677    }
2678  }
2679}
2680
2681#undef __
2682
2683}  // namespace compiler
2684}  // namespace internal
2685}  // namespace v8
2686