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/ast/scopes.h"
6#include "src/compiler/code-generator.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  DoubleRegister InputOrZeroDoubleRegister(size_t index) {
57    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
58
59    return InputDoubleRegister(index);
60  }
61
62  DoubleRegister InputOrZeroSingleRegister(size_t index) {
63    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
64
65    return InputSingleRegister(index);
66  }
67
68  Operand InputImmediate(size_t index) {
69    Constant constant = ToConstant(instr_->InputAt(index));
70    switch (constant.type()) {
71      case Constant::kInt32:
72        return Operand(constant.ToInt32());
73      case Constant::kInt64:
74        return Operand(constant.ToInt64());
75      case Constant::kFloat32:
76        return Operand(
77            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
78      case Constant::kFloat64:
79        return Operand(
80            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
81      case Constant::kExternalReference:
82      case Constant::kHeapObject:
83        // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
84        //    maybe not done on arm due to const pool ??
85        break;
86      case Constant::kRpoNumber:
87        UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
88        break;
89    }
90    UNREACHABLE();
91    return Operand(zero_reg);
92  }
93
94  Operand InputOperand(size_t index) {
95    InstructionOperand* op = instr_->InputAt(index);
96    if (op->IsRegister()) {
97      return Operand(ToRegister(op));
98    }
99    return InputImmediate(index);
100  }
101
102  MemOperand MemoryOperand(size_t* first_index) {
103    const size_t index = *first_index;
104    switch (AddressingModeField::decode(instr_->opcode())) {
105      case kMode_None:
106        break;
107      case kMode_MRI:
108        *first_index += 2;
109        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
110      case kMode_MRR:
111        // TODO(plind): r6 address mode, to be implemented ...
112        UNREACHABLE();
113    }
114    UNREACHABLE();
115    return MemOperand(no_reg);
116  }
117
118  MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
119
120  MemOperand ToMemOperand(InstructionOperand* op) const {
121    DCHECK_NOT_NULL(op);
122    DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
123    FrameOffset offset = frame_access_state()->GetFrameOffset(
124        AllocatedOperand::cast(op)->index());
125    return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
126  }
127};
128
129
130static inline bool HasRegisterInput(Instruction* instr, size_t index) {
131  return instr->InputAt(index)->IsRegister();
132}
133
134
135namespace {
136
137class OutOfLineLoadSingle final : public OutOfLineCode {
138 public:
139  OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
140      : OutOfLineCode(gen), result_(result) {}
141
142  void Generate() final {
143    __ Move(result_, std::numeric_limits<float>::quiet_NaN());
144  }
145
146 private:
147  FloatRegister const result_;
148};
149
150
151class OutOfLineLoadDouble final : public OutOfLineCode {
152 public:
153  OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
154      : OutOfLineCode(gen), result_(result) {}
155
156  void Generate() final {
157    __ Move(result_, std::numeric_limits<double>::quiet_NaN());
158  }
159
160 private:
161  DoubleRegister const result_;
162};
163
164
165class OutOfLineLoadInteger final : public OutOfLineCode {
166 public:
167  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
168      : OutOfLineCode(gen), result_(result) {}
169
170  void Generate() final { __ mov(result_, zero_reg); }
171
172 private:
173  Register const result_;
174};
175
176
177class OutOfLineRound : public OutOfLineCode {
178 public:
179  OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
180      : OutOfLineCode(gen), result_(result) {}
181
182  void Generate() final {
183    // Handle rounding to zero case where sign has to be preserved.
184    // High bits of double input already in kScratchReg.
185    __ dsrl(at, kScratchReg, 31);
186    __ dsll(at, at, 31);
187    __ mthc1(at, result_);
188  }
189
190 private:
191  DoubleRegister const result_;
192};
193
194
195class OutOfLineRound32 : public OutOfLineCode {
196 public:
197  OutOfLineRound32(CodeGenerator* gen, DoubleRegister result)
198      : OutOfLineCode(gen), result_(result) {}
199
200  void Generate() final {
201    // Handle rounding to zero case where sign has to be preserved.
202    // High bits of float input already in kScratchReg.
203    __ srl(at, kScratchReg, 31);
204    __ sll(at, at, 31);
205    __ mtc1(at, result_);
206  }
207
208 private:
209  DoubleRegister const result_;
210};
211
212
213class OutOfLineRecordWrite final : public OutOfLineCode {
214 public:
215  OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
216                       Register value, Register scratch0, Register scratch1,
217                       RecordWriteMode mode)
218      : OutOfLineCode(gen),
219        object_(object),
220        index_(index),
221        value_(value),
222        scratch0_(scratch0),
223        scratch1_(scratch1),
224        mode_(mode) {}
225
226  void Generate() final {
227    if (mode_ > RecordWriteMode::kValueIsPointer) {
228      __ JumpIfSmi(value_, exit());
229    }
230    if (mode_ > RecordWriteMode::kValueIsMap) {
231      __ CheckPageFlag(value_, scratch0_,
232                       MemoryChunk::kPointersToHereAreInterestingMask, eq,
233                       exit());
234    }
235    SaveFPRegsMode const save_fp_mode =
236        frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
237    // TODO(turbofan): Once we get frame elision working, we need to save
238    // and restore lr properly here if the frame was elided.
239    RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
240                         EMIT_REMEMBERED_SET, save_fp_mode);
241    __ Daddu(scratch1_, object_, index_);
242    __ CallStub(&stub);
243  }
244
245 private:
246  Register const object_;
247  Register const index_;
248  Register const value_;
249  Register const scratch0_;
250  Register const scratch1_;
251  RecordWriteMode const mode_;
252};
253
254
255Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
256  switch (condition) {
257    case kEqual:
258      return eq;
259    case kNotEqual:
260      return ne;
261    case kSignedLessThan:
262      return lt;
263    case kSignedGreaterThanOrEqual:
264      return ge;
265    case kSignedLessThanOrEqual:
266      return le;
267    case kSignedGreaterThan:
268      return gt;
269    case kUnsignedLessThan:
270      return lo;
271    case kUnsignedGreaterThanOrEqual:
272      return hs;
273    case kUnsignedLessThanOrEqual:
274      return ls;
275    case kUnsignedGreaterThan:
276      return hi;
277    case kUnorderedEqual:
278    case kUnorderedNotEqual:
279      break;
280    default:
281      break;
282  }
283  UNREACHABLE();
284  return kNoCondition;
285}
286
287
288Condition FlagsConditionToConditionTst(FlagsCondition condition) {
289  switch (condition) {
290    case kNotEqual:
291      return ne;
292    case kEqual:
293      return eq;
294    default:
295      break;
296  }
297  UNREACHABLE();
298  return kNoCondition;
299}
300
301
302Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
303  switch (condition) {
304    case kOverflow:
305      return ne;
306    case kNotOverflow:
307      return eq;
308    default:
309      break;
310  }
311  UNREACHABLE();
312  return kNoCondition;
313}
314
315
316FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
317                                             FlagsCondition condition) {
318  switch (condition) {
319    case kEqual:
320      predicate = true;
321      return EQ;
322    case kNotEqual:
323      predicate = false;
324      return EQ;
325    case kUnsignedLessThan:
326      predicate = true;
327      return OLT;
328    case kUnsignedGreaterThanOrEqual:
329      predicate = false;
330      return ULT;
331    case kUnsignedLessThanOrEqual:
332      predicate = true;
333      return OLE;
334    case kUnsignedGreaterThan:
335      predicate = false;
336      return ULE;
337    case kUnorderedEqual:
338    case kUnorderedNotEqual:
339      predicate = true;
340      break;
341    default:
342      predicate = true;
343      break;
344  }
345  UNREACHABLE();
346  return kNoFPUCondition;
347}
348
349}  // namespace
350
351
352#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
353  do {                                                                        \
354    auto result = i.Output##width##Register();                                \
355    auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
356    if (instr->InputAt(0)->IsRegister()) {                                    \
357      auto offset = i.InputRegister(0);                                       \
358      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
359      __ Daddu(kScratchReg, i.InputRegister(2), offset);                      \
360      __ asm_instr(result, MemOperand(kScratchReg, 0));                       \
361    } else {                                                                  \
362      int offset = static_cast<int>(i.InputOperand(0).immediate());           \
363      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
364      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
365    }                                                                         \
366    __ bind(ool->exit());                                                     \
367  } while (0)
368
369
370#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
371  do {                                                                        \
372    auto result = i.OutputRegister();                                         \
373    auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
374    if (instr->InputAt(0)->IsRegister()) {                                    \
375      auto offset = i.InputRegister(0);                                       \
376      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
377      __ Daddu(kScratchReg, i.InputRegister(2), offset);                      \
378      __ asm_instr(result, MemOperand(kScratchReg, 0));                       \
379    } else {                                                                  \
380      int offset = static_cast<int>(i.InputOperand(0).immediate());           \
381      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
382      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
383    }                                                                         \
384    __ bind(ool->exit());                                                     \
385  } while (0)
386
387
388#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
389  do {                                                                 \
390    Label done;                                                        \
391    if (instr->InputAt(0)->IsRegister()) {                             \
392      auto offset = i.InputRegister(0);                                \
393      auto value = i.Input##width##Register(2);                        \
394      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
395      __ Daddu(kScratchReg, i.InputRegister(3), offset);               \
396      __ asm_instr(value, MemOperand(kScratchReg, 0));                 \
397    } else {                                                           \
398      int offset = static_cast<int>(i.InputOperand(0).immediate());    \
399      auto value = i.Input##width##Register(2);                        \
400      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
401      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
402    }                                                                  \
403    __ bind(&done);                                                    \
404  } while (0)
405
406
407#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
408  do {                                                                 \
409    Label done;                                                        \
410    if (instr->InputAt(0)->IsRegister()) {                             \
411      auto offset = i.InputRegister(0);                                \
412      auto value = i.InputRegister(2);                                 \
413      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
414      __ Daddu(kScratchReg, i.InputRegister(3), offset);               \
415      __ asm_instr(value, MemOperand(kScratchReg, 0));                 \
416    } else {                                                           \
417      int offset = static_cast<int>(i.InputOperand(0).immediate());    \
418      auto value = i.InputRegister(2);                                 \
419      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
420      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
421    }                                                                  \
422    __ bind(&done);                                                    \
423  } while (0)
424
425
426#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode)                                  \
427  if (kArchVariant == kMips64r6) {                                             \
428    __ cfc1(kScratchReg, FCSR);                                                \
429    __ li(at, Operand(mode_##mode));                                           \
430    __ ctc1(at, FCSR);                                                         \
431    __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
432    __ ctc1(kScratchReg, FCSR);                                                \
433  } else {                                                                     \
434    auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister());    \
435    Label done;                                                                \
436    __ mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
437    __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
438           HeapNumber::kExponentBits);                                         \
439    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
440              Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
441    __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
442    __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));         \
443    __ dmfc1(at, i.OutputDoubleRegister());                                    \
444    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
445    __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
446    __ bind(ool->exit());                                                      \
447    __ bind(&done);                                                            \
448  }
449
450#define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode)                                   \
451  if (kArchVariant == kMips64r6) {                                            \
452    __ cfc1(kScratchReg, FCSR);                                               \
453    __ li(at, Operand(mode_##mode));                                          \
454    __ ctc1(at, FCSR);                                                        \
455    __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));            \
456    __ ctc1(kScratchReg, FCSR);                                               \
457  } else {                                                                    \
458    int32_t kFloat32ExponentBias = 127;                                       \
459    int32_t kFloat32MantissaBits = 23;                                        \
460    int32_t kFloat32ExponentBits = 8;                                         \
461    auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
462    Label done;                                                               \
463    __ mfc1(kScratchReg, i.InputDoubleRegister(0));                           \
464    __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits);      \
465    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                  \
466              Operand(kFloat32ExponentBias + kFloat32MantissaBits));          \
467    __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));             \
468    __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));        \
469    __ mfc1(at, i.OutputDoubleRegister());                                    \
470    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));       \
471    __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister());           \
472    __ bind(ool->exit());                                                     \
473    __ bind(&done);                                                           \
474  }
475
476void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
477  int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
478  if (sp_slot_delta > 0) {
479    __ daddiu(sp, sp, sp_slot_delta * kPointerSize);
480  }
481  frame_access_state()->SetFrameAccessToDefault();
482}
483
484
485void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
486  int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
487  if (sp_slot_delta < 0) {
488    __ Dsubu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
489    frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
490  }
491  if (frame()->needs_frame()) {
492    __ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
493    __ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
494  }
495  frame_access_state()->SetFrameAccessToSP();
496}
497
498
499// Assembles an instruction after register allocation, producing machine code.
500void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
501  MipsOperandConverter i(this, instr);
502  InstructionCode opcode = instr->opcode();
503
504  switch (ArchOpcodeField::decode(opcode)) {
505    case kArchCallCodeObject: {
506      EnsureSpaceForLazyDeopt();
507      if (instr->InputAt(0)->IsImmediate()) {
508        __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
509                RelocInfo::CODE_TARGET);
510      } else {
511        __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
512        __ Call(at);
513      }
514      RecordCallPosition(instr);
515      frame_access_state()->ClearSPDelta();
516      break;
517    }
518    case kArchTailCallCodeObject: {
519      int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
520      AssembleDeconstructActivationRecord(stack_param_delta);
521      if (instr->InputAt(0)->IsImmediate()) {
522        __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
523                RelocInfo::CODE_TARGET);
524      } else {
525        __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
526        __ Jump(at);
527      }
528      frame_access_state()->ClearSPDelta();
529      break;
530    }
531    case kArchCallJSFunction: {
532      EnsureSpaceForLazyDeopt();
533      Register func = i.InputRegister(0);
534      if (FLAG_debug_code) {
535        // Check the function's context matches the context argument.
536        __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
537        __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
538      }
539      __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
540      __ Call(at);
541      RecordCallPosition(instr);
542      frame_access_state()->ClearSPDelta();
543      break;
544    }
545    case kArchTailCallJSFunction: {
546      Register func = i.InputRegister(0);
547      if (FLAG_debug_code) {
548        // Check the function's context matches the context argument.
549        __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
550        __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
551      }
552      int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
553      AssembleDeconstructActivationRecord(stack_param_delta);
554      __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
555      __ Jump(at);
556      frame_access_state()->ClearSPDelta();
557      break;
558    }
559    case kArchLazyBailout: {
560      EnsureSpaceForLazyDeopt();
561      RecordCallPosition(instr);
562      break;
563    }
564    case kArchPrepareCallCFunction: {
565      int const num_parameters = MiscField::decode(instr->opcode());
566      __ PrepareCallCFunction(num_parameters, kScratchReg);
567      // Frame alignment requires using FP-relative frame addressing.
568      frame_access_state()->SetFrameAccessToFP();
569      break;
570    }
571    case kArchPrepareTailCall:
572      AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
573      break;
574    case kArchCallCFunction: {
575      int const num_parameters = MiscField::decode(instr->opcode());
576      if (instr->InputAt(0)->IsImmediate()) {
577        ExternalReference ref = i.InputExternalReference(0);
578        __ CallCFunction(ref, num_parameters);
579      } else {
580        Register func = i.InputRegister(0);
581        __ CallCFunction(func, num_parameters);
582      }
583      frame_access_state()->SetFrameAccessToDefault();
584      frame_access_state()->ClearSPDelta();
585      break;
586    }
587    case kArchJmp:
588      AssembleArchJump(i.InputRpo(0));
589      break;
590    case kArchLookupSwitch:
591      AssembleArchLookupSwitch(instr);
592      break;
593    case kArchTableSwitch:
594      AssembleArchTableSwitch(instr);
595      break;
596    case kArchNop:
597    case kArchThrowTerminator:
598      // don't emit code for nops.
599      break;
600    case kArchDeoptimize: {
601      int deopt_state_id =
602          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
603      Deoptimizer::BailoutType bailout_type =
604          Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
605      AssembleDeoptimizerCall(deopt_state_id, bailout_type);
606      break;
607    }
608    case kArchRet:
609      AssembleReturn();
610      break;
611    case kArchStackPointer:
612      __ mov(i.OutputRegister(), sp);
613      break;
614    case kArchFramePointer:
615      __ mov(i.OutputRegister(), fp);
616      break;
617    case kArchTruncateDoubleToI:
618      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
619      break;
620    case kArchStoreWithWriteBarrier: {
621      RecordWriteMode mode =
622          static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
623      Register object = i.InputRegister(0);
624      Register index = i.InputRegister(1);
625      Register value = i.InputRegister(2);
626      Register scratch0 = i.TempRegister(0);
627      Register scratch1 = i.TempRegister(1);
628      auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
629                                                   scratch0, scratch1, mode);
630      __ Daddu(at, object, index);
631      __ sd(value, MemOperand(at));
632      __ CheckPageFlag(object, scratch0,
633                       MemoryChunk::kPointersFromHereAreInterestingMask, ne,
634                       ool->entry());
635      __ bind(ool->exit());
636      break;
637    }
638    case kMips64Add:
639      __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
640      break;
641    case kMips64Dadd:
642      __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
643      break;
644    case kMips64DaddOvf:
645      // Pseudo-instruction used for overflow/branch. No opcode emitted here.
646      break;
647    case kMips64Sub:
648      __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
649      break;
650    case kMips64Dsub:
651      __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
652      break;
653    case kMips64DsubOvf:
654      // Pseudo-instruction used for overflow/branch. No opcode emitted here.
655      break;
656    case kMips64Mul:
657      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
658      break;
659    case kMips64MulHigh:
660      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
661      break;
662    case kMips64MulHighU:
663      __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
664      break;
665    case kMips64DMulHigh:
666      __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
667      break;
668    case kMips64Div:
669      __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
670      if (kArchVariant == kMips64r6) {
671        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
672      } else {
673        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
674      }
675      break;
676    case kMips64DivU:
677      __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
678      if (kArchVariant == kMips64r6) {
679        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
680      } else {
681        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
682      }
683      break;
684    case kMips64Mod:
685      __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
686      break;
687    case kMips64ModU:
688      __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
689      break;
690    case kMips64Dmul:
691      __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
692      break;
693    case kMips64Ddiv:
694      __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
695      if (kArchVariant == kMips64r6) {
696        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
697      } else {
698        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
699      }
700      break;
701    case kMips64DdivU:
702      __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
703      if (kArchVariant == kMips64r6) {
704        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
705      } else {
706        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
707      }
708      break;
709    case kMips64Dmod:
710      __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
711      break;
712    case kMips64DmodU:
713      __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
714      break;
715    case kMips64And:
716      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
717      break;
718    case kMips64Or:
719      __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
720      break;
721    case kMips64Nor:
722      if (instr->InputAt(1)->IsRegister()) {
723        __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
724      } else {
725        DCHECK(i.InputOperand(1).immediate() == 0);
726        __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
727      }
728      break;
729    case kMips64Xor:
730      __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
731      break;
732    case kMips64Clz:
733      __ Clz(i.OutputRegister(), i.InputRegister(0));
734      break;
735    case kMips64Dclz:
736      __ dclz(i.OutputRegister(), i.InputRegister(0));
737      break;
738    case kMips64Shl:
739      if (instr->InputAt(1)->IsRegister()) {
740        __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
741      } else {
742        int64_t imm = i.InputOperand(1).immediate();
743        __ sll(i.OutputRegister(), i.InputRegister(0),
744               static_cast<uint16_t>(imm));
745      }
746      break;
747    case kMips64Shr:
748      if (instr->InputAt(1)->IsRegister()) {
749        __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
750      } else {
751        int64_t imm = i.InputOperand(1).immediate();
752        __ srl(i.OutputRegister(), i.InputRegister(0),
753               static_cast<uint16_t>(imm));
754      }
755      break;
756    case kMips64Sar:
757      if (instr->InputAt(1)->IsRegister()) {
758        __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
759      } else {
760        int64_t imm = i.InputOperand(1).immediate();
761        __ sra(i.OutputRegister(), i.InputRegister(0),
762               static_cast<uint16_t>(imm));
763      }
764      break;
765    case kMips64Ext:
766      __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
767             i.InputInt8(2));
768      break;
769    case kMips64Ins:
770      if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
771        __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
772      } else {
773        __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
774               i.InputInt8(2));
775      }
776      break;
777    case kMips64Dext: {
778      int16_t pos = i.InputInt8(1);
779      int16_t size = i.InputInt8(2);
780      if (size > 0 && size <= 32 && pos >= 0 && pos < 32) {
781        __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
782                i.InputInt8(2));
783      } else if (size > 32 && size <= 64 && pos > 0 && pos < 32) {
784        __ Dextm(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
785                 i.InputInt8(2));
786      } else {
787        DCHECK(size > 0 && size <= 32 && pos >= 32 && pos < 64);
788        __ Dextu(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
789                 i.InputInt8(2));
790      }
791      break;
792    }
793    case kMips64Dins:
794      if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
795        __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
796      } else {
797        __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
798                i.InputInt8(2));
799      }
800      break;
801    case kMips64Dshl:
802      if (instr->InputAt(1)->IsRegister()) {
803        __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
804      } else {
805        int64_t imm = i.InputOperand(1).immediate();
806        if (imm < 32) {
807          __ dsll(i.OutputRegister(), i.InputRegister(0),
808                  static_cast<uint16_t>(imm));
809        } else {
810          __ dsll32(i.OutputRegister(), i.InputRegister(0),
811                    static_cast<uint16_t>(imm - 32));
812        }
813      }
814      break;
815    case kMips64Dshr:
816      if (instr->InputAt(1)->IsRegister()) {
817        __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
818      } else {
819        int64_t imm = i.InputOperand(1).immediate();
820        if (imm < 32) {
821          __ dsrl(i.OutputRegister(), i.InputRegister(0),
822                  static_cast<uint16_t>(imm));
823        } else {
824          __ dsrl32(i.OutputRegister(), i.InputRegister(0),
825                    static_cast<uint16_t>(imm - 32));
826        }
827      }
828      break;
829    case kMips64Dsar:
830      if (instr->InputAt(1)->IsRegister()) {
831        __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
832      } else {
833        int64_t imm = i.InputOperand(1).immediate();
834        if (imm < 32) {
835          __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
836        } else {
837          __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
838        }
839      }
840      break;
841    case kMips64Ror:
842      __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
843      break;
844    case kMips64Dror:
845      __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
846      break;
847    case kMips64Tst:
848      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
849      break;
850    case kMips64Cmp:
851      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
852      break;
853    case kMips64Mov:
854      // TODO(plind): Should we combine mov/li like this, or use separate instr?
855      //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
856      if (HasRegisterInput(instr, 0)) {
857        __ mov(i.OutputRegister(), i.InputRegister(0));
858      } else {
859        __ li(i.OutputRegister(), i.InputOperand(0));
860      }
861      break;
862
863    case kMips64CmpS:
864      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
865      break;
866    case kMips64AddS:
867      // TODO(plind): add special case: combine mult & add.
868      __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
869               i.InputDoubleRegister(1));
870      break;
871    case kMips64SubS:
872      __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
873               i.InputDoubleRegister(1));
874      break;
875    case kMips64MulS:
876      // TODO(plind): add special case: right op is -1.0, see arm port.
877      __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
878               i.InputDoubleRegister(1));
879      break;
880    case kMips64DivS:
881      __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
882               i.InputDoubleRegister(1));
883      break;
884    case kMips64ModS: {
885      // TODO(bmeurer): We should really get rid of this special instruction,
886      // and generate a CallAddress instruction instead.
887      FrameScope scope(masm(), StackFrame::MANUAL);
888      __ PrepareCallCFunction(0, 2, kScratchReg);
889      __ MovToFloatParameters(i.InputDoubleRegister(0),
890                              i.InputDoubleRegister(1));
891      // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
892      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
893                       0, 2);
894      // Move the result in the double result register.
895      __ MovFromFloatResult(i.OutputSingleRegister());
896      break;
897    }
898    case kMips64AbsS:
899      __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
900      break;
901    case kMips64SqrtS: {
902      __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
903      break;
904    }
905    case kMips64MaxS:
906      __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
907               i.InputDoubleRegister(1));
908      break;
909    case kMips64MinS:
910      __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
911               i.InputDoubleRegister(1));
912      break;
913    case kMips64CmpD:
914      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
915      break;
916    case kMips64AddD:
917      // TODO(plind): add special case: combine mult & add.
918      __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
919               i.InputDoubleRegister(1));
920      break;
921    case kMips64SubD:
922      __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
923               i.InputDoubleRegister(1));
924      break;
925    case kMips64MulD:
926      // TODO(plind): add special case: right op is -1.0, see arm port.
927      __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
928               i.InputDoubleRegister(1));
929      break;
930    case kMips64DivD:
931      __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
932               i.InputDoubleRegister(1));
933      break;
934    case kMips64ModD: {
935      // TODO(bmeurer): We should really get rid of this special instruction,
936      // and generate a CallAddress instruction instead.
937      FrameScope scope(masm(), StackFrame::MANUAL);
938      __ PrepareCallCFunction(0, 2, kScratchReg);
939      __ MovToFloatParameters(i.InputDoubleRegister(0),
940                              i.InputDoubleRegister(1));
941      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
942                       0, 2);
943      // Move the result in the double result register.
944      __ MovFromFloatResult(i.OutputDoubleRegister());
945      break;
946    }
947    case kMips64AbsD:
948      __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
949      break;
950    case kMips64SqrtD: {
951      __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
952      break;
953    }
954    case kMips64MaxD:
955      __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
956               i.InputDoubleRegister(1));
957      break;
958    case kMips64MinD:
959      __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
960               i.InputDoubleRegister(1));
961      break;
962    case kMips64Float64RoundDown: {
963      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
964      break;
965    }
966    case kMips64Float32RoundDown: {
967      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
968      break;
969    }
970    case kMips64Float64RoundTruncate: {
971      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
972      break;
973    }
974    case kMips64Float32RoundTruncate: {
975      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
976      break;
977    }
978    case kMips64Float64RoundUp: {
979      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
980      break;
981    }
982    case kMips64Float32RoundUp: {
983      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
984      break;
985    }
986    case kMips64Float64RoundTiesEven: {
987      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
988      break;
989    }
990    case kMips64Float32RoundTiesEven: {
991      ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
992      break;
993    }
994    case kMips64Float64Max: {
995      // (b < a) ? a : b
996      if (kArchVariant == kMips64r6) {
997        __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
998                 i.InputDoubleRegister(0));
999        __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1000                 i.InputDoubleRegister(0));
1001      } else {
1002        __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1003        // Left operand is result, passthrough if false.
1004        __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1005      }
1006      break;
1007    }
1008    case kMips64Float64Min: {
1009      // (a < b) ? a : b
1010      if (kArchVariant == kMips64r6) {
1011        __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1012                 i.InputDoubleRegister(1));
1013        __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1014                 i.InputDoubleRegister(0));
1015      } else {
1016        __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1017        // Right operand is result, passthrough if false.
1018        __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1019      }
1020      break;
1021    }
1022    case kMips64Float32Max: {
1023      // (b < a) ? a : b
1024      if (kArchVariant == kMips64r6) {
1025        __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1026                 i.InputDoubleRegister(0));
1027        __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1028                 i.InputDoubleRegister(0));
1029      } else {
1030        __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1031        // Left operand is result, passthrough if false.
1032        __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1033      }
1034      break;
1035    }
1036    case kMips64Float32Min: {
1037      // (a < b) ? a : b
1038      if (kArchVariant == kMips64r6) {
1039        __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1040                 i.InputDoubleRegister(1));
1041        __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1042                 i.InputDoubleRegister(0));
1043      } else {
1044        __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1045        // Right operand is result, passthrough if false.
1046        __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1047      }
1048      break;
1049    }
1050    case kMips64CvtSD:
1051      __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1052      break;
1053    case kMips64CvtDS:
1054      __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1055      break;
1056    case kMips64CvtDW: {
1057      FPURegister scratch = kScratchDoubleReg;
1058      __ mtc1(i.InputRegister(0), scratch);
1059      __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1060      break;
1061    }
1062    case kMips64CvtSW: {
1063      FPURegister scratch = kScratchDoubleReg;
1064      __ mtc1(i.InputRegister(0), scratch);
1065      __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1066      break;
1067    }
1068    case kMips64CvtSL: {
1069      FPURegister scratch = kScratchDoubleReg;
1070      __ dmtc1(i.InputRegister(0), scratch);
1071      __ cvt_s_l(i.OutputDoubleRegister(), scratch);
1072      break;
1073    }
1074    case kMips64CvtDL: {
1075      FPURegister scratch = kScratchDoubleReg;
1076      __ dmtc1(i.InputRegister(0), scratch);
1077      __ cvt_d_l(i.OutputDoubleRegister(), scratch);
1078      break;
1079    }
1080    case kMips64CvtDUw: {
1081      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1082      break;
1083    }
1084    case kMips64CvtDUl: {
1085      __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1086      break;
1087    }
1088    case kMips64CvtSUl: {
1089      __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1090      break;
1091    }
1092    case kMips64FloorWD: {
1093      FPURegister scratch = kScratchDoubleReg;
1094      __ floor_w_d(scratch, i.InputDoubleRegister(0));
1095      __ mfc1(i.OutputRegister(), scratch);
1096      break;
1097    }
1098    case kMips64CeilWD: {
1099      FPURegister scratch = kScratchDoubleReg;
1100      __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1101      __ mfc1(i.OutputRegister(), scratch);
1102      break;
1103    }
1104    case kMips64RoundWD: {
1105      FPURegister scratch = kScratchDoubleReg;
1106      __ round_w_d(scratch, i.InputDoubleRegister(0));
1107      __ mfc1(i.OutputRegister(), scratch);
1108      break;
1109    }
1110    case kMips64TruncWD: {
1111      FPURegister scratch = kScratchDoubleReg;
1112      // Other arches use round to zero here, so we follow.
1113      __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1114      __ mfc1(i.OutputRegister(), scratch);
1115      break;
1116    }
1117    case kMips64FloorWS: {
1118      FPURegister scratch = kScratchDoubleReg;
1119      __ floor_w_s(scratch, i.InputDoubleRegister(0));
1120      __ mfc1(i.OutputRegister(), scratch);
1121      break;
1122    }
1123    case kMips64CeilWS: {
1124      FPURegister scratch = kScratchDoubleReg;
1125      __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1126      __ mfc1(i.OutputRegister(), scratch);
1127      break;
1128    }
1129    case kMips64RoundWS: {
1130      FPURegister scratch = kScratchDoubleReg;
1131      __ round_w_s(scratch, i.InputDoubleRegister(0));
1132      __ mfc1(i.OutputRegister(), scratch);
1133      break;
1134    }
1135    case kMips64TruncWS: {
1136      FPURegister scratch = kScratchDoubleReg;
1137      __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1138      __ mfc1(i.OutputRegister(), scratch);
1139      break;
1140    }
1141    case kMips64TruncLS: {
1142      FPURegister scratch = kScratchDoubleReg;
1143      Register tmp_fcsr = kScratchReg;
1144      Register result = kScratchReg2;
1145
1146      bool load_status = instr->OutputCount() > 1;
1147      if (load_status) {
1148        // Save FCSR.
1149        __ cfc1(tmp_fcsr, FCSR);
1150        // Clear FPU flags.
1151        __ ctc1(zero_reg, FCSR);
1152      }
1153      // Other arches use round to zero here, so we follow.
1154      __ trunc_l_s(scratch, i.InputDoubleRegister(0));
1155      __ dmfc1(i.OutputRegister(), scratch);
1156      if (load_status) {
1157        __ cfc1(result, FCSR);
1158        // Check for overflow and NaNs.
1159        __ andi(result, result,
1160                (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1161        __ Slt(result, zero_reg, result);
1162        __ xori(result, result, 1);
1163        __ mov(i.OutputRegister(1), result);
1164        // Restore FCSR
1165        __ ctc1(tmp_fcsr, FCSR);
1166      }
1167      break;
1168    }
1169    case kMips64TruncLD: {
1170      FPURegister scratch = kScratchDoubleReg;
1171      Register tmp_fcsr = kScratchReg;
1172      Register result = kScratchReg2;
1173
1174      bool load_status = instr->OutputCount() > 1;
1175      if (load_status) {
1176        // Save FCSR.
1177        __ cfc1(tmp_fcsr, FCSR);
1178        // Clear FPU flags.
1179        __ ctc1(zero_reg, FCSR);
1180      }
1181      // Other arches use round to zero here, so we follow.
1182      __ trunc_l_d(scratch, i.InputDoubleRegister(0));
1183      __ dmfc1(i.OutputRegister(0), scratch);
1184      if (load_status) {
1185        __ cfc1(result, FCSR);
1186        // Check for overflow and NaNs.
1187        __ andi(result, result,
1188                (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1189        __ Slt(result, zero_reg, result);
1190        __ xori(result, result, 1);
1191        __ mov(i.OutputRegister(1), result);
1192        // Restore FCSR
1193        __ ctc1(tmp_fcsr, FCSR);
1194      }
1195      break;
1196    }
1197    case kMips64TruncUwD: {
1198      FPURegister scratch = kScratchDoubleReg;
1199      // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1200      __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1201      break;
1202    }
1203    case kMips64TruncUlS: {
1204      FPURegister scratch = kScratchDoubleReg;
1205      Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1206      // TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function.
1207      __ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch,
1208                    result);
1209      break;
1210    }
1211    case kMips64TruncUlD: {
1212      FPURegister scratch = kScratchDoubleReg;
1213      Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1214      // TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
1215      __ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
1216                    result);
1217      break;
1218    }
1219    case kMips64BitcastDL:
1220      __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0));
1221      break;
1222    case kMips64BitcastLD:
1223      __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister());
1224      break;
1225    case kMips64Float64ExtractLowWord32:
1226      __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1227      break;
1228    case kMips64Float64ExtractHighWord32:
1229      __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1230      break;
1231    case kMips64Float64InsertLowWord32:
1232      __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1233      break;
1234    case kMips64Float64InsertHighWord32:
1235      __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1236      break;
1237    // ... more basic instructions ...
1238
1239    case kMips64Lbu:
1240      __ lbu(i.OutputRegister(), i.MemoryOperand());
1241      break;
1242    case kMips64Lb:
1243      __ lb(i.OutputRegister(), i.MemoryOperand());
1244      break;
1245    case kMips64Sb:
1246      __ sb(i.InputRegister(2), i.MemoryOperand());
1247      break;
1248    case kMips64Lhu:
1249      __ lhu(i.OutputRegister(), i.MemoryOperand());
1250      break;
1251    case kMips64Lh:
1252      __ lh(i.OutputRegister(), i.MemoryOperand());
1253      break;
1254    case kMips64Sh:
1255      __ sh(i.InputRegister(2), i.MemoryOperand());
1256      break;
1257    case kMips64Lw:
1258      __ lw(i.OutputRegister(), i.MemoryOperand());
1259      break;
1260    case kMips64Ld:
1261      __ ld(i.OutputRegister(), i.MemoryOperand());
1262      break;
1263    case kMips64Sw:
1264      __ sw(i.InputRegister(2), i.MemoryOperand());
1265      break;
1266    case kMips64Sd:
1267      __ sd(i.InputRegister(2), i.MemoryOperand());
1268      break;
1269    case kMips64Lwc1: {
1270      __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1271      break;
1272    }
1273    case kMips64Swc1: {
1274      size_t index = 0;
1275      MemOperand operand = i.MemoryOperand(&index);
1276      __ swc1(i.InputSingleRegister(index), operand);
1277      break;
1278    }
1279    case kMips64Ldc1:
1280      __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1281      break;
1282    case kMips64Sdc1:
1283      __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
1284      break;
1285    case kMips64Push:
1286      if (instr->InputAt(0)->IsDoubleRegister()) {
1287        __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1288        __ Subu(sp, sp, Operand(kDoubleSize));
1289        frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1290      } else {
1291        __ Push(i.InputRegister(0));
1292        frame_access_state()->IncreaseSPDelta(1);
1293      }
1294      break;
1295    case kMips64StackClaim: {
1296      __ Dsubu(sp, sp, Operand(i.InputInt32(0)));
1297      frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
1298      break;
1299    }
1300    case kMips64StoreToStackSlot: {
1301      if (instr->InputAt(0)->IsDoubleRegister()) {
1302        __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1303      } else {
1304        __ sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1305      }
1306      break;
1307    }
1308    case kCheckedLoadInt8:
1309      ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
1310      break;
1311    case kCheckedLoadUint8:
1312      ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
1313      break;
1314    case kCheckedLoadInt16:
1315      ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
1316      break;
1317    case kCheckedLoadUint16:
1318      ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
1319      break;
1320    case kCheckedLoadWord32:
1321      ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
1322      break;
1323    case kCheckedLoadWord64:
1324      ASSEMBLE_CHECKED_LOAD_INTEGER(ld);
1325      break;
1326    case kCheckedLoadFloat32:
1327      ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
1328      break;
1329    case kCheckedLoadFloat64:
1330      ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
1331      break;
1332    case kCheckedStoreWord8:
1333      ASSEMBLE_CHECKED_STORE_INTEGER(sb);
1334      break;
1335    case kCheckedStoreWord16:
1336      ASSEMBLE_CHECKED_STORE_INTEGER(sh);
1337      break;
1338    case kCheckedStoreWord32:
1339      ASSEMBLE_CHECKED_STORE_INTEGER(sw);
1340      break;
1341    case kCheckedStoreWord64:
1342      ASSEMBLE_CHECKED_STORE_INTEGER(sd);
1343      break;
1344    case kCheckedStoreFloat32:
1345      ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
1346      break;
1347    case kCheckedStoreFloat64:
1348      ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
1349      break;
1350  }
1351}  // NOLINT(readability/fn_size)
1352
1353
1354#define UNSUPPORTED_COND(opcode, condition)                                  \
1355  OFStream out(stdout);                                                      \
1356  out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
1357  UNIMPLEMENTED();
1358
1359static bool convertCondition(FlagsCondition condition, Condition& cc) {
1360  switch (condition) {
1361    case kEqual:
1362      cc = eq;
1363      return true;
1364    case kNotEqual:
1365      cc = ne;
1366      return true;
1367    case kUnsignedLessThan:
1368      cc = lt;
1369      return true;
1370    case kUnsignedGreaterThanOrEqual:
1371      cc = uge;
1372      return true;
1373    case kUnsignedLessThanOrEqual:
1374      cc = le;
1375      return true;
1376    case kUnsignedGreaterThan:
1377      cc = ugt;
1378      return true;
1379    default:
1380      break;
1381  }
1382  return false;
1383}
1384
1385
1386// Assembles branches after an instruction.
1387void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1388  MipsOperandConverter i(this, instr);
1389  Label* tlabel = branch->true_label;
1390  Label* flabel = branch->false_label;
1391  Condition cc = kNoCondition;
1392  // MIPS does not have condition code flags, so compare and branch are
1393  // implemented differently than on the other arch's. The compare operations
1394  // emit mips psuedo-instructions, which are handled here by branch
1395  // instructions that do the actual comparison. Essential that the input
1396  // registers to compare pseudo-op are not modified before this branch op, as
1397  // they are tested here.
1398
1399  if (instr->arch_opcode() == kMips64Tst) {
1400    cc = FlagsConditionToConditionTst(branch->condition);
1401    __ And(at, i.InputRegister(0), i.InputOperand(1));
1402    __ Branch(tlabel, cc, at, Operand(zero_reg));
1403  } else if (instr->arch_opcode() == kMips64Dadd ||
1404             instr->arch_opcode() == kMips64Dsub) {
1405    cc = FlagsConditionToConditionOvf(branch->condition);
1406    __ dsra32(kScratchReg, i.OutputRegister(), 0);
1407    __ sra(at, i.OutputRegister(), 31);
1408    __ Branch(tlabel, cc, at, Operand(kScratchReg));
1409  } else if (instr->arch_opcode() == kMips64DaddOvf) {
1410    switch (branch->condition) {
1411      case kOverflow:
1412        __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1413                         i.InputOperand(1), tlabel, flabel);
1414        break;
1415      case kNotOverflow:
1416        __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1417                         i.InputOperand(1), flabel, tlabel);
1418        break;
1419      default:
1420        UNSUPPORTED_COND(kMips64DaddOvf, branch->condition);
1421        break;
1422    }
1423  } else if (instr->arch_opcode() == kMips64DsubOvf) {
1424    switch (branch->condition) {
1425      case kOverflow:
1426        __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1427                         i.InputOperand(1), tlabel, flabel);
1428        break;
1429      case kNotOverflow:
1430        __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1431                         i.InputOperand(1), flabel, tlabel);
1432        break;
1433      default:
1434        UNSUPPORTED_COND(kMips64DsubOvf, branch->condition);
1435        break;
1436    }
1437  } else if (instr->arch_opcode() == kMips64Cmp) {
1438    cc = FlagsConditionToConditionCmp(branch->condition);
1439    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
1440  } else if (instr->arch_opcode() == kMips64CmpS) {
1441    if (!convertCondition(branch->condition, cc)) {
1442      UNSUPPORTED_COND(kMips64CmpS, branch->condition);
1443    }
1444    FPURegister left = i.InputOrZeroSingleRegister(0);
1445    FPURegister right = i.InputOrZeroSingleRegister(1);
1446    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1447        !__ IsDoubleZeroRegSet()) {
1448      __ Move(kDoubleRegZero, 0.0);
1449    }
1450    __ BranchF32(tlabel, nullptr, cc, left, right);
1451  } else if (instr->arch_opcode() == kMips64CmpD) {
1452    if (!convertCondition(branch->condition, cc)) {
1453      UNSUPPORTED_COND(kMips64CmpD, branch->condition);
1454    }
1455    FPURegister left = i.InputOrZeroDoubleRegister(0);
1456    FPURegister right = i.InputOrZeroDoubleRegister(1);
1457    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1458        !__ IsDoubleZeroRegSet()) {
1459      __ Move(kDoubleRegZero, 0.0);
1460    }
1461    __ BranchF64(tlabel, nullptr, cc, left, right);
1462  } else {
1463    PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
1464           instr->arch_opcode());
1465    UNIMPLEMENTED();
1466  }
1467  if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
1468}
1469
1470
1471void CodeGenerator::AssembleArchJump(RpoNumber target) {
1472  if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
1473}
1474
1475
1476// Assembles boolean materializations after an instruction.
1477void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1478                                        FlagsCondition condition) {
1479  MipsOperandConverter i(this, instr);
1480  Label done;
1481
1482  // Materialize a full 32-bit 1 or 0 value. The result register is always the
1483  // last output of the instruction.
1484  Label false_value;
1485  DCHECK_NE(0u, instr->OutputCount());
1486  Register result = i.OutputRegister(instr->OutputCount() - 1);
1487  Condition cc = kNoCondition;
1488  // MIPS does not have condition code flags, so compare and branch are
1489  // implemented differently than on the other arch's. The compare operations
1490  // emit mips pseudo-instructions, which are checked and handled here.
1491
1492  if (instr->arch_opcode() == kMips64Tst) {
1493    cc = FlagsConditionToConditionTst(condition);
1494    __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1495    __ Sltu(result, zero_reg, kScratchReg);
1496    if (cc == eq) {
1497      // Sltu produces 0 for equality, invert the result.
1498      __ xori(result, result, 1);
1499    }
1500    return;
1501  } else if (instr->arch_opcode() == kMips64Dadd ||
1502             instr->arch_opcode() == kMips64Dsub) {
1503    cc = FlagsConditionToConditionOvf(condition);
1504    // Check for overflow creates 1 or 0 for result.
1505    __ dsrl32(kScratchReg, i.OutputRegister(), 31);
1506    __ srl(at, i.OutputRegister(), 31);
1507    __ xor_(result, kScratchReg, at);
1508    if (cc == eq)  // Toggle result for not overflow.
1509      __ xori(result, result, 1);
1510    return;
1511  } else if (instr->arch_opcode() == kMips64DaddOvf ||
1512             instr->arch_opcode() == kMips64DsubOvf) {
1513    Label flabel, tlabel;
1514    switch (instr->arch_opcode()) {
1515      case kMips64DaddOvf:
1516        __ DaddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1517                           i.InputOperand(1), &flabel);
1518
1519        break;
1520      case kMips64DsubOvf:
1521        __ DsubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1522                           i.InputOperand(1), &flabel);
1523        break;
1524      default:
1525        UNREACHABLE();
1526        break;
1527    }
1528    __ li(result, 1);
1529    __ Branch(&tlabel);
1530    __ bind(&flabel);
1531    __ li(result, 0);
1532    __ bind(&tlabel);
1533  } else if (instr->arch_opcode() == kMips64Cmp) {
1534    cc = FlagsConditionToConditionCmp(condition);
1535    switch (cc) {
1536      case eq:
1537      case ne: {
1538        Register left = i.InputRegister(0);
1539        Operand right = i.InputOperand(1);
1540        Register select;
1541        if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) {
1542          // Pass left operand if right is zero.
1543          select = left;
1544        } else {
1545          __ Dsubu(kScratchReg, left, right);
1546          select = kScratchReg;
1547        }
1548        __ Sltu(result, zero_reg, select);
1549        if (cc == eq) {
1550          // Sltu produces 0 for equality, invert the result.
1551          __ xori(result, result, 1);
1552        }
1553      } break;
1554      case lt:
1555      case ge: {
1556        Register left = i.InputRegister(0);
1557        Operand right = i.InputOperand(1);
1558        __ Slt(result, left, right);
1559        if (cc == ge) {
1560          __ xori(result, result, 1);
1561        }
1562      } break;
1563      case gt:
1564      case le: {
1565        Register left = i.InputRegister(1);
1566        Operand right = i.InputOperand(0);
1567        __ Slt(result, left, right);
1568        if (cc == le) {
1569          __ xori(result, result, 1);
1570        }
1571      } break;
1572      case lo:
1573      case hs: {
1574        Register left = i.InputRegister(0);
1575        Operand right = i.InputOperand(1);
1576        __ Sltu(result, left, right);
1577        if (cc == hs) {
1578          __ xori(result, result, 1);
1579        }
1580      } break;
1581      case hi:
1582      case ls: {
1583        Register left = i.InputRegister(1);
1584        Operand right = i.InputOperand(0);
1585        __ Sltu(result, left, right);
1586        if (cc == ls) {
1587          __ xori(result, result, 1);
1588        }
1589      } break;
1590      default:
1591        UNREACHABLE();
1592    }
1593    return;
1594  } else if (instr->arch_opcode() == kMips64CmpD ||
1595             instr->arch_opcode() == kMips64CmpS) {
1596    FPURegister left = i.InputOrZeroDoubleRegister(0);
1597    FPURegister right = i.InputOrZeroDoubleRegister(1);
1598    if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1599        !__ IsDoubleZeroRegSet()) {
1600      __ Move(kDoubleRegZero, 0.0);
1601    }
1602    bool predicate;
1603    FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
1604    if (kArchVariant != kMips64r6) {
1605      __ li(result, Operand(1));
1606      if (instr->arch_opcode() == kMips64CmpD) {
1607        __ c(cc, D, left, right);
1608      } else {
1609        DCHECK(instr->arch_opcode() == kMips64CmpS);
1610        __ c(cc, S, left, right);
1611      }
1612      if (predicate) {
1613        __ Movf(result, zero_reg);
1614      } else {
1615        __ Movt(result, zero_reg);
1616      }
1617    } else {
1618      if (instr->arch_opcode() == kMips64CmpD) {
1619        __ cmp(cc, L, kDoubleCompareReg, left, right);
1620      } else {
1621        DCHECK(instr->arch_opcode() == kMips64CmpS);
1622        __ cmp(cc, W, kDoubleCompareReg, left, right);
1623      }
1624      __ dmfc1(result, kDoubleCompareReg);
1625      __ andi(result, result, 1);  // Cmp returns all 1's/0's, use only LSB.
1626
1627      if (!predicate)  // Toggle result for not equal.
1628        __ xori(result, result, 1);
1629    }
1630    return;
1631  } else {
1632    PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
1633           instr->arch_opcode());
1634    TRACE_UNIMPL();
1635    UNIMPLEMENTED();
1636  }
1637}
1638
1639
1640void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1641  MipsOperandConverter i(this, instr);
1642  Register input = i.InputRegister(0);
1643  for (size_t index = 2; index < instr->InputCount(); index += 2) {
1644    __ li(at, Operand(i.InputInt32(index + 0)));
1645    __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
1646  }
1647  __ nop();  // Branch delay slot of the last beq.
1648  AssembleArchJump(i.InputRpo(1));
1649}
1650
1651
1652void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1653  MipsOperandConverter i(this, instr);
1654  Register input = i.InputRegister(0);
1655  size_t const case_count = instr->InputCount() - 2;
1656  Label here;
1657
1658  __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
1659  __ BlockTrampolinePoolFor(static_cast<int>(case_count) * 2 + 7);
1660  // Ensure that dd-ed labels use 8 byte aligned addresses.
1661  __ Align(8);
1662  __ bal(&here);
1663  __ dsll(at, input, 3);  // Branch delay slot.
1664  __ bind(&here);
1665  __ daddu(at, at, ra);
1666  __ ld(at, MemOperand(at, 4 * v8::internal::Assembler::kInstrSize));
1667  __ jr(at);
1668  __ nop();  // Branch delay slot nop.
1669  for (size_t index = 0; index < case_count; ++index) {
1670    __ dd(GetLabel(i.InputRpo(index + 2)));
1671  }
1672}
1673
1674
1675void CodeGenerator::AssembleDeoptimizerCall(
1676    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
1677  Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
1678      isolate(), deoptimization_id, bailout_type);
1679  __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1680}
1681
1682
1683void CodeGenerator::AssemblePrologue() {
1684  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1685  if (descriptor->IsCFunctionCall()) {
1686    __ Push(ra, fp);
1687    __ mov(fp, sp);
1688  } else if (descriptor->IsJSFunctionCall()) {
1689    __ Prologue(this->info()->GeneratePreagedPrologue());
1690  } else if (frame()->needs_frame()) {
1691    __ StubPrologue();
1692  } else {
1693    frame()->SetElidedFrameSizeInSlots(0);
1694  }
1695  frame_access_state()->SetFrameAccessToDefault();
1696
1697  int stack_shrink_slots = frame()->GetSpillSlotCount();
1698  if (info()->is_osr()) {
1699    // TurboFan OSR-compiled functions cannot be entered directly.
1700    __ Abort(kShouldNotDirectlyEnterOsrFunction);
1701
1702    // Unoptimized code jumps directly to this entrypoint while the unoptimized
1703    // frame is still on the stack. Optimized code uses OSR values directly from
1704    // the unoptimized frame. Thus, all that needs to be done is to allocate the
1705    // remaining stack slots.
1706    if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1707    osr_pc_offset_ = __ pc_offset();
1708    // TODO(titzer): cannot address target function == local #-1
1709    __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1710    stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
1711  }
1712
1713  if (stack_shrink_slots > 0) {
1714    __ Dsubu(sp, sp, Operand(stack_shrink_slots * kPointerSize));
1715  }
1716
1717  const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1718  if (saves_fpu != 0) {
1719    // Save callee-saved FPU registers.
1720    __ MultiPushFPU(saves_fpu);
1721    int count = base::bits::CountPopulation32(saves_fpu);
1722    DCHECK(kNumCalleeSavedFPU == count);
1723    frame()->AllocateSavedCalleeRegisterSlots(count *
1724                                              (kDoubleSize / kPointerSize));
1725  }
1726
1727  const RegList saves = descriptor->CalleeSavedRegisters();
1728  if (saves != 0) {
1729    // Save callee-saved registers.
1730    __ MultiPush(saves);
1731    // kNumCalleeSaved includes the fp register, but the fp register
1732    // is saved separately in TF.
1733    int count = base::bits::CountPopulation32(saves);
1734    DCHECK(kNumCalleeSaved == count + 1);
1735    frame()->AllocateSavedCalleeRegisterSlots(count);
1736  }
1737}
1738
1739
1740void CodeGenerator::AssembleReturn() {
1741  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1742
1743  // Restore GP registers.
1744  const RegList saves = descriptor->CalleeSavedRegisters();
1745  if (saves != 0) {
1746    __ MultiPop(saves);
1747  }
1748
1749  // Restore FPU registers.
1750  const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1751  if (saves_fpu != 0) {
1752    __ MultiPopFPU(saves_fpu);
1753  }
1754
1755  if (descriptor->IsCFunctionCall()) {
1756    __ mov(sp, fp);
1757    __ Pop(ra, fp);
1758  } else if (frame()->needs_frame()) {
1759    // Canonicalize JSFunction return sites for now.
1760    if (return_label_.is_bound()) {
1761      __ Branch(&return_label_);
1762      return;
1763    } else {
1764      __ bind(&return_label_);
1765      __ mov(sp, fp);
1766      __ Pop(ra, fp);
1767    }
1768  }
1769  int pop_count = static_cast<int>(descriptor->StackParameterCount());
1770  if (pop_count != 0) {
1771    __ DropAndRet(pop_count);
1772  } else {
1773    __ Ret();
1774  }
1775}
1776
1777
1778void CodeGenerator::AssembleMove(InstructionOperand* source,
1779                                 InstructionOperand* destination) {
1780  MipsOperandConverter g(this, nullptr);
1781  // Dispatch on the source and destination operand kinds.  Not all
1782  // combinations are possible.
1783  if (source->IsRegister()) {
1784    DCHECK(destination->IsRegister() || destination->IsStackSlot());
1785    Register src = g.ToRegister(source);
1786    if (destination->IsRegister()) {
1787      __ mov(g.ToRegister(destination), src);
1788    } else {
1789      __ sd(src, g.ToMemOperand(destination));
1790    }
1791  } else if (source->IsStackSlot()) {
1792    DCHECK(destination->IsRegister() || destination->IsStackSlot());
1793    MemOperand src = g.ToMemOperand(source);
1794    if (destination->IsRegister()) {
1795      __ ld(g.ToRegister(destination), src);
1796    } else {
1797      Register temp = kScratchReg;
1798      __ ld(temp, src);
1799      __ sd(temp, g.ToMemOperand(destination));
1800    }
1801  } else if (source->IsConstant()) {
1802    Constant src = g.ToConstant(source);
1803    if (destination->IsRegister() || destination->IsStackSlot()) {
1804      Register dst =
1805          destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
1806      switch (src.type()) {
1807        case Constant::kInt32:
1808          __ li(dst, Operand(src.ToInt32()));
1809          break;
1810        case Constant::kFloat32:
1811          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1812          break;
1813        case Constant::kInt64:
1814          __ li(dst, Operand(src.ToInt64()));
1815          break;
1816        case Constant::kFloat64:
1817          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1818          break;
1819        case Constant::kExternalReference:
1820          __ li(dst, Operand(src.ToExternalReference()));
1821          break;
1822        case Constant::kHeapObject: {
1823          Handle<HeapObject> src_object = src.ToHeapObject();
1824          Heap::RootListIndex index;
1825          int offset;
1826          if (IsMaterializableFromFrame(src_object, &offset)) {
1827            __ ld(dst, MemOperand(fp, offset));
1828          } else if (IsMaterializableFromRoot(src_object, &index)) {
1829            __ LoadRoot(dst, index);
1830          } else {
1831            __ li(dst, src_object);
1832          }
1833          break;
1834        }
1835        case Constant::kRpoNumber:
1836          UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
1837          break;
1838      }
1839      if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
1840    } else if (src.type() == Constant::kFloat32) {
1841      if (destination->IsDoubleStackSlot()) {
1842        MemOperand dst = g.ToMemOperand(destination);
1843        __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
1844        __ sw(at, dst);
1845      } else {
1846        FloatRegister dst = g.ToSingleRegister(destination);
1847        __ Move(dst, src.ToFloat32());
1848      }
1849    } else {
1850      DCHECK_EQ(Constant::kFloat64, src.type());
1851      DoubleRegister dst = destination->IsDoubleRegister()
1852                               ? g.ToDoubleRegister(destination)
1853                               : kScratchDoubleReg;
1854      __ Move(dst, src.ToFloat64());
1855      if (destination->IsDoubleStackSlot()) {
1856        __ sdc1(dst, g.ToMemOperand(destination));
1857      }
1858    }
1859  } else if (source->IsDoubleRegister()) {
1860    FPURegister src = g.ToDoubleRegister(source);
1861    if (destination->IsDoubleRegister()) {
1862      FPURegister dst = g.ToDoubleRegister(destination);
1863      __ Move(dst, src);
1864    } else {
1865      DCHECK(destination->IsDoubleStackSlot());
1866      __ sdc1(src, g.ToMemOperand(destination));
1867    }
1868  } else if (source->IsDoubleStackSlot()) {
1869    DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1870    MemOperand src = g.ToMemOperand(source);
1871    if (destination->IsDoubleRegister()) {
1872      __ ldc1(g.ToDoubleRegister(destination), src);
1873    } else {
1874      FPURegister temp = kScratchDoubleReg;
1875      __ ldc1(temp, src);
1876      __ sdc1(temp, g.ToMemOperand(destination));
1877    }
1878  } else {
1879    UNREACHABLE();
1880  }
1881}
1882
1883
1884void CodeGenerator::AssembleSwap(InstructionOperand* source,
1885                                 InstructionOperand* destination) {
1886  MipsOperandConverter g(this, nullptr);
1887  // Dispatch on the source and destination operand kinds.  Not all
1888  // combinations are possible.
1889  if (source->IsRegister()) {
1890    // Register-register.
1891    Register temp = kScratchReg;
1892    Register src = g.ToRegister(source);
1893    if (destination->IsRegister()) {
1894      Register dst = g.ToRegister(destination);
1895      __ Move(temp, src);
1896      __ Move(src, dst);
1897      __ Move(dst, temp);
1898    } else {
1899      DCHECK(destination->IsStackSlot());
1900      MemOperand dst = g.ToMemOperand(destination);
1901      __ mov(temp, src);
1902      __ ld(src, dst);
1903      __ sd(temp, dst);
1904    }
1905  } else if (source->IsStackSlot()) {
1906    DCHECK(destination->IsStackSlot());
1907    Register temp_0 = kScratchReg;
1908    Register temp_1 = kScratchReg2;
1909    MemOperand src = g.ToMemOperand(source);
1910    MemOperand dst = g.ToMemOperand(destination);
1911    __ ld(temp_0, src);
1912    __ ld(temp_1, dst);
1913    __ sd(temp_0, dst);
1914    __ sd(temp_1, src);
1915  } else if (source->IsDoubleRegister()) {
1916    FPURegister temp = kScratchDoubleReg;
1917    FPURegister src = g.ToDoubleRegister(source);
1918    if (destination->IsDoubleRegister()) {
1919      FPURegister dst = g.ToDoubleRegister(destination);
1920      __ Move(temp, src);
1921      __ Move(src, dst);
1922      __ Move(dst, temp);
1923    } else {
1924      DCHECK(destination->IsDoubleStackSlot());
1925      MemOperand dst = g.ToMemOperand(destination);
1926      __ Move(temp, src);
1927      __ ldc1(src, dst);
1928      __ sdc1(temp, dst);
1929    }
1930  } else if (source->IsDoubleStackSlot()) {
1931    DCHECK(destination->IsDoubleStackSlot());
1932    Register temp_0 = kScratchReg;
1933    FPURegister temp_1 = kScratchDoubleReg;
1934    MemOperand src0 = g.ToMemOperand(source);
1935    MemOperand src1(src0.rm(), src0.offset() + kIntSize);
1936    MemOperand dst0 = g.ToMemOperand(destination);
1937    MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
1938    __ ldc1(temp_1, dst0);  // Save destination in temp_1.
1939    __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
1940    __ sw(temp_0, dst0);
1941    __ lw(temp_0, src1);
1942    __ sw(temp_0, dst1);
1943    __ sdc1(temp_1, src0);
1944  } else {
1945    // No other combinations are possible.
1946    UNREACHABLE();
1947  }
1948}
1949
1950
1951void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1952  // On 64-bit MIPS we emit the jump tables inline.
1953  UNREACHABLE();
1954}
1955
1956
1957void CodeGenerator::AddNopForSmiCodeInlining() {
1958  // Unused on 32-bit ARM. Still exists on 64-bit arm.
1959  // TODO(plind): Unclear when this is called now. Understand, fix if needed.
1960  __ nop();  // Maybe PROPERTY_ACCESS_INLINED?
1961}
1962
1963
1964void CodeGenerator::EnsureSpaceForLazyDeopt() {
1965  if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1966    return;
1967  }
1968
1969  int space_needed = Deoptimizer::patch_size();
1970  // Ensure that we have enough space after the previous lazy-bailout
1971  // instruction for patching the code here.
1972  int current_pc = masm()->pc_offset();
1973  if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1974    // Block tramoline pool emission for duration of padding.
1975    v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
1976        masm());
1977    int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1978    DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1979    while (padding_size > 0) {
1980      __ nop();
1981      padding_size -= v8::internal::Assembler::kInstrSize;
1982    }
1983  }
1984}
1985
1986#undef __
1987
1988}  // namespace compiler
1989}  // namespace internal
1990}  // namespace v8
1991