60e016fa2281eed086be33ec69fbc65f9f2f1273
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / mips64 / code-generator-mips64.cc
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/compiler/code-generator-impl.h"
7 #include "src/compiler/gap-resolver.h"
8 #include "src/compiler/node-matchers.h"
9 #include "src/mips/macro-assembler-mips.h"
10 #include "src/scopes.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
16 #define __ masm()->
17
18
19 // TODO(plind): Possibly avoid using these lithium names.
20 #define kScratchReg kLithiumScratchReg
21 #define kScratchReg2 kLithiumScratchReg2
22 #define kScratchDoubleReg kLithiumScratchDouble
23
24
25 // TODO(plind): consider renaming these macros.
26 #define TRACE_MSG(msg)                                                      \
27   PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
28          __LINE__)
29
30 #define TRACE_UNIMPL()                                                       \
31   PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
32          __LINE__)
33
34
35 // Adds Mips-specific methods to convert InstructionOperands.
36 class MipsOperandConverter FINAL : public InstructionOperandConverter {
37  public:
38   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
39       : InstructionOperandConverter(gen, instr) {}
40
41   FloatRegister OutputSingleRegister(int index = 0) {
42     return ToSingleRegister(instr_->OutputAt(index));
43   }
44
45   FloatRegister InputSingleRegister(int index) {
46     return ToSingleRegister(instr_->InputAt(index));
47   }
48
49   FloatRegister ToSingleRegister(InstructionOperand* op) {
50     // Single (Float) and Double register namespace is same on MIPS,
51     // both are typedefs of FPURegister.
52     return ToDoubleRegister(op);
53   }
54
55   Operand InputImmediate(int index) {
56     Constant constant = ToConstant(instr_->InputAt(index));
57     switch (constant.type()) {
58       case Constant::kInt32:
59         return Operand(constant.ToInt32());
60       case Constant::kInt64:
61         return Operand(constant.ToInt64());
62       case Constant::kFloat32:
63         return Operand(
64             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
65       case Constant::kFloat64:
66         return Operand(
67             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
68       case Constant::kExternalReference:
69       case Constant::kHeapObject:
70         // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
71         //    maybe not done on arm due to const pool ??
72         break;
73       case Constant::kRpoNumber:
74         UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
75         break;
76     }
77     UNREACHABLE();
78     return Operand(zero_reg);
79   }
80
81   Operand InputOperand(int index) {
82     InstructionOperand* op = instr_->InputAt(index);
83     if (op->IsRegister()) {
84       return Operand(ToRegister(op));
85     }
86     return InputImmediate(index);
87   }
88
89   MemOperand MemoryOperand(int* first_index) {
90     const int index = *first_index;
91     switch (AddressingModeField::decode(instr_->opcode())) {
92       case kMode_None:
93         break;
94       case kMode_MRI:
95         *first_index += 2;
96         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
97       case kMode_MRR:
98         // TODO(plind): r6 address mode, to be implemented ...
99         UNREACHABLE();
100     }
101     UNREACHABLE();
102     return MemOperand(no_reg);
103   }
104
105   MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
106
107   MemOperand ToMemOperand(InstructionOperand* op) const {
108     DCHECK(op != NULL);
109     DCHECK(!op->IsRegister());
110     DCHECK(!op->IsDoubleRegister());
111     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
112     // The linkage computes where all spill slots are located.
113     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
114     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
115   }
116 };
117
118
119 static inline bool HasRegisterInput(Instruction* instr, int index) {
120   return instr->InputAt(index)->IsRegister();
121 }
122
123
124 namespace {
125
126 class OutOfLineLoadSingle FINAL : public OutOfLineCode {
127  public:
128   OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
129       : OutOfLineCode(gen), result_(result) {}
130
131   void Generate() FINAL {
132     __ Move(result_, std::numeric_limits<float>::quiet_NaN());
133   }
134
135  private:
136   FloatRegister const result_;
137 };
138
139
140 class OutOfLineLoadDouble FINAL : public OutOfLineCode {
141  public:
142   OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
143       : OutOfLineCode(gen), result_(result) {}
144
145   void Generate() FINAL {
146     __ Move(result_, std::numeric_limits<double>::quiet_NaN());
147   }
148
149  private:
150   DoubleRegister const result_;
151 };
152
153
154 class OutOfLineLoadInteger FINAL : public OutOfLineCode {
155  public:
156   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
157       : OutOfLineCode(gen), result_(result) {}
158
159   void Generate() FINAL { __ mov(result_, zero_reg); }
160
161  private:
162   Register const result_;
163 };
164
165
166 class OutOfLineRound : public OutOfLineCode {
167  public:
168   OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
169       : OutOfLineCode(gen), result_(result) {}
170
171   void Generate() FINAL {
172     // Handle rounding to zero case where sign has to be preserved.
173     // High bits of double input already in kScratchReg.
174     __ dsrl(at, kScratchReg, 31);
175     __ dsll(at, at, 31);
176     __ mthc1(at, result_);
177   }
178
179  private:
180   DoubleRegister const result_;
181 };
182
183
184 class OutOfLineTruncate FINAL : public OutOfLineRound {
185  public:
186   OutOfLineTruncate(CodeGenerator* gen, DoubleRegister result)
187       : OutOfLineRound(gen, result) {}
188 };
189
190
191 class OutOfLineFloor FINAL : public OutOfLineRound {
192  public:
193   OutOfLineFloor(CodeGenerator* gen, DoubleRegister result)
194       : OutOfLineRound(gen, result) {}
195 };
196
197
198 class OutOfLineCeil FINAL : public OutOfLineRound {
199  public:
200   OutOfLineCeil(CodeGenerator* gen, DoubleRegister result)
201       : OutOfLineRound(gen, result) {}
202 };
203
204
205 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
206   switch (condition) {
207     case kEqual:
208       return eq;
209     case kNotEqual:
210       return ne;
211     case kSignedLessThan:
212       return lt;
213     case kSignedGreaterThanOrEqual:
214       return ge;
215     case kSignedLessThanOrEqual:
216       return le;
217     case kSignedGreaterThan:
218       return gt;
219     case kUnsignedLessThan:
220       return lo;
221     case kUnsignedGreaterThanOrEqual:
222       return hs;
223     case kUnsignedLessThanOrEqual:
224       return ls;
225     case kUnsignedGreaterThan:
226       return hi;
227     case kUnorderedEqual:
228     case kUnorderedNotEqual:
229       break;
230     default:
231       break;
232   }
233   UNREACHABLE();
234   return kNoCondition;
235 }
236
237
238 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
239   switch (condition) {
240     case kNotEqual:
241       return ne;
242     case kEqual:
243       return eq;
244     default:
245       break;
246   }
247   UNREACHABLE();
248   return kNoCondition;
249 }
250
251
252 Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
253   switch (condition) {
254     case kOverflow:
255       return ne;
256     case kNotOverflow:
257       return eq;
258     default:
259       break;
260   }
261   UNREACHABLE();
262   return kNoCondition;
263 }
264
265
266 FPUCondition FlagsConditionToConditionCmpD(bool& predicate,
267                                            FlagsCondition condition) {
268   switch (condition) {
269     case kEqual:
270       predicate = true;
271       return EQ;
272     case kNotEqual:
273       predicate = false;
274       return EQ;
275     case kUnsignedLessThan:
276       predicate = true;
277       return OLT;
278     case kUnsignedGreaterThanOrEqual:
279       predicate = false;
280       return ULT;
281     case kUnsignedLessThanOrEqual:
282       predicate = true;
283       return OLE;
284     case kUnsignedGreaterThan:
285       predicate = false;
286       return ULE;
287     case kUnorderedEqual:
288     case kUnorderedNotEqual:
289       predicate = true;
290       break;
291     default:
292       predicate = true;
293       break;
294   }
295   UNREACHABLE();
296   return kNoFPUCondition;
297 }
298
299 }  // namespace
300
301
302 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
303   do {                                                                        \
304     auto result = i.Output##width##Register();                                \
305     auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
306     if (instr->InputAt(0)->IsRegister()) {                                    \
307       auto offset = i.InputRegister(0);                                       \
308       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
309       __ Daddu(at, i.InputRegister(2), offset);                               \
310       __ asm_instr(result, MemOperand(at, 0));                                \
311     } else {                                                                  \
312       auto offset = i.InputOperand(0).immediate();                            \
313       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
314       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
315     }                                                                         \
316     __ bind(ool->exit());                                                     \
317   } while (0)
318
319
320 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
321   do {                                                                        \
322     auto result = i.OutputRegister();                                         \
323     auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
324     if (instr->InputAt(0)->IsRegister()) {                                    \
325       auto offset = i.InputRegister(0);                                       \
326       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
327       __ Daddu(at, i.InputRegister(2), offset);                               \
328       __ asm_instr(result, MemOperand(at, 0));                                \
329     } else {                                                                  \
330       auto offset = i.InputOperand(0).immediate();                            \
331       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
332       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
333     }                                                                         \
334     __ bind(ool->exit());                                                     \
335   } while (0)
336
337
338 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
339   do {                                                                 \
340     Label done;                                                        \
341     if (instr->InputAt(0)->IsRegister()) {                             \
342       auto offset = i.InputRegister(0);                                \
343       auto value = i.Input##width##Register(2);                        \
344       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
345       __ Daddu(at, i.InputRegister(3), offset);                        \
346       __ asm_instr(value, MemOperand(at, 0));                          \
347     } else {                                                           \
348       auto offset = i.InputOperand(0).immediate();                     \
349       auto value = i.Input##width##Register(2);                        \
350       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
351       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
352     }                                                                  \
353     __ bind(&done);                                                    \
354   } while (0)
355
356
357 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
358   do {                                                                 \
359     Label done;                                                        \
360     if (instr->InputAt(0)->IsRegister()) {                             \
361       auto offset = i.InputRegister(0);                                \
362       auto value = i.InputRegister(2);                                 \
363       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
364       __ Daddu(at, i.InputRegister(3), offset);                        \
365       __ asm_instr(value, MemOperand(at, 0));                          \
366     } else {                                                           \
367       auto offset = i.InputOperand(0).immediate();                     \
368       auto value = i.InputRegister(2);                                 \
369       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
370       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
371     }                                                                  \
372     __ bind(&done);                                                    \
373   } while (0)
374
375
376 #define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(asm_instr, operation)                  \
377   do {                                                                         \
378     auto ool =                                                                 \
379         new (zone()) OutOfLine##operation(this, i.OutputDoubleRegister());     \
380     Label done;                                                                \
381     __ mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
382     __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
383            HeapNumber::kExponentBits);                                         \
384     __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
385               Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
386     __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
387     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));          \
388     __ dmfc1(at, i.OutputDoubleRegister());                                    \
389     __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
390     __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
391     __ bind(ool->exit());                                                      \
392     __ bind(&done);                                                            \
393   } while (0)
394
395
396 // Assembles an instruction after register allocation, producing machine code.
397 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
398   MipsOperandConverter i(this, instr);
399   InstructionCode opcode = instr->opcode();
400
401   switch (ArchOpcodeField::decode(opcode)) {
402     case kArchCallCodeObject: {
403       EnsureSpaceForLazyDeopt();
404       if (instr->InputAt(0)->IsImmediate()) {
405         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
406                 RelocInfo::CODE_TARGET);
407       } else {
408         __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
409         __ Call(at);
410       }
411       AddSafepointAndDeopt(instr);
412       break;
413     }
414     case kArchCallJSFunction: {
415       EnsureSpaceForLazyDeopt();
416       Register func = i.InputRegister(0);
417       if (FLAG_debug_code) {
418         // Check the function's context matches the context argument.
419         __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
420         __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
421       }
422
423       __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
424       __ Call(at);
425       AddSafepointAndDeopt(instr);
426       break;
427     }
428     case kArchJmp:
429       AssembleArchJump(i.InputRpo(0));
430       break;
431     case kArchLookupSwitch:
432       AssembleArchLookupSwitch(instr);
433       break;
434     case kArchTableSwitch:
435       AssembleArchTableSwitch(instr);
436       break;
437     case kArchNop:
438       // don't emit code for nops.
439       break;
440     case kArchRet:
441       AssembleReturn();
442       break;
443     case kArchStackPointer:
444       __ mov(i.OutputRegister(), sp);
445       break;
446     case kArchTruncateDoubleToI:
447       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
448       break;
449     case kMips64Add:
450       __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
451       break;
452     case kMips64Dadd:
453       __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
454       break;
455     case kMips64Sub:
456       __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
457       break;
458     case kMips64Dsub:
459       __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
460       break;
461     case kMips64Mul:
462       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
463       break;
464     case kMips64MulHigh:
465       __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
466       break;
467     case kMips64MulHighU:
468       __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
469       break;
470     case kMips64Div:
471       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
472       break;
473     case kMips64DivU:
474       __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
475       break;
476     case kMips64Mod:
477       __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
478       break;
479     case kMips64ModU:
480       __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
481       break;
482     case kMips64Dmul:
483       __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
484       break;
485     case kMips64Ddiv:
486       __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
487       break;
488     case kMips64DdivU:
489       __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
490       break;
491     case kMips64Dmod:
492       __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
493       break;
494     case kMips64DmodU:
495       __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
496       break;
497       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
498       break;
499     case kMips64And:
500       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
501       break;
502     case kMips64Or:
503       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
504       break;
505     case kMips64Xor:
506       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
507       break;
508     case kMips64Shl:
509       if (instr->InputAt(1)->IsRegister()) {
510         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
511       } else {
512         int32_t imm = i.InputOperand(1).immediate();
513         __ sll(i.OutputRegister(), i.InputRegister(0), imm);
514       }
515       break;
516     case kMips64Shr:
517       if (instr->InputAt(1)->IsRegister()) {
518         __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
519       } else {
520         int32_t imm = i.InputOperand(1).immediate();
521         __ srl(i.OutputRegister(), i.InputRegister(0), imm);
522       }
523       break;
524     case kMips64Sar:
525       if (instr->InputAt(1)->IsRegister()) {
526         __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
527       } else {
528         int32_t imm = i.InputOperand(1).immediate();
529         __ sra(i.OutputRegister(), i.InputRegister(0), imm);
530       }
531       break;
532     case kMips64Ext:
533       __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
534              i.InputInt8(2));
535       break;
536     case kMips64Dext:
537       __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
538               i.InputInt8(2));
539       break;
540     case kMips64Dshl:
541       if (instr->InputAt(1)->IsRegister()) {
542         __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
543       } else {
544         int32_t imm = i.InputOperand(1).immediate();
545         if (imm < 32) {
546           __ dsll(i.OutputRegister(), i.InputRegister(0), imm);
547         } else {
548           __ dsll32(i.OutputRegister(), i.InputRegister(0), imm - 32);
549         }
550       }
551       break;
552     case kMips64Dshr:
553       if (instr->InputAt(1)->IsRegister()) {
554         __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
555       } else {
556         int32_t imm = i.InputOperand(1).immediate();
557         if (imm < 32) {
558           __ dsrl(i.OutputRegister(), i.InputRegister(0), imm);
559         } else {
560           __ dsrl32(i.OutputRegister(), i.InputRegister(0), imm - 32);
561         }
562       }
563       break;
564     case kMips64Dsar:
565       if (instr->InputAt(1)->IsRegister()) {
566         __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
567       } else {
568         int32_t imm = i.InputOperand(1).immediate();
569         if (imm < 32) {
570           __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
571         } else {
572           __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
573         }
574       }
575       break;
576     case kMips64Ror:
577       __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
578       break;
579     case kMips64Dror:
580       __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
581       break;
582     case kMips64Tst:
583     case kMips64Tst32:
584       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
585       break;
586     case kMips64Cmp:
587     case kMips64Cmp32:
588       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
589       break;
590     case kMips64Mov:
591       // TODO(plind): Should we combine mov/li like this, or use separate instr?
592       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
593       if (HasRegisterInput(instr, 0)) {
594         __ mov(i.OutputRegister(), i.InputRegister(0));
595       } else {
596         __ li(i.OutputRegister(), i.InputOperand(0));
597       }
598       break;
599
600     case kMips64CmpD:
601       // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
602       break;
603     case kMips64AddD:
604       // TODO(plind): add special case: combine mult & add.
605       __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
606                i.InputDoubleRegister(1));
607       break;
608     case kMips64SubD:
609       __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
610                i.InputDoubleRegister(1));
611       break;
612     case kMips64MulD:
613       // TODO(plind): add special case: right op is -1.0, see arm port.
614       __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
615                i.InputDoubleRegister(1));
616       break;
617     case kMips64DivD:
618       __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
619                i.InputDoubleRegister(1));
620       break;
621     case kMips64ModD: {
622       // TODO(bmeurer): We should really get rid of this special instruction,
623       // and generate a CallAddress instruction instead.
624       FrameScope scope(masm(), StackFrame::MANUAL);
625       __ PrepareCallCFunction(0, 2, kScratchReg);
626       __ MovToFloatParameters(i.InputDoubleRegister(0),
627                               i.InputDoubleRegister(1));
628       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
629                        0, 2);
630       // Move the result in the double result register.
631       __ MovFromFloatResult(i.OutputDoubleRegister());
632       break;
633     }
634     case kMips64Float64Floor: {
635       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor_l_d, Floor);
636       break;
637     }
638     case kMips64Float64Ceil: {
639       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
640       break;
641     }
642     case kMips64Float64RoundTruncate: {
643       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc_l_d, Truncate);
644       break;
645     }
646     case kMips64SqrtD: {
647       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
648       break;
649     }
650     case kMips64CvtSD: {
651       __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
652       break;
653     }
654     case kMips64CvtDS: {
655       __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
656       break;
657     }
658     case kMips64CvtDW: {
659       FPURegister scratch = kScratchDoubleReg;
660       __ mtc1(i.InputRegister(0), scratch);
661       __ cvt_d_w(i.OutputDoubleRegister(), scratch);
662       break;
663     }
664     case kMips64CvtDUw: {
665       FPURegister scratch = kScratchDoubleReg;
666       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
667       break;
668     }
669     case kMips64TruncWD: {
670       FPURegister scratch = kScratchDoubleReg;
671       // Other arches use round to zero here, so we follow.
672       __ trunc_w_d(scratch, i.InputDoubleRegister(0));
673       __ mfc1(i.OutputRegister(), scratch);
674       break;
675     }
676     case kMips64TruncUwD: {
677       FPURegister scratch = kScratchDoubleReg;
678       // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
679       __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
680       break;
681     }
682     // ... more basic instructions ...
683
684     case kMips64Lbu:
685       __ lbu(i.OutputRegister(), i.MemoryOperand());
686       break;
687     case kMips64Lb:
688       __ lb(i.OutputRegister(), i.MemoryOperand());
689       break;
690     case kMips64Sb:
691       __ sb(i.InputRegister(2), i.MemoryOperand());
692       break;
693     case kMips64Lhu:
694       __ lhu(i.OutputRegister(), i.MemoryOperand());
695       break;
696     case kMips64Lh:
697       __ lh(i.OutputRegister(), i.MemoryOperand());
698       break;
699     case kMips64Sh:
700       __ sh(i.InputRegister(2), i.MemoryOperand());
701       break;
702     case kMips64Lw:
703       __ lw(i.OutputRegister(), i.MemoryOperand());
704       break;
705     case kMips64Ld:
706       __ ld(i.OutputRegister(), i.MemoryOperand());
707       break;
708     case kMips64Sw:
709       __ sw(i.InputRegister(2), i.MemoryOperand());
710       break;
711     case kMips64Sd:
712       __ sd(i.InputRegister(2), i.MemoryOperand());
713       break;
714     case kMips64Lwc1: {
715       __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
716       break;
717     }
718     case kMips64Swc1: {
719       int index = 0;
720       MemOperand operand = i.MemoryOperand(&index);
721       __ swc1(i.InputSingleRegister(index), operand);
722       break;
723     }
724     case kMips64Ldc1:
725       __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
726       break;
727     case kMips64Sdc1:
728       __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
729       break;
730     case kMips64Push:
731       __ Push(i.InputRegister(0));
732       break;
733     case kMips64StackClaim: {
734       int words = MiscField::decode(instr->opcode());
735       __ Dsubu(sp, sp, Operand(words << kPointerSizeLog2));
736       break;
737     }
738     case kMips64StoreToStackSlot: {
739       int slot = MiscField::decode(instr->opcode());
740       __ sd(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
741       break;
742     }
743     case kMips64StoreWriteBarrier: {
744       Register object = i.InputRegister(0);
745       Register index = i.InputRegister(1);
746       Register value = i.InputRegister(2);
747       __ daddu(index, object, index);
748       __ sd(value, MemOperand(index));
749       SaveFPRegsMode mode =
750           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
751       RAStatus ra_status = kRAHasNotBeenSaved;
752       __ RecordWrite(object, index, value, ra_status, mode);
753       break;
754     }
755     case kCheckedLoadInt8:
756       ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
757       break;
758     case kCheckedLoadUint8:
759       ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
760       break;
761     case kCheckedLoadInt16:
762       ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
763       break;
764     case kCheckedLoadUint16:
765       ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
766       break;
767     case kCheckedLoadWord32:
768       ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
769       break;
770     case kCheckedLoadFloat32:
771       ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
772       break;
773     case kCheckedLoadFloat64:
774       ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
775       break;
776     case kCheckedStoreWord8:
777       ASSEMBLE_CHECKED_STORE_INTEGER(sb);
778       break;
779     case kCheckedStoreWord16:
780       ASSEMBLE_CHECKED_STORE_INTEGER(sh);
781       break;
782     case kCheckedStoreWord32:
783       ASSEMBLE_CHECKED_STORE_INTEGER(sw);
784       break;
785     case kCheckedStoreFloat32:
786       ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
787       break;
788     case kCheckedStoreFloat64:
789       ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
790       break;
791   }
792 }
793
794
795 #define UNSUPPORTED_COND(opcode, condition)                                  \
796   OFStream out(stdout);                                                      \
797   out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
798   UNIMPLEMENTED();
799
800 // Assembles branches after an instruction.
801 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
802   MipsOperandConverter i(this, instr);
803   Label* tlabel = branch->true_label;
804   Label* flabel = branch->false_label;
805   Condition cc = kNoCondition;
806
807   // MIPS does not have condition code flags, so compare and branch are
808   // implemented differently than on the other arch's. The compare operations
809   // emit mips psuedo-instructions, which are handled here by branch
810   // instructions that do the actual comparison. Essential that the input
811   // registers to compare psuedo-op are not modified before this branch op, as
812   // they are tested here.
813   // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
814   //    not separated by other instructions.
815
816   if (instr->arch_opcode() == kMips64Tst) {
817     cc = FlagsConditionToConditionTst(branch->condition);
818     __ And(at, i.InputRegister(0), i.InputOperand(1));
819     __ Branch(tlabel, cc, at, Operand(zero_reg));
820   } else if (instr->arch_opcode() == kMips64Tst32) {
821     cc = FlagsConditionToConditionTst(branch->condition);
822     // Zero-extend registers on MIPS64 only 64-bit operand
823     // branch and compare op. is available.
824     // This is a disadvantage to perform 32-bit operation on MIPS64.
825     // Try to force globally in front-end Word64 representation to be preferred
826     // for MIPS64 even for Word32.
827     __ And(at, i.InputRegister(0), i.InputOperand(1));
828     __ Dext(at, at, 0, 32);
829     __ Branch(tlabel, cc, at, Operand(zero_reg));
830   } else if (instr->arch_opcode() == kMips64Dadd ||
831              instr->arch_opcode() == kMips64Dsub) {
832     cc = FlagsConditionToConditionOvf(branch->condition);
833
834     __ dsra32(kScratchReg, i.OutputRegister(), 0);
835     __ sra(at, i.OutputRegister(), 31);
836     __ Branch(tlabel, cc, at, Operand(kScratchReg));
837   } else if (instr->arch_opcode() == kMips64Cmp) {
838     cc = FlagsConditionToConditionCmp(branch->condition);
839     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
840
841     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
842
843   } else if (instr->arch_opcode() == kMips64Cmp32) {
844     cc = FlagsConditionToConditionCmp(branch->condition);
845
846     switch (branch->condition) {
847       case kEqual:
848       case kNotEqual:
849       case kSignedLessThan:
850       case kSignedGreaterThanOrEqual:
851       case kSignedLessThanOrEqual:
852       case kSignedGreaterThan:
853         // Sign-extend registers on MIPS64 only 64-bit operand
854         // branch and compare op. is available.
855         __ sll(i.InputRegister(0), i.InputRegister(0), 0);
856         if (instr->InputAt(1)->IsRegister()) {
857           __ sll(i.InputRegister(1), i.InputRegister(1), 0);
858         }
859         break;
860       case kUnsignedLessThan:
861       case kUnsignedGreaterThanOrEqual:
862       case kUnsignedLessThanOrEqual:
863       case kUnsignedGreaterThan:
864         // Zero-extend registers on MIPS64 only 64-bit operand
865         // branch and compare op. is available.
866         __ Dext(i.InputRegister(0), i.InputRegister(0), 0, 32);
867         if (instr->InputAt(1)->IsRegister()) {
868           __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32);
869         }
870         break;
871       default:
872         UNSUPPORTED_COND(kMips64Cmp, branch->condition);
873         break;
874     }
875     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
876
877     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
878   } else if (instr->arch_opcode() == kMips64CmpD) {
879     // TODO(dusmil) optimize unordered checks to use less instructions
880     // even if we have to unfold BranchF macro.
881     Label* nan = flabel;
882     switch (branch->condition) {
883       case kEqual:
884         cc = eq;
885         break;
886       case kNotEqual:
887         cc = ne;
888         nan = tlabel;
889         break;
890       case kUnsignedLessThan:
891         cc = lt;
892         break;
893       case kUnsignedGreaterThanOrEqual:
894         cc = ge;
895         nan = tlabel;
896         break;
897       case kUnsignedLessThanOrEqual:
898         cc = le;
899         break;
900       case kUnsignedGreaterThan:
901         cc = gt;
902         nan = tlabel;
903         break;
904       default:
905         UNSUPPORTED_COND(kMips64CmpD, branch->condition);
906         break;
907     }
908     __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
909                i.InputDoubleRegister(1));
910
911     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
912   } else {
913     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
914            instr->arch_opcode());
915     UNIMPLEMENTED();
916   }
917 }
918
919
920 void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
921   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
922 }
923
924
925 // Assembles boolean materializations after an instruction.
926 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
927                                         FlagsCondition condition) {
928   MipsOperandConverter i(this, instr);
929   Label done;
930
931   // Materialize a full 32-bit 1 or 0 value. The result register is always the
932   // last output of the instruction.
933   Label false_value;
934   DCHECK_NE(0u, instr->OutputCount());
935   Register result = i.OutputRegister(instr->OutputCount() - 1);
936   Condition cc = kNoCondition;
937
938   // MIPS does not have condition code flags, so compare and branch are
939   // implemented differently than on the other arch's. The compare operations
940   // emit mips pseudo-instructions, which are checked and handled here.
941
942   // For materializations, we use delay slot to set the result true, and
943   // in the false case, where we fall through the branch, we reset the result
944   // false.
945
946   if (instr->arch_opcode() == kMips64Tst) {
947     cc = FlagsConditionToConditionTst(condition);
948     __ And(at, i.InputRegister(0), i.InputOperand(1));
949     __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
950     __ li(result, Operand(1));  // In delay slot.
951   } else if (instr->arch_opcode() == kMips64Tst32) {
952     cc = FlagsConditionToConditionTst(condition);
953     // Zero-extend register on MIPS64 only 64-bit operand
954     // branch and compare op. is available.
955     __ And(at, i.InputRegister(0), i.InputOperand(1));
956     __ Dext(at, at, 0, 32);
957     __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
958     __ li(result, Operand(1));  // In delay slot.
959   } else if (instr->arch_opcode() == kMips64Dadd ||
960              instr->arch_opcode() == kMips64Dsub) {
961     cc = FlagsConditionToConditionOvf(condition);
962     __ dsra32(kScratchReg, i.OutputRegister(), 0);
963     __ sra(at, i.OutputRegister(), 31);
964     __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(kScratchReg));
965     __ li(result, Operand(1));  // In delay slot.
966   } else if (instr->arch_opcode() == kMips64Cmp) {
967     Register left = i.InputRegister(0);
968     Operand right = i.InputOperand(1);
969     cc = FlagsConditionToConditionCmp(condition);
970     __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
971     __ li(result, Operand(1));  // In delay slot.
972   } else if (instr->arch_opcode() == kMips64Cmp32) {
973     Register left = i.InputRegister(0);
974     Operand right = i.InputOperand(1);
975     cc = FlagsConditionToConditionCmp(condition);
976
977     switch (condition) {
978       case kEqual:
979       case kNotEqual:
980       case kSignedLessThan:
981       case kSignedGreaterThanOrEqual:
982       case kSignedLessThanOrEqual:
983       case kSignedGreaterThan:
984         // Sign-extend registers on MIPS64 only 64-bit operand
985         // branch and compare op. is available.
986         __ sll(left, left, 0);
987         if (instr->InputAt(1)->IsRegister()) {
988           __ sll(i.InputRegister(1), i.InputRegister(1), 0);
989         }
990         break;
991       case kUnsignedLessThan:
992       case kUnsignedGreaterThanOrEqual:
993       case kUnsignedLessThanOrEqual:
994       case kUnsignedGreaterThan:
995         // Zero-extend registers on MIPS64 only 64-bit operand
996         // branch and compare op. is available.
997         __ Dext(left, left, 0, 32);
998         if (instr->InputAt(1)->IsRegister()) {
999           __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32);
1000         }
1001         break;
1002       default:
1003         UNSUPPORTED_COND(kMips64Cmp32, condition);
1004         break;
1005     }
1006     __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
1007     __ li(result, Operand(1));  // In delay slot.
1008   } else if (instr->arch_opcode() == kMips64CmpD) {
1009     FPURegister left = i.InputDoubleRegister(0);
1010     FPURegister right = i.InputDoubleRegister(1);
1011
1012     bool predicate;
1013     FPUCondition cc = FlagsConditionToConditionCmpD(predicate, condition);
1014     if (kArchVariant != kMips64r6) {
1015       __ li(result, Operand(1));
1016       __ c(cc, D, left, right);
1017       if (predicate) {
1018         __ Movf(result, zero_reg);
1019       } else {
1020         __ Movt(result, zero_reg);
1021       }
1022     } else {
1023       __ cmp(cc, L, kDoubleCompareReg, left, right);
1024       __ dmfc1(at, kDoubleCompareReg);
1025       __ dsrl32(result, at, 31);  // Cmp returns all 1s for true.
1026       if (!predicate)             // Toggle result for not equal.
1027         __ xori(result, result, 1);
1028     }
1029     return;
1030   } else {
1031     PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
1032            instr->arch_opcode());
1033     TRACE_UNIMPL();
1034     UNIMPLEMENTED();
1035   }
1036   // Fallthru case is the false materialization.
1037   __ bind(&false_value);
1038   __ li(result, Operand(static_cast<int64_t>(0)));
1039   __ bind(&done);
1040 }
1041
1042
1043 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1044   MipsOperandConverter i(this, instr);
1045   Register input = i.InputRegister(0);
1046   for (size_t index = 2; index < instr->InputCount(); index += 2) {
1047     __ li(at, Operand(i.InputInt32(index + 0)));
1048     __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
1049   }
1050   __ nop();  // Branch delay slot of the last beq.
1051   AssembleArchJump(i.InputRpo(1));
1052 }
1053
1054
1055 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1056   MipsOperandConverter i(this, instr);
1057   Register input = i.InputRegister(0);
1058   size_t const case_count = instr->InputCount() - 2;
1059   Label here;
1060
1061   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
1062   __ BlockTrampolinePoolFor(case_count * 2 + 7);
1063   // Ensure that dd-ed labels use 8 byte aligned addresses.
1064   if ((masm()->pc_offset() & 7) != 0) {
1065     __ nop();
1066   }
1067   __ bal(&here);
1068   __ dsll(at, input, 3);  // Branch delay slot.
1069   __ bind(&here);
1070   __ daddu(at, at, ra);
1071   __ ld(at, MemOperand(at, 4 * v8::internal::Assembler::kInstrSize));
1072   __ jr(at);
1073   __ nop();  // Branch delay slot nop.
1074   for (size_t index = 0; index < case_count; ++index) {
1075     __ dd(GetLabel(i.InputRpo(index + 2)));
1076   }
1077 }
1078
1079
1080 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
1081   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
1082       isolate(), deoptimization_id, Deoptimizer::LAZY);
1083   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1084 }
1085
1086
1087 void CodeGenerator::AssemblePrologue() {
1088   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1089   int stack_slots = frame()->GetSpillSlotCount();
1090   if (descriptor->kind() == CallDescriptor::kCallAddress) {
1091     __ Push(ra, fp);
1092     __ mov(fp, sp);
1093     const RegList saves = descriptor->CalleeSavedRegisters();
1094     if (saves != 0) {  // Save callee-saved registers.
1095       // TODO(plind): make callee save size const, possibly DCHECK it.
1096       int register_save_area_size = 0;
1097       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1098         if (!((1 << i) & saves)) continue;
1099         register_save_area_size += kPointerSize;
1100       }
1101       frame()->SetRegisterSaveAreaSize(register_save_area_size);
1102       __ MultiPush(saves);
1103     }
1104   } else if (descriptor->IsJSFunctionCall()) {
1105     CompilationInfo* info = this->info();
1106     __ Prologue(info->IsCodePreAgingActive());
1107     frame()->SetRegisterSaveAreaSize(
1108         StandardFrameConstants::kFixedFrameSizeFromFp);
1109   } else if (stack_slots > 0) {
1110     __ StubPrologue();
1111     frame()->SetRegisterSaveAreaSize(
1112         StandardFrameConstants::kFixedFrameSizeFromFp);
1113   }
1114
1115   if (info()->is_osr()) {
1116     // TurboFan OSR-compiled functions cannot be entered directly.
1117     __ Abort(kShouldNotDirectlyEnterOsrFunction);
1118
1119     // Unoptimized code jumps directly to this entrypoint while the unoptimized
1120     // frame is still on the stack. Optimized code uses OSR values directly from
1121     // the unoptimized frame. Thus, all that needs to be done is to allocate the
1122     // remaining stack slots.
1123     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1124     osr_pc_offset_ = __ pc_offset();
1125     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
1126     stack_slots -= frame()->GetOsrStackSlotCount();
1127   }
1128
1129   if (stack_slots > 0) {
1130     __ Dsubu(sp, sp, Operand(stack_slots * kPointerSize));
1131   }
1132 }
1133
1134
1135 void CodeGenerator::AssembleReturn() {
1136   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1137   int stack_slots = frame()->GetSpillSlotCount();
1138   if (descriptor->kind() == CallDescriptor::kCallAddress) {
1139     if (frame()->GetRegisterSaveAreaSize() > 0) {
1140       // Remove this frame's spill slots first.
1141       if (stack_slots > 0) {
1142         __ Daddu(sp, sp, Operand(stack_slots * kPointerSize));
1143       }
1144       // Restore registers.
1145       const RegList saves = descriptor->CalleeSavedRegisters();
1146       if (saves != 0) {
1147         __ MultiPop(saves);
1148       }
1149     }
1150     __ mov(sp, fp);
1151     __ Pop(ra, fp);
1152     __ Ret();
1153   } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
1154     __ mov(sp, fp);
1155     __ Pop(ra, fp);
1156     int pop_count = descriptor->IsJSFunctionCall()
1157                         ? static_cast<int>(descriptor->JSParameterCount())
1158                         : 0;
1159     __ DropAndRet(pop_count);
1160   } else {
1161     __ Ret();
1162   }
1163 }
1164
1165
1166 void CodeGenerator::AssembleMove(InstructionOperand* source,
1167                                  InstructionOperand* destination) {
1168   MipsOperandConverter g(this, NULL);
1169   // Dispatch on the source and destination operand kinds.  Not all
1170   // combinations are possible.
1171   if (source->IsRegister()) {
1172     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1173     Register src = g.ToRegister(source);
1174     if (destination->IsRegister()) {
1175       __ mov(g.ToRegister(destination), src);
1176     } else {
1177       __ sd(src, g.ToMemOperand(destination));
1178     }
1179   } else if (source->IsStackSlot()) {
1180     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1181     MemOperand src = g.ToMemOperand(source);
1182     if (destination->IsRegister()) {
1183       __ ld(g.ToRegister(destination), src);
1184     } else {
1185       Register temp = kScratchReg;
1186       __ ld(temp, src);
1187       __ sd(temp, g.ToMemOperand(destination));
1188     }
1189   } else if (source->IsConstant()) {
1190     Constant src = g.ToConstant(source);
1191     if (destination->IsRegister() || destination->IsStackSlot()) {
1192       Register dst =
1193           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
1194       switch (src.type()) {
1195         case Constant::kInt32:
1196           __ li(dst, Operand(src.ToInt32()));
1197           break;
1198         case Constant::kFloat32:
1199           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1200           break;
1201         case Constant::kInt64:
1202           __ li(dst, Operand(src.ToInt64()));
1203           break;
1204         case Constant::kFloat64:
1205           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1206           break;
1207         case Constant::kExternalReference:
1208           __ li(dst, Operand(src.ToExternalReference()));
1209           break;
1210         case Constant::kHeapObject:
1211           __ li(dst, src.ToHeapObject());
1212           break;
1213         case Constant::kRpoNumber:
1214           UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
1215           break;
1216       }
1217       if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
1218     } else if (src.type() == Constant::kFloat32) {
1219       if (destination->IsDoubleStackSlot()) {
1220         MemOperand dst = g.ToMemOperand(destination);
1221         __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
1222         __ sw(at, dst);
1223       } else {
1224         FloatRegister dst = g.ToSingleRegister(destination);
1225         __ Move(dst, src.ToFloat32());
1226       }
1227     } else {
1228       DCHECK_EQ(Constant::kFloat64, src.type());
1229       DoubleRegister dst = destination->IsDoubleRegister()
1230                                ? g.ToDoubleRegister(destination)
1231                                : kScratchDoubleReg;
1232       __ Move(dst, src.ToFloat64());
1233       if (destination->IsDoubleStackSlot()) {
1234         __ sdc1(dst, g.ToMemOperand(destination));
1235       }
1236     }
1237   } else if (source->IsDoubleRegister()) {
1238     FPURegister src = g.ToDoubleRegister(source);
1239     if (destination->IsDoubleRegister()) {
1240       FPURegister dst = g.ToDoubleRegister(destination);
1241       __ Move(dst, src);
1242     } else {
1243       DCHECK(destination->IsDoubleStackSlot());
1244       __ sdc1(src, g.ToMemOperand(destination));
1245     }
1246   } else if (source->IsDoubleStackSlot()) {
1247     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1248     MemOperand src = g.ToMemOperand(source);
1249     if (destination->IsDoubleRegister()) {
1250       __ ldc1(g.ToDoubleRegister(destination), src);
1251     } else {
1252       FPURegister temp = kScratchDoubleReg;
1253       __ ldc1(temp, src);
1254       __ sdc1(temp, g.ToMemOperand(destination));
1255     }
1256   } else {
1257     UNREACHABLE();
1258   }
1259 }
1260
1261
1262 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1263                                  InstructionOperand* destination) {
1264   MipsOperandConverter g(this, NULL);
1265   // Dispatch on the source and destination operand kinds.  Not all
1266   // combinations are possible.
1267   if (source->IsRegister()) {
1268     // Register-register.
1269     Register temp = kScratchReg;
1270     Register src = g.ToRegister(source);
1271     if (destination->IsRegister()) {
1272       Register dst = g.ToRegister(destination);
1273       __ Move(temp, src);
1274       __ Move(src, dst);
1275       __ Move(dst, temp);
1276     } else {
1277       DCHECK(destination->IsStackSlot());
1278       MemOperand dst = g.ToMemOperand(destination);
1279       __ mov(temp, src);
1280       __ ld(src, dst);
1281       __ sd(temp, dst);
1282     }
1283   } else if (source->IsStackSlot()) {
1284     DCHECK(destination->IsStackSlot());
1285     Register temp_0 = kScratchReg;
1286     Register temp_1 = kScratchReg2;
1287     MemOperand src = g.ToMemOperand(source);
1288     MemOperand dst = g.ToMemOperand(destination);
1289     __ ld(temp_0, src);
1290     __ ld(temp_1, dst);
1291     __ sd(temp_0, dst);
1292     __ sd(temp_1, src);
1293   } else if (source->IsDoubleRegister()) {
1294     FPURegister temp = kScratchDoubleReg;
1295     FPURegister src = g.ToDoubleRegister(source);
1296     if (destination->IsDoubleRegister()) {
1297       FPURegister dst = g.ToDoubleRegister(destination);
1298       __ Move(temp, src);
1299       __ Move(src, dst);
1300       __ Move(dst, temp);
1301     } else {
1302       DCHECK(destination->IsDoubleStackSlot());
1303       MemOperand dst = g.ToMemOperand(destination);
1304       __ Move(temp, src);
1305       __ ldc1(src, dst);
1306       __ sdc1(temp, dst);
1307     }
1308   } else if (source->IsDoubleStackSlot()) {
1309     DCHECK(destination->IsDoubleStackSlot());
1310     Register temp_0 = kScratchReg;
1311     FPURegister temp_1 = kScratchDoubleReg;
1312     MemOperand src0 = g.ToMemOperand(source);
1313     MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
1314     MemOperand dst0 = g.ToMemOperand(destination);
1315     MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
1316     __ ldc1(temp_1, dst0);  // Save destination in temp_1.
1317     __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
1318     __ sw(temp_0, dst0);
1319     __ lw(temp_0, src1);
1320     __ sw(temp_0, dst1);
1321     __ sdc1(temp_1, src0);
1322   } else {
1323     // No other combinations are possible.
1324     UNREACHABLE();
1325   }
1326 }
1327
1328
1329 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1330   // On 64-bit MIPS we emit the jump tables inline.
1331   UNREACHABLE();
1332 }
1333
1334
1335 void CodeGenerator::AddNopForSmiCodeInlining() {
1336   // Unused on 32-bit ARM. Still exists on 64-bit arm.
1337   // TODO(plind): Unclear when this is called now. Understand, fix if needed.
1338   __ nop();  // Maybe PROPERTY_ACCESS_INLINED?
1339 }
1340
1341
1342 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1343   int space_needed = Deoptimizer::patch_size();
1344   if (!info()->IsStub()) {
1345     // Ensure that we have enough space after the previous lazy-bailout
1346     // instruction for patching the code here.
1347     int current_pc = masm()->pc_offset();
1348     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1349       // Block tramoline pool emission for duration of padding.
1350       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
1351           masm());
1352       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1353       DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1354       while (padding_size > 0) {
1355         __ nop();
1356         padding_size -= v8::internal::Assembler::kInstrSize;
1357       }
1358     }
1359   }
1360   MarkLazyDeoptSite();
1361 }
1362
1363 #undef __
1364
1365 }  // namespace compiler
1366 }  // namespace internal
1367 }  // namespace v8