blob: c437d5e895f99f8c2ab857b946e2d468a022471b [file] [log] [blame]
Emily Bernier958fae72015-03-24 16:35:39 -04001// 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
Ben Murdoch014dc512016-03-22 12:00:34 +00005#include "src/ast/scopes.h"
Emily Bernier958fae72015-03-24 16:35:39 -04006#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"
Ben Murdoch014dc512016-03-22 12:00:34 +000010#include "src/compiler/osr.h"
Emily Bernier958fae72015-03-24 16:35:39 -040011#include "src/mips/macro-assembler-mips.h"
Emily Bernier958fae72015-03-24 16:35:39 -040012
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 kCompareReg kLithiumScratchReg2
23#define kScratchReg2 kLithiumScratchReg2
24#define kScratchDoubleReg kLithiumScratchDouble
25
26
27// TODO(plind): consider renaming these macros.
28#define TRACE_MSG(msg) \
29 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
30 __LINE__)
31
32#define TRACE_UNIMPL() \
33 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
34 __LINE__)
35
36
37// Adds Mips-specific methods to convert InstructionOperands.
Ben Murdoch014dc512016-03-22 12:00:34 +000038class MipsOperandConverter final : public InstructionOperandConverter {
Emily Bernier958fae72015-03-24 16:35:39 -040039 public:
40 MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
41 : InstructionOperandConverter(gen, instr) {}
42
Ben Murdoch014dc512016-03-22 12:00:34 +000043 FloatRegister OutputSingleRegister(size_t index = 0) {
Emily Bernier958fae72015-03-24 16:35:39 -040044 return ToSingleRegister(instr_->OutputAt(index));
45 }
46
Ben Murdoch014dc512016-03-22 12:00:34 +000047 FloatRegister InputSingleRegister(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040048 return ToSingleRegister(instr_->InputAt(index));
49 }
50
51 FloatRegister ToSingleRegister(InstructionOperand* op) {
52 // Single (Float) and Double register namespace is same on MIPS,
53 // both are typedefs of FPURegister.
54 return ToDoubleRegister(op);
55 }
56
Ben Murdoch014dc512016-03-22 12:00:34 +000057 DoubleRegister InputOrZeroDoubleRegister(size_t index) {
58 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
59
60 return InputDoubleRegister(index);
61 }
62
63 DoubleRegister InputOrZeroSingleRegister(size_t index) {
64 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
65
66 return InputSingleRegister(index);
67 }
68
69 Operand InputImmediate(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040070 Constant constant = ToConstant(instr_->InputAt(index));
71 switch (constant.type()) {
72 case Constant::kInt32:
73 return Operand(constant.ToInt32());
74 case Constant::kFloat32:
75 return Operand(
76 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
77 case Constant::kFloat64:
78 return Operand(
79 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
80 case Constant::kInt64:
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
Ben Murdoch014dc512016-03-22 12:00:34 +000094 Operand InputOperand(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040095 InstructionOperand* op = instr_->InputAt(index);
96 if (op->IsRegister()) {
97 return Operand(ToRegister(op));
98 }
99 return InputImmediate(index);
100 }
101
Ben Murdoch014dc512016-03-22 12:00:34 +0000102 MemOperand MemoryOperand(size_t* first_index) {
103 const size_t index = *first_index;
Emily Bernier958fae72015-03-24 16:35:39 -0400104 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
Ben Murdoch014dc512016-03-22 12:00:34 +0000118 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
Emily Bernier958fae72015-03-24 16:35:39 -0400119
120 MemOperand ToMemOperand(InstructionOperand* op) const {
Ben Murdoch014dc512016-03-22 12:00:34 +0000121 DCHECK_NOT_NULL(op);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100122 DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100123 return SlotToMemOperand(AllocatedOperand::cast(op)->index());
124 }
125
126 MemOperand SlotToMemOperand(int slot) const {
127 FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
Emily Bernier958fae72015-03-24 16:35:39 -0400128 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
129 }
130};
131
132
Ben Murdoch014dc512016-03-22 12:00:34 +0000133static inline bool HasRegisterInput(Instruction* instr, size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -0400134 return instr->InputAt(index)->IsRegister();
135}
136
137
138namespace {
139
Ben Murdoch014dc512016-03-22 12:00:34 +0000140class OutOfLineLoadSingle final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400141 public:
142 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
143 : OutOfLineCode(gen), result_(result) {}
144
Ben Murdoch014dc512016-03-22 12:00:34 +0000145 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400146 __ Move(result_, std::numeric_limits<float>::quiet_NaN());
147 }
148
149 private:
150 FloatRegister const result_;
151};
152
153
Ben Murdoch014dc512016-03-22 12:00:34 +0000154class OutOfLineLoadDouble final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400155 public:
156 OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
157 : OutOfLineCode(gen), result_(result) {}
158
Ben Murdoch014dc512016-03-22 12:00:34 +0000159 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400160 __ Move(result_, std::numeric_limits<double>::quiet_NaN());
161 }
162
163 private:
164 DoubleRegister const result_;
165};
166
167
Ben Murdoch014dc512016-03-22 12:00:34 +0000168class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400169 public:
170 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
171 : OutOfLineCode(gen), result_(result) {}
172
Ben Murdoch014dc512016-03-22 12:00:34 +0000173 void Generate() final { __ mov(result_, zero_reg); }
Emily Bernier958fae72015-03-24 16:35:39 -0400174
175 private:
176 Register const result_;
177};
178
179
180class OutOfLineRound : public OutOfLineCode {
181 public:
182 OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
183 : OutOfLineCode(gen), result_(result) {}
184
Ben Murdoch014dc512016-03-22 12:00:34 +0000185 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400186 // Handle rounding to zero case where sign has to be preserved.
187 // High bits of double input already in kScratchReg.
188 __ srl(at, kScratchReg, 31);
189 __ sll(at, at, 31);
190 __ Mthc1(at, result_);
191 }
192
193 private:
194 DoubleRegister const result_;
195};
196
197
Ben Murdoch014dc512016-03-22 12:00:34 +0000198class OutOfLineRound32 : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400199 public:
Ben Murdoch014dc512016-03-22 12:00:34 +0000200 OutOfLineRound32(CodeGenerator* gen, DoubleRegister result)
201 : OutOfLineCode(gen), result_(result) {}
202
203 void Generate() final {
204 // Handle rounding to zero case where sign has to be preserved.
205 // High bits of float input already in kScratchReg.
206 __ srl(at, kScratchReg, 31);
207 __ sll(at, at, 31);
208 __ mtc1(at, result_);
209 }
210
211 private:
212 DoubleRegister const result_;
Emily Bernier958fae72015-03-24 16:35:39 -0400213};
214
215
Ben Murdoch014dc512016-03-22 12:00:34 +0000216class OutOfLineRecordWrite final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400217 public:
Ben Murdoch014dc512016-03-22 12:00:34 +0000218 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
219 Register value, Register scratch0, Register scratch1,
220 RecordWriteMode mode)
221 : OutOfLineCode(gen),
222 object_(object),
223 index_(index),
224 value_(value),
225 scratch0_(scratch0),
226 scratch1_(scratch1),
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100227 mode_(mode),
228 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch014dc512016-03-22 12:00:34 +0000229
230 void Generate() final {
231 if (mode_ > RecordWriteMode::kValueIsPointer) {
232 __ JumpIfSmi(value_, exit());
233 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100234 __ CheckPageFlag(value_, scratch0_,
235 MemoryChunk::kPointersToHereAreInterestingMask, eq,
236 exit());
237 RememberedSetAction const remembered_set_action =
238 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
239 : OMIT_REMEMBERED_SET;
Ben Murdoch014dc512016-03-22 12:00:34 +0000240 SaveFPRegsMode const save_fp_mode =
241 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100242 if (must_save_lr_) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100243 // We need to save and restore ra if the frame was elided.
244 __ Push(ra);
245 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000246 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch109988c2016-05-18 11:27:45 +0100247 remembered_set_action, save_fp_mode);
Ben Murdoch014dc512016-03-22 12:00:34 +0000248 __ Addu(scratch1_, object_, index_);
249 __ CallStub(&stub);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100250 if (must_save_lr_) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100251 __ Pop(ra);
252 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000253 }
254
255 private:
256 Register const object_;
257 Register const index_;
258 Register const value_;
259 Register const scratch0_;
260 Register const scratch1_;
261 RecordWriteMode const mode_;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100262 bool must_save_lr_;
Emily Bernier958fae72015-03-24 16:35:39 -0400263};
264
265
Ben Murdoch014dc512016-03-22 12:00:34 +0000266Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
267 switch (condition) {
268 case kEqual:
269 return eq;
270 case kNotEqual:
271 return ne;
272 case kSignedLessThan:
273 return lt;
274 case kSignedGreaterThanOrEqual:
275 return ge;
276 case kSignedLessThanOrEqual:
277 return le;
278 case kSignedGreaterThan:
279 return gt;
280 case kUnsignedLessThan:
281 return lo;
282 case kUnsignedGreaterThanOrEqual:
283 return hs;
284 case kUnsignedLessThanOrEqual:
285 return ls;
286 case kUnsignedGreaterThan:
287 return hi;
288 case kUnorderedEqual:
289 case kUnorderedNotEqual:
290 break;
291 default:
292 break;
293 }
294 UNREACHABLE();
295 return kNoCondition;
296}
297
298
299Condition FlagsConditionToConditionTst(FlagsCondition condition) {
300 switch (condition) {
301 case kNotEqual:
302 return ne;
303 case kEqual:
304 return eq;
305 default:
306 break;
307 }
308 UNREACHABLE();
309 return kNoCondition;
310}
311
312
313FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
314 FlagsCondition condition) {
315 switch (condition) {
316 case kEqual:
317 predicate = true;
318 return EQ;
319 case kNotEqual:
320 predicate = false;
321 return EQ;
322 case kUnsignedLessThan:
323 predicate = true;
324 return OLT;
325 case kUnsignedGreaterThanOrEqual:
326 predicate = false;
327 return ULT;
328 case kUnsignedLessThanOrEqual:
329 predicate = true;
330 return OLE;
331 case kUnsignedGreaterThan:
332 predicate = false;
333 return ULE;
334 case kUnorderedEqual:
335 case kUnorderedNotEqual:
336 predicate = true;
337 break;
338 default:
339 predicate = true;
340 break;
341 }
342 UNREACHABLE();
343 return kNoFPUCondition;
344}
Emily Bernier958fae72015-03-24 16:35:39 -0400345
346} // namespace
347
348
349#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \
350 do { \
351 auto result = i.Output##width##Register(); \
352 auto ool = new (zone()) OutOfLineLoad##width(this, result); \
353 if (instr->InputAt(0)->IsRegister()) { \
354 auto offset = i.InputRegister(0); \
355 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000356 __ addu(kScratchReg, i.InputRegister(2), offset); \
357 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400358 } else { \
359 auto offset = i.InputOperand(0).immediate(); \
360 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
361 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
362 } \
363 __ bind(ool->exit()); \
364 } while (0)
365
366
367#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
368 do { \
369 auto result = i.OutputRegister(); \
370 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
371 if (instr->InputAt(0)->IsRegister()) { \
372 auto offset = i.InputRegister(0); \
373 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000374 __ addu(kScratchReg, i.InputRegister(2), offset); \
375 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400376 } else { \
377 auto offset = i.InputOperand(0).immediate(); \
378 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
379 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
380 } \
381 __ bind(ool->exit()); \
382 } while (0)
383
384
385#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
386 do { \
387 Label done; \
388 if (instr->InputAt(0)->IsRegister()) { \
389 auto offset = i.InputRegister(0); \
390 auto value = i.Input##width##Register(2); \
391 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000392 __ addu(kScratchReg, i.InputRegister(3), offset); \
393 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400394 } else { \
395 auto offset = i.InputOperand(0).immediate(); \
396 auto value = i.Input##width##Register(2); \
397 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
398 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
399 } \
400 __ bind(&done); \
401 } while (0)
402
403
404#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
405 do { \
406 Label done; \
407 if (instr->InputAt(0)->IsRegister()) { \
408 auto offset = i.InputRegister(0); \
409 auto value = i.InputRegister(2); \
410 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000411 __ addu(kScratchReg, i.InputRegister(3), offset); \
412 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400413 } else { \
414 auto offset = i.InputOperand(0).immediate(); \
415 auto value = i.InputRegister(2); \
416 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
417 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
418 } \
419 __ bind(&done); \
420 } while (0)
421
422
Ben Murdoch014dc512016-03-22 12:00:34 +0000423#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
424 if (IsMipsArchVariant(kMips32r6)) { \
425 __ cfc1(kScratchReg, FCSR); \
426 __ li(at, Operand(mode_##mode)); \
427 __ ctc1(at, FCSR); \
428 __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
429 __ ctc1(kScratchReg, FCSR); \
430 } else { \
431 auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister()); \
Emily Bernier958fae72015-03-24 16:35:39 -0400432 Label done; \
433 __ Mfhc1(kScratchReg, i.InputDoubleRegister(0)); \
434 __ Ext(at, kScratchReg, HeapNumber::kExponentShift, \
435 HeapNumber::kExponentBits); \
436 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
437 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
438 __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000439 __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400440 __ Move(at, kScratchReg2, i.OutputDoubleRegister()); \
441 __ or_(at, at, kScratchReg2); \
442 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
443 __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
444 __ bind(ool->exit()); \
445 __ bind(&done); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000446 }
447
448
449#define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode) \
450 if (IsMipsArchVariant(kMips32r6)) { \
451 __ cfc1(kScratchReg, FCSR); \
452 __ li(at, Operand(mode_##mode)); \
453 __ ctc1(at, FCSR); \
454 __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
455 __ ctc1(kScratchReg, FCSR); \
456 } else { \
457 int32_t kFloat32ExponentBias = 127; \
458 int32_t kFloat32MantissaBits = 23; \
459 int32_t kFloat32ExponentBits = 8; \
460 auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
461 Label done; \
462 __ mfc1(kScratchReg, i.InputDoubleRegister(0)); \
463 __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits); \
464 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
465 Operand(kFloat32ExponentBias + kFloat32MantissaBits)); \
466 __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
467 __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
468 __ mfc1(at, i.OutputDoubleRegister()); \
469 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
470 __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
471 __ bind(ool->exit()); \
472 __ bind(&done); \
473 }
474
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100475#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \
476 do { \
477 __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
478 __ sync(); \
479 } while (0)
480
481#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
482 do { \
483 __ sync(); \
484 __ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
485 __ sync(); \
486 } while (0)
487
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100488void CodeGenerator::AssembleDeconstructFrame() {
489 __ mov(sp, fp);
490 __ Pop(ra, fp);
491}
492
Ben Murdoch014dc512016-03-22 12:00:34 +0000493void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
494 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
495 if (sp_slot_delta > 0) {
496 __ addiu(sp, sp, sp_slot_delta * kPointerSize);
497 }
498 frame_access_state()->SetFrameAccessToDefault();
499}
500
501
502void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
503 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
504 if (sp_slot_delta < 0) {
505 __ Subu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
506 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
507 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100508 if (frame_access_state()->has_frame()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000509 __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
510 __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
511 }
512 frame_access_state()->SetFrameAccessToSP();
513}
Emily Bernier958fae72015-03-24 16:35:39 -0400514
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100515void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
516 Register scratch1,
517 Register scratch2,
518 Register scratch3) {
519 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
520 Label done;
521
522 // Check if current frame is an arguments adaptor frame.
523 __ lw(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
524 __ Branch(&done, ne, scratch1,
525 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
526
527 // Load arguments count from current arguments adaptor frame (note, it
528 // does not include receiver).
529 Register caller_args_count_reg = scratch1;
530 __ lw(caller_args_count_reg,
531 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
532 __ SmiUntag(caller_args_count_reg);
533
534 ParameterCount callee_args_count(args_reg);
535 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
536 scratch3);
537 __ bind(&done);
538}
Emily Bernier958fae72015-03-24 16:35:39 -0400539
540// Assembles an instruction after register allocation, producing machine code.
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100541CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
542 Instruction* instr) {
Emily Bernier958fae72015-03-24 16:35:39 -0400543 MipsOperandConverter i(this, instr);
544 InstructionCode opcode = instr->opcode();
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100545 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
546 switch (arch_opcode) {
Emily Bernier958fae72015-03-24 16:35:39 -0400547 case kArchCallCodeObject: {
548 EnsureSpaceForLazyDeopt();
549 if (instr->InputAt(0)->IsImmediate()) {
550 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
551 RelocInfo::CODE_TARGET);
552 } else {
553 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
554 __ Call(at);
555 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000556 RecordCallPosition(instr);
557 frame_access_state()->ClearSPDelta();
558 break;
559 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100560 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch014dc512016-03-22 12:00:34 +0000561 case kArchTailCallCodeObject: {
562 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
563 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100564 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
565 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
566 i.TempRegister(0), i.TempRegister(1),
567 i.TempRegister(2));
568 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000569 if (instr->InputAt(0)->IsImmediate()) {
570 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
571 RelocInfo::CODE_TARGET);
572 } else {
573 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
574 __ Jump(at);
575 }
576 frame_access_state()->ClearSPDelta();
Emily Bernier958fae72015-03-24 16:35:39 -0400577 break;
578 }
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100579 case kArchTailCallAddress: {
580 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
581 AssembleDeconstructActivationRecord(stack_param_delta);
582 CHECK(!instr->InputAt(0)->IsImmediate());
583 __ Jump(i.InputRegister(0));
584 frame_access_state()->ClearSPDelta();
585 break;
586 }
Emily Bernier958fae72015-03-24 16:35:39 -0400587 case kArchCallJSFunction: {
588 EnsureSpaceForLazyDeopt();
589 Register func = i.InputRegister(0);
590 if (FLAG_debug_code) {
591 // Check the function's context matches the context argument.
592 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
593 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
594 }
595
596 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
597 __ Call(at);
Ben Murdoch014dc512016-03-22 12:00:34 +0000598 RecordCallPosition(instr);
599 frame_access_state()->ClearSPDelta();
600 break;
601 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100602 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch014dc512016-03-22 12:00:34 +0000603 case kArchTailCallJSFunction: {
604 Register func = i.InputRegister(0);
605 if (FLAG_debug_code) {
606 // Check the function's context matches the context argument.
607 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
608 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
609 }
610
611 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
612 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100613 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
614 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
615 i.TempRegister(0), i.TempRegister(1),
616 i.TempRegister(2));
617 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000618 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
619 __ Jump(at);
620 frame_access_state()->ClearSPDelta();
621 break;
622 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000623 case kArchPrepareCallCFunction: {
624 int const num_parameters = MiscField::decode(instr->opcode());
625 __ PrepareCallCFunction(num_parameters, kScratchReg);
626 // Frame alignment requires using FP-relative frame addressing.
627 frame_access_state()->SetFrameAccessToFP();
628 break;
629 }
630 case kArchPrepareTailCall:
631 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
632 break;
633 case kArchCallCFunction: {
634 int const num_parameters = MiscField::decode(instr->opcode());
635 if (instr->InputAt(0)->IsImmediate()) {
636 ExternalReference ref = i.InputExternalReference(0);
637 __ CallCFunction(ref, num_parameters);
638 } else {
639 Register func = i.InputRegister(0);
640 __ CallCFunction(func, num_parameters);
641 }
642 frame_access_state()->SetFrameAccessToDefault();
643 frame_access_state()->ClearSPDelta();
Emily Bernier958fae72015-03-24 16:35:39 -0400644 break;
645 }
646 case kArchJmp:
647 AssembleArchJump(i.InputRpo(0));
648 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000649 case kArchLookupSwitch:
650 AssembleArchLookupSwitch(instr);
651 break;
652 case kArchTableSwitch:
653 AssembleArchTableSwitch(instr);
654 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400655 case kArchNop:
Ben Murdoch014dc512016-03-22 12:00:34 +0000656 case kArchThrowTerminator:
Emily Bernier958fae72015-03-24 16:35:39 -0400657 // don't emit code for nops.
658 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000659 case kArchDeoptimize: {
660 int deopt_state_id =
661 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
662 Deoptimizer::BailoutType bailout_type =
663 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100664 CodeGenResult result =
665 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
666 if (result != kSuccess) return result;
Ben Murdoch014dc512016-03-22 12:00:34 +0000667 break;
668 }
Emily Bernier958fae72015-03-24 16:35:39 -0400669 case kArchRet:
670 AssembleReturn();
671 break;
672 case kArchStackPointer:
673 __ mov(i.OutputRegister(), sp);
674 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000675 case kArchFramePointer:
676 __ mov(i.OutputRegister(), fp);
677 break;
Ben Murdoch109988c2016-05-18 11:27:45 +0100678 case kArchParentFramePointer:
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100679 if (frame_access_state()->has_frame()) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100680 __ lw(i.OutputRegister(), MemOperand(fp, 0));
681 } else {
682 __ mov(i.OutputRegister(), fp);
683 }
684 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400685 case kArchTruncateDoubleToI:
686 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
687 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000688 case kArchStoreWithWriteBarrier: {
689 RecordWriteMode mode =
690 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
691 Register object = i.InputRegister(0);
692 Register index = i.InputRegister(1);
693 Register value = i.InputRegister(2);
694 Register scratch0 = i.TempRegister(0);
695 Register scratch1 = i.TempRegister(1);
696 auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
697 scratch0, scratch1, mode);
698 __ Addu(at, object, index);
699 __ sw(value, MemOperand(at));
700 __ CheckPageFlag(object, scratch0,
701 MemoryChunk::kPointersFromHereAreInterestingMask, ne,
702 ool->entry());
703 __ bind(ool->exit());
704 break;
705 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100706 case kArchStackSlot: {
707 FrameOffset offset =
708 frame_access_state()->GetFrameOffset(i.InputInt32(0));
709 __ Addu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
710 Operand(offset.offset()));
711 break;
712 }
Emily Bernier958fae72015-03-24 16:35:39 -0400713 case kMipsAdd:
714 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
715 break;
716 case kMipsAddOvf:
Ben Murdoch014dc512016-03-22 12:00:34 +0000717 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
Emily Bernier958fae72015-03-24 16:35:39 -0400718 break;
719 case kMipsSub:
720 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
721 break;
722 case kMipsSubOvf:
Ben Murdoch014dc512016-03-22 12:00:34 +0000723 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
Emily Bernier958fae72015-03-24 16:35:39 -0400724 break;
725 case kMipsMul:
726 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
727 break;
728 case kMipsMulHigh:
729 __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
730 break;
731 case kMipsMulHighU:
732 __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
733 break;
734 case kMipsDiv:
735 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +0000736 if (IsMipsArchVariant(kMips32r6)) {
737 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
738 } else {
739 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
740 }
Emily Bernier958fae72015-03-24 16:35:39 -0400741 break;
742 case kMipsDivU:
743 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +0000744 if (IsMipsArchVariant(kMips32r6)) {
745 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
746 } else {
747 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
748 }
Emily Bernier958fae72015-03-24 16:35:39 -0400749 break;
750 case kMipsMod:
751 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
752 break;
753 case kMipsModU:
754 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
755 break;
756 case kMipsAnd:
757 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
758 break;
759 case kMipsOr:
760 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
761 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000762 case kMipsNor:
763 if (instr->InputAt(1)->IsRegister()) {
764 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
765 } else {
766 DCHECK(i.InputOperand(1).immediate() == 0);
767 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
768 }
769 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400770 case kMipsXor:
771 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
772 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000773 case kMipsClz:
774 __ Clz(i.OutputRegister(), i.InputRegister(0));
775 break;
Ben Murdoch109988c2016-05-18 11:27:45 +0100776 case kMipsCtz: {
777 Register reg1 = kScratchReg;
778 Register reg2 = kScratchReg2;
779 Label skip_for_zero;
780 Label end;
781 // Branch if the operand is zero
782 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
783 // Find the number of bits before the last bit set to 1.
784 __ Subu(reg2, zero_reg, i.InputRegister(0));
785 __ And(reg2, reg2, i.InputRegister(0));
786 __ clz(reg2, reg2);
787 // Get the number of bits after the last bit set to 1.
788 __ li(reg1, 0x1F);
789 __ Subu(i.OutputRegister(), reg1, reg2);
790 __ Branch(&end);
791 __ bind(&skip_for_zero);
792 // If the operand is zero, return word length as the result.
793 __ li(i.OutputRegister(), 0x20);
794 __ bind(&end);
795 } break;
796 case kMipsPopcnt: {
797 Register reg1 = kScratchReg;
798 Register reg2 = kScratchReg2;
799 uint32_t m1 = 0x55555555;
800 uint32_t m2 = 0x33333333;
801 uint32_t m4 = 0x0f0f0f0f;
802 uint32_t m8 = 0x00ff00ff;
803 uint32_t m16 = 0x0000ffff;
804
805 // Put count of ones in every 2 bits into those 2 bits.
806 __ li(at, m1);
807 __ srl(reg1, i.InputRegister(0), 1);
808 __ And(reg2, i.InputRegister(0), at);
809 __ And(reg1, reg1, at);
810 __ addu(reg1, reg1, reg2);
811
812 // Put count of ones in every 4 bits into those 4 bits.
813 __ li(at, m2);
814 __ srl(reg2, reg1, 2);
815 __ And(reg2, reg2, at);
816 __ And(reg1, reg1, at);
817 __ addu(reg1, reg1, reg2);
818
819 // Put count of ones in every 8 bits into those 8 bits.
820 __ li(at, m4);
821 __ srl(reg2, reg1, 4);
822 __ And(reg2, reg2, at);
823 __ And(reg1, reg1, at);
824 __ addu(reg1, reg1, reg2);
825
826 // Put count of ones in every 16 bits into those 16 bits.
827 __ li(at, m8);
828 __ srl(reg2, reg1, 8);
829 __ And(reg2, reg2, at);
830 __ And(reg1, reg1, at);
831 __ addu(reg1, reg1, reg2);
832
833 // Calculate total number of ones.
834 __ li(at, m16);
835 __ srl(reg2, reg1, 16);
836 __ And(reg2, reg2, at);
837 __ And(reg1, reg1, at);
838 __ addu(i.OutputRegister(), reg1, reg2);
839 } break;
Emily Bernier958fae72015-03-24 16:35:39 -0400840 case kMipsShl:
841 if (instr->InputAt(1)->IsRegister()) {
842 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
843 } else {
844 int32_t imm = i.InputOperand(1).immediate();
845 __ sll(i.OutputRegister(), i.InputRegister(0), imm);
846 }
847 break;
848 case kMipsShr:
849 if (instr->InputAt(1)->IsRegister()) {
850 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
851 } else {
852 int32_t imm = i.InputOperand(1).immediate();
853 __ srl(i.OutputRegister(), i.InputRegister(0), imm);
854 }
855 break;
856 case kMipsSar:
857 if (instr->InputAt(1)->IsRegister()) {
858 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
859 } else {
860 int32_t imm = i.InputOperand(1).immediate();
861 __ sra(i.OutputRegister(), i.InputRegister(0), imm);
862 }
863 break;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100864 case kMipsShlPair: {
865 if (instr->InputAt(2)->IsRegister()) {
866 __ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
867 i.InputRegister(1), i.InputRegister(2));
868 } else {
869 uint32_t imm = i.InputOperand(2).immediate();
870 __ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
871 i.InputRegister(1), imm);
872 }
873 } break;
874 case kMipsShrPair: {
875 if (instr->InputAt(2)->IsRegister()) {
876 __ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
877 i.InputRegister(1), i.InputRegister(2));
878 } else {
879 uint32_t imm = i.InputOperand(2).immediate();
880 __ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
881 i.InputRegister(1), imm);
882 }
883 } break;
884 case kMipsSarPair: {
885 if (instr->InputAt(2)->IsRegister()) {
886 __ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
887 i.InputRegister(1), i.InputRegister(2));
888 } else {
889 uint32_t imm = i.InputOperand(2).immediate();
890 __ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
891 i.InputRegister(1), imm);
892 }
893 } break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000894 case kMipsExt:
895 __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
896 i.InputInt8(2));
897 break;
898 case kMipsIns:
899 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
900 __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
901 } else {
902 __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
903 i.InputInt8(2));
904 }
905 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400906 case kMipsRor:
907 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
908 break;
909 case kMipsTst:
910 // Pseudo-instruction used for tst/branch. No opcode emitted here.
911 break;
912 case kMipsCmp:
913 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
914 break;
915 case kMipsMov:
916 // TODO(plind): Should we combine mov/li like this, or use separate instr?
917 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
918 if (HasRegisterInput(instr, 0)) {
919 __ mov(i.OutputRegister(), i.InputRegister(0));
920 } else {
921 __ li(i.OutputRegister(), i.InputOperand(0));
922 }
923 break;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100924 case kMipsLsa:
925 DCHECK(instr->InputAt(2)->IsImmediate());
926 __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
927 i.InputInt8(2));
928 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000929 case kMipsCmpS:
930 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
931 break;
932 case kMipsAddS:
933 // TODO(plind): add special case: combine mult & add.
934 __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
935 i.InputDoubleRegister(1));
936 break;
937 case kMipsSubS:
938 __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
939 i.InputDoubleRegister(1));
940 break;
941 case kMipsMulS:
942 // TODO(plind): add special case: right op is -1.0, see arm port.
943 __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
944 i.InputDoubleRegister(1));
945 break;
946 case kMipsDivS:
947 __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
948 i.InputDoubleRegister(1));
949 break;
950 case kMipsModS: {
951 // TODO(bmeurer): We should really get rid of this special instruction,
952 // and generate a CallAddress instruction instead.
953 FrameScope scope(masm(), StackFrame::MANUAL);
954 __ PrepareCallCFunction(0, 2, kScratchReg);
955 __ MovToFloatParameters(i.InputDoubleRegister(0),
956 i.InputDoubleRegister(1));
957 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
958 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
959 0, 2);
960 // Move the result in the double result register.
961 __ MovFromFloatResult(i.OutputSingleRegister());
962 break;
963 }
964 case kMipsAbsS:
965 __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
966 break;
967 case kMipsSqrtS: {
968 __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
969 break;
970 }
971 case kMipsMaxS:
972 __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
973 i.InputDoubleRegister(1));
974 break;
975 case kMipsMinS:
976 __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
977 i.InputDoubleRegister(1));
978 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400979 case kMipsCmpD:
980 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
981 break;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100982 case kMipsAddPair:
983 __ AddPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
984 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3));
985 break;
986 case kMipsSubPair:
987 __ SubPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
988 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3));
989 break;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100990 case kMipsMulPair: {
991 __ Mulu(i.OutputRegister(1), i.OutputRegister(0), i.InputRegister(0),
992 i.InputRegister(2));
993 __ mul(kScratchReg, i.InputRegister(0), i.InputRegister(3));
994 __ mul(kScratchReg2, i.InputRegister(1), i.InputRegister(2));
995 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg);
996 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg2);
997 } break;
Emily Bernier958fae72015-03-24 16:35:39 -0400998 case kMipsAddD:
999 // TODO(plind): add special case: combine mult & add.
1000 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1001 i.InputDoubleRegister(1));
1002 break;
1003 case kMipsSubD:
1004 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1005 i.InputDoubleRegister(1));
1006 break;
1007 case kMipsMulD:
1008 // TODO(plind): add special case: right op is -1.0, see arm port.
1009 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1010 i.InputDoubleRegister(1));
1011 break;
1012 case kMipsDivD:
1013 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1014 i.InputDoubleRegister(1));
1015 break;
1016 case kMipsModD: {
1017 // TODO(bmeurer): We should really get rid of this special instruction,
1018 // and generate a CallAddress instruction instead.
1019 FrameScope scope(masm(), StackFrame::MANUAL);
1020 __ PrepareCallCFunction(0, 2, kScratchReg);
1021 __ MovToFloatParameters(i.InputDoubleRegister(0),
1022 i.InputDoubleRegister(1));
1023 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1024 0, 2);
1025 // Move the result in the double result register.
1026 __ MovFromFloatResult(i.OutputDoubleRegister());
1027 break;
1028 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001029 case kMipsAbsD:
1030 __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1031 break;
1032 case kMipsSqrtD: {
1033 __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
Emily Bernier958fae72015-03-24 16:35:39 -04001034 break;
1035 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001036 case kMipsMaxD:
1037 __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1038 i.InputDoubleRegister(1));
1039 break;
1040 case kMipsMinD:
1041 __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1042 i.InputDoubleRegister(1));
1043 break;
1044 case kMipsFloat64RoundDown: {
1045 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
1046 break;
1047 }
1048 case kMipsFloat32RoundDown: {
1049 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
Emily Bernier958fae72015-03-24 16:35:39 -04001050 break;
1051 }
1052 case kMipsFloat64RoundTruncate: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001053 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
Emily Bernier958fae72015-03-24 16:35:39 -04001054 break;
1055 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001056 case kMipsFloat32RoundTruncate: {
1057 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
1058 break;
1059 }
1060 case kMipsFloat64RoundUp: {
1061 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
1062 break;
1063 }
1064 case kMipsFloat32RoundUp: {
1065 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
1066 break;
1067 }
1068 case kMipsFloat64RoundTiesEven: {
1069 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
1070 break;
1071 }
1072 case kMipsFloat32RoundTiesEven: {
1073 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
1074 break;
1075 }
1076 case kMipsFloat64Max: {
1077 // (b < a) ? a : b
1078 if (IsMipsArchVariant(kMips32r6)) {
1079 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1080 i.InputDoubleRegister(0));
1081 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1082 i.InputDoubleRegister(0));
1083 } else {
1084 __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1085 // Left operand is result, passthrough if false.
1086 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1087 }
1088 break;
1089 }
1090 case kMipsFloat64Min: {
1091 // (a < b) ? a : b
1092 if (IsMipsArchVariant(kMips32r6)) {
1093 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1094 i.InputDoubleRegister(1));
1095 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1096 i.InputDoubleRegister(0));
1097 } else {
1098 __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1099 // Right operand is result, passthrough if false.
1100 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1101 }
1102 break;
1103 }
1104 case kMipsFloat32Max: {
1105 // (b < a) ? a : b
1106 if (IsMipsArchVariant(kMips32r6)) {
1107 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1108 i.InputDoubleRegister(0));
1109 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1110 i.InputDoubleRegister(0));
1111 } else {
1112 __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1113 // Left operand is result, passthrough if false.
1114 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1115 }
1116 break;
1117 }
1118 case kMipsFloat32Min: {
1119 // (a < b) ? a : b
1120 if (IsMipsArchVariant(kMips32r6)) {
1121 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1122 i.InputDoubleRegister(1));
1123 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1124 i.InputDoubleRegister(0));
1125 } else {
1126 __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1127 // Right operand is result, passthrough if false.
1128 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1129 }
Emily Bernier958fae72015-03-24 16:35:39 -04001130 break;
1131 }
1132 case kMipsCvtSD: {
1133 __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1134 break;
1135 }
1136 case kMipsCvtDS: {
1137 __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1138 break;
1139 }
1140 case kMipsCvtDW: {
1141 FPURegister scratch = kScratchDoubleReg;
1142 __ mtc1(i.InputRegister(0), scratch);
1143 __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1144 break;
1145 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001146 case kMipsCvtSW: {
1147 FPURegister scratch = kScratchDoubleReg;
1148 __ mtc1(i.InputRegister(0), scratch);
1149 __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1150 break;
1151 }
Ben Murdoch109988c2016-05-18 11:27:45 +01001152 case kMipsCvtSUw: {
1153 FPURegister scratch = kScratchDoubleReg;
1154 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1155 __ cvt_s_d(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1156 break;
1157 }
Emily Bernier958fae72015-03-24 16:35:39 -04001158 case kMipsCvtDUw: {
1159 FPURegister scratch = kScratchDoubleReg;
1160 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1161 break;
1162 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001163 case kMipsFloorWD: {
1164 FPURegister scratch = kScratchDoubleReg;
1165 __ floor_w_d(scratch, i.InputDoubleRegister(0));
1166 __ mfc1(i.OutputRegister(), scratch);
1167 break;
1168 }
1169 case kMipsCeilWD: {
1170 FPURegister scratch = kScratchDoubleReg;
1171 __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1172 __ mfc1(i.OutputRegister(), scratch);
1173 break;
1174 }
1175 case kMipsRoundWD: {
1176 FPURegister scratch = kScratchDoubleReg;
1177 __ round_w_d(scratch, i.InputDoubleRegister(0));
1178 __ mfc1(i.OutputRegister(), scratch);
1179 break;
1180 }
Emily Bernier958fae72015-03-24 16:35:39 -04001181 case kMipsTruncWD: {
1182 FPURegister scratch = kScratchDoubleReg;
1183 // Other arches use round to zero here, so we follow.
1184 __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1185 __ mfc1(i.OutputRegister(), scratch);
1186 break;
1187 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001188 case kMipsFloorWS: {
1189 FPURegister scratch = kScratchDoubleReg;
1190 __ floor_w_s(scratch, i.InputDoubleRegister(0));
1191 __ mfc1(i.OutputRegister(), scratch);
1192 break;
1193 }
1194 case kMipsCeilWS: {
1195 FPURegister scratch = kScratchDoubleReg;
1196 __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1197 __ mfc1(i.OutputRegister(), scratch);
1198 break;
1199 }
1200 case kMipsRoundWS: {
1201 FPURegister scratch = kScratchDoubleReg;
1202 __ round_w_s(scratch, i.InputDoubleRegister(0));
1203 __ mfc1(i.OutputRegister(), scratch);
1204 break;
1205 }
1206 case kMipsTruncWS: {
1207 FPURegister scratch = kScratchDoubleReg;
1208 __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1209 __ mfc1(i.OutputRegister(), scratch);
1210 break;
1211 }
Emily Bernier958fae72015-03-24 16:35:39 -04001212 case kMipsTruncUwD: {
1213 FPURegister scratch = kScratchDoubleReg;
1214 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1215 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1216 break;
1217 }
Ben Murdoch109988c2016-05-18 11:27:45 +01001218 case kMipsTruncUwS: {
1219 FPURegister scratch = kScratchDoubleReg;
1220 // TODO(plind): Fix wrong param order of Trunc_uw_s() macro-asm function.
1221 __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1222 break;
1223 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001224 case kMipsFloat64ExtractLowWord32:
1225 __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1226 break;
1227 case kMipsFloat64ExtractHighWord32:
1228 __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1229 break;
1230 case kMipsFloat64InsertLowWord32:
1231 __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1232 break;
1233 case kMipsFloat64InsertHighWord32:
1234 __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1235 break;
Emily Bernier958fae72015-03-24 16:35:39 -04001236 // ... more basic instructions ...
1237
1238 case kMipsLbu:
1239 __ lbu(i.OutputRegister(), i.MemoryOperand());
1240 break;
1241 case kMipsLb:
1242 __ lb(i.OutputRegister(), i.MemoryOperand());
1243 break;
1244 case kMipsSb:
1245 __ sb(i.InputRegister(2), i.MemoryOperand());
1246 break;
1247 case kMipsLhu:
1248 __ lhu(i.OutputRegister(), i.MemoryOperand());
1249 break;
1250 case kMipsLh:
1251 __ lh(i.OutputRegister(), i.MemoryOperand());
1252 break;
1253 case kMipsSh:
1254 __ sh(i.InputRegister(2), i.MemoryOperand());
1255 break;
1256 case kMipsLw:
1257 __ lw(i.OutputRegister(), i.MemoryOperand());
1258 break;
1259 case kMipsSw:
1260 __ sw(i.InputRegister(2), i.MemoryOperand());
1261 break;
1262 case kMipsLwc1: {
1263 __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1264 break;
1265 }
1266 case kMipsSwc1: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001267 size_t index = 0;
Emily Bernier958fae72015-03-24 16:35:39 -04001268 MemOperand operand = i.MemoryOperand(&index);
1269 __ swc1(i.InputSingleRegister(index), operand);
1270 break;
1271 }
1272 case kMipsLdc1:
1273 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1274 break;
1275 case kMipsSdc1:
1276 __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
1277 break;
1278 case kMipsPush:
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001279 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001280 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1281 __ Subu(sp, sp, Operand(kDoubleSize));
1282 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1283 } else {
1284 __ Push(i.InputRegister(0));
1285 frame_access_state()->IncreaseSPDelta(1);
1286 }
Emily Bernier958fae72015-03-24 16:35:39 -04001287 break;
1288 case kMipsStackClaim: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001289 __ Subu(sp, sp, Operand(i.InputInt32(0)));
1290 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001291 break;
1292 }
1293 case kMipsStoreToStackSlot: {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001294 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001295 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1296 } else {
1297 __ sw(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1298 }
Emily Bernier958fae72015-03-24 16:35:39 -04001299 break;
1300 }
1301 case kCheckedLoadInt8:
1302 ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
1303 break;
1304 case kCheckedLoadUint8:
1305 ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
1306 break;
1307 case kCheckedLoadInt16:
1308 ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
1309 break;
1310 case kCheckedLoadUint16:
1311 ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
1312 break;
1313 case kCheckedLoadWord32:
1314 ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
1315 break;
1316 case kCheckedLoadFloat32:
1317 ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
1318 break;
1319 case kCheckedLoadFloat64:
1320 ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
1321 break;
1322 case kCheckedStoreWord8:
1323 ASSEMBLE_CHECKED_STORE_INTEGER(sb);
1324 break;
1325 case kCheckedStoreWord16:
1326 ASSEMBLE_CHECKED_STORE_INTEGER(sh);
1327 break;
1328 case kCheckedStoreWord32:
1329 ASSEMBLE_CHECKED_STORE_INTEGER(sw);
1330 break;
1331 case kCheckedStoreFloat32:
1332 ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
1333 break;
1334 case kCheckedStoreFloat64:
1335 ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
1336 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001337 case kCheckedLoadWord64:
1338 case kCheckedStoreWord64:
1339 UNREACHABLE(); // currently unsupported checked int64 load/store.
1340 break;
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001341 case kAtomicLoadInt8:
1342 ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
1343 break;
1344 case kAtomicLoadUint8:
1345 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
1346 break;
1347 case kAtomicLoadInt16:
1348 ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
1349 break;
1350 case kAtomicLoadUint16:
1351 ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
1352 break;
1353 case kAtomicLoadWord32:
1354 ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
1355 break;
1356 case kAtomicStoreWord8:
1357 ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
1358 break;
1359 case kAtomicStoreWord16:
1360 ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
1361 break;
1362 case kAtomicStoreWord32:
1363 ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
1364 break;
Emily Bernier958fae72015-03-24 16:35:39 -04001365 }
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001366 return kSuccess;
Ben Murdoch014dc512016-03-22 12:00:34 +00001367} // NOLINT(readability/fn_size)
Emily Bernier958fae72015-03-24 16:35:39 -04001368
1369
1370#define UNSUPPORTED_COND(opcode, condition) \
1371 OFStream out(stdout); \
1372 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
1373 UNIMPLEMENTED();
1374
Ben Murdoch014dc512016-03-22 12:00:34 +00001375static bool convertCondition(FlagsCondition condition, Condition& cc) {
1376 switch (condition) {
1377 case kEqual:
1378 cc = eq;
1379 return true;
1380 case kNotEqual:
1381 cc = ne;
1382 return true;
1383 case kUnsignedLessThan:
1384 cc = lt;
1385 return true;
1386 case kUnsignedGreaterThanOrEqual:
1387 cc = uge;
1388 return true;
1389 case kUnsignedLessThanOrEqual:
1390 cc = le;
1391 return true;
1392 case kUnsignedGreaterThan:
1393 cc = ugt;
1394 return true;
1395 default:
1396 break;
1397 }
1398 return false;
1399}
1400
1401
Emily Bernier958fae72015-03-24 16:35:39 -04001402// Assembles branches after an instruction.
1403void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1404 MipsOperandConverter i(this, instr);
1405 Label* tlabel = branch->true_label;
1406 Label* flabel = branch->false_label;
1407 Condition cc = kNoCondition;
Emily Bernier958fae72015-03-24 16:35:39 -04001408 // MIPS does not have condition code flags, so compare and branch are
1409 // implemented differently than on the other arch's. The compare operations
1410 // emit mips pseudo-instructions, which are handled here by branch
1411 // instructions that do the actual comparison. Essential that the input
1412 // registers to compare pseudo-op are not modified before this branch op, as
1413 // they are tested here.
Emily Bernier958fae72015-03-24 16:35:39 -04001414
1415 if (instr->arch_opcode() == kMipsTst) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001416 cc = FlagsConditionToConditionTst(branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001417 __ And(at, i.InputRegister(0), i.InputOperand(1));
1418 __ Branch(tlabel, cc, at, Operand(zero_reg));
Ben Murdoch014dc512016-03-22 12:00:34 +00001419 } else if (instr->arch_opcode() == kMipsAddOvf) {
Emily Bernier958fae72015-03-24 16:35:39 -04001420 switch (branch->condition) {
1421 case kOverflow:
Ben Murdoch014dc512016-03-22 12:00:34 +00001422 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1423 i.InputOperand(1), tlabel, flabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001424 break;
1425 case kNotOverflow:
Ben Murdoch014dc512016-03-22 12:00:34 +00001426 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1427 i.InputOperand(1), flabel, tlabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001428 break;
1429 default:
1430 UNSUPPORTED_COND(kMipsAddOvf, branch->condition);
1431 break;
1432 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001433 } else if (instr->arch_opcode() == kMipsSubOvf) {
1434 switch (branch->condition) {
1435 case kOverflow:
1436 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1437 i.InputOperand(1), tlabel, flabel);
1438 break;
1439 case kNotOverflow:
1440 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1441 i.InputOperand(1), flabel, tlabel);
1442 break;
1443 default:
1444 UNSUPPORTED_COND(kMipsAddOvf, branch->condition);
1445 break;
1446 }
Emily Bernier958fae72015-03-24 16:35:39 -04001447 } else if (instr->arch_opcode() == kMipsCmp) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001448 cc = FlagsConditionToConditionCmp(branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001449 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +00001450 } else if (instr->arch_opcode() == kMipsCmpS) {
1451 if (!convertCondition(branch->condition, cc)) {
1452 UNSUPPORTED_COND(kMips64CmpS, branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001453 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001454 FPURegister left = i.InputOrZeroSingleRegister(0);
1455 FPURegister right = i.InputOrZeroSingleRegister(1);
1456 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1457 !__ IsDoubleZeroRegSet()) {
1458 __ Move(kDoubleRegZero, 0.0);
1459 }
1460 __ BranchF32(tlabel, nullptr, cc, left, right);
1461 } else if (instr->arch_opcode() == kMipsCmpD) {
1462 if (!convertCondition(branch->condition, cc)) {
1463 UNSUPPORTED_COND(kMips64CmpD, branch->condition);
1464 }
1465 FPURegister left = i.InputOrZeroDoubleRegister(0);
1466 FPURegister right = i.InputOrZeroDoubleRegister(1);
1467 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1468 !__ IsDoubleZeroRegSet()) {
1469 __ Move(kDoubleRegZero, 0.0);
1470 }
1471 __ BranchF64(tlabel, nullptr, cc, left, right);
Emily Bernier958fae72015-03-24 16:35:39 -04001472 } else {
1473 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
1474 instr->arch_opcode());
1475 UNIMPLEMENTED();
1476 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001477 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel.
Emily Bernier958fae72015-03-24 16:35:39 -04001478}
1479
1480
Ben Murdoch014dc512016-03-22 12:00:34 +00001481void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernier958fae72015-03-24 16:35:39 -04001482 if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
1483}
1484
1485
1486// Assembles boolean materializations after an instruction.
1487void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1488 FlagsCondition condition) {
1489 MipsOperandConverter i(this, instr);
1490 Label done;
1491
1492 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1493 // last output of the instruction.
1494 Label false_value;
Ben Murdoch014dc512016-03-22 12:00:34 +00001495 DCHECK_NE(0u, instr->OutputCount());
Emily Bernier958fae72015-03-24 16:35:39 -04001496 Register result = i.OutputRegister(instr->OutputCount() - 1);
1497 Condition cc = kNoCondition;
Emily Bernier958fae72015-03-24 16:35:39 -04001498 // MIPS does not have condition code flags, so compare and branch are
1499 // implemented differently than on the other arch's. The compare operations
1500 // emit mips psuedo-instructions, which are checked and handled here.
1501
Emily Bernier958fae72015-03-24 16:35:39 -04001502 if (instr->arch_opcode() == kMipsTst) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001503 cc = FlagsConditionToConditionTst(condition);
1504 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1505 __ Sltu(result, zero_reg, kScratchReg);
1506 if (cc == eq) {
1507 // Sltu produces 0 for equality, invert the result.
1508 __ xori(result, result, 1);
Emily Bernier958fae72015-03-24 16:35:39 -04001509 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001510 return;
Emily Bernier958fae72015-03-24 16:35:39 -04001511 } else if (instr->arch_opcode() == kMipsAddOvf ||
1512 instr->arch_opcode() == kMipsSubOvf) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001513 Label flabel, tlabel;
1514 switch (instr->arch_opcode()) {
1515 case kMipsAddOvf:
1516 __ AddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1517 i.InputOperand(1), &flabel);
1518
Emily Bernier958fae72015-03-24 16:35:39 -04001519 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001520 case kMipsSubOvf:
1521 __ SubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1522 i.InputOperand(1), &flabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001523 break;
1524 default:
Ben Murdoch014dc512016-03-22 12:00:34 +00001525 UNREACHABLE();
Emily Bernier958fae72015-03-24 16:35:39 -04001526 break;
1527 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001528 __ li(result, 1);
1529 __ Branch(&tlabel);
1530 __ bind(&flabel);
1531 __ li(result, 0);
1532 __ bind(&tlabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001533 } else if (instr->arch_opcode() == kMipsCmp) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001534 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 __ Subu(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;
Emily Bernier958fae72015-03-24 16:35:39 -04001590 default:
Ben Murdoch014dc512016-03-22 12:00:34 +00001591 UNREACHABLE();
Emily Bernier958fae72015-03-24 16:35:39 -04001592 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001593 return;
1594 } else if (instr->arch_opcode() == kMipsCmpD ||
1595 instr->arch_opcode() == kMipsCmpS) {
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);
Emily Bernier958fae72015-03-24 16:35:39 -04001601 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001602 bool predicate;
1603 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
1604 if (!IsMipsArchVariant(kMips32r6)) {
1605 __ li(result, Operand(1));
1606 if (instr->arch_opcode() == kMipsCmpD) {
1607 __ c(cc, D, left, right);
1608 } else {
1609 DCHECK(instr->arch_opcode() == kMipsCmpS);
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() == kMipsCmpD) {
1619 __ cmp(cc, L, kDoubleCompareReg, left, right);
1620 } else {
1621 DCHECK(instr->arch_opcode() == kMipsCmpS);
1622 __ cmp(cc, W, kDoubleCompareReg, left, right);
1623 }
1624 __ mfc1(result, kDoubleCompareReg);
1625 __ andi(result, result, 1); // Cmp returns all 1's/0's, use only LSB.
1626 if (!predicate) // Toggle result for not equal.
1627 __ xori(result, result, 1);
1628 }
1629 return;
Emily Bernier958fae72015-03-24 16:35:39 -04001630 } else {
1631 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
1632 instr->arch_opcode());
1633 TRACE_UNIMPL();
1634 UNIMPLEMENTED();
1635 }
Emily Bernier958fae72015-03-24 16:35:39 -04001636}
1637
1638
Ben Murdoch014dc512016-03-22 12:00:34 +00001639void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1640 MipsOperandConverter i(this, instr);
1641 Register input = i.InputRegister(0);
1642 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1643 __ li(at, Operand(i.InputInt32(index + 0)));
1644 __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
1645 }
1646 __ nop(); // Branch delay slot of the last beq.
1647 AssembleArchJump(i.InputRpo(1));
1648}
1649
1650
1651void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1652 MipsOperandConverter i(this, instr);
1653 Register input = i.InputRegister(0);
1654 size_t const case_count = instr->InputCount() - 2;
Ben Murdoch014dc512016-03-22 12:00:34 +00001655 __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
Ben Murdoch109988c2016-05-18 11:27:45 +01001656 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
1657 return GetLabel(i.InputRpo(index + 2));
1658 });
Ben Murdoch014dc512016-03-22 12:00:34 +00001659}
1660
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001661CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch014dc512016-03-22 12:00:34 +00001662 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Emily Bernier958fae72015-03-24 16:35:39 -04001663 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch014dc512016-03-22 12:00:34 +00001664 isolate(), deoptimization_id, bailout_type);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001665 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Emily Bernier958fae72015-03-24 16:35:39 -04001666 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001667 return kSuccess;
Emily Bernier958fae72015-03-24 16:35:39 -04001668}
1669
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001670void CodeGenerator::FinishFrame(Frame* frame) {
Emily Bernier958fae72015-03-24 16:35:39 -04001671 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001672
1673 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1674 if (saves_fpu != 0) {
1675 frame->AlignSavedCalleeRegisterSlots();
1676 }
1677
1678 if (saves_fpu != 0) {
1679 int count = base::bits::CountPopulation32(saves_fpu);
1680 DCHECK(kNumCalleeSavedFPU == count);
1681 frame->AllocateSavedCalleeRegisterSlots(count *
1682 (kDoubleSize / kPointerSize));
1683 }
1684
1685 const RegList saves = descriptor->CalleeSavedRegisters();
1686 if (saves != 0) {
1687 int count = base::bits::CountPopulation32(saves);
1688 DCHECK(kNumCalleeSaved == count + 1);
1689 frame->AllocateSavedCalleeRegisterSlots(count);
1690 }
1691}
1692
1693void CodeGenerator::AssembleConstructFrame() {
1694 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001695 if (frame_access_state()->has_frame()) {
1696 if (descriptor->IsCFunctionCall()) {
1697 __ Push(ra, fp);
1698 __ mov(fp, sp);
1699 } else if (descriptor->IsJSFunctionCall()) {
1700 __ Prologue(this->info()->GeneratePreagedPrologue());
1701 } else {
1702 __ StubPrologue(info()->GetOutputStackFrameType());
1703 }
Emily Bernier958fae72015-03-24 16:35:39 -04001704 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001705
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001706 int shrink_slots = frame()->GetSpillSlotCount();
1707
Ben Murdoch014dc512016-03-22 12:00:34 +00001708 if (info()->is_osr()) {
1709 // TurboFan OSR-compiled functions cannot be entered directly.
1710 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1711
1712 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1713 // frame is still on the stack. Optimized code uses OSR values directly from
1714 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1715 // remaining stack slots.
1716 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1717 osr_pc_offset_ = __ pc_offset();
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001718 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdoch014dc512016-03-22 12:00:34 +00001719 }
1720
1721 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001722 if (shrink_slots > 0) {
1723 __ Subu(sp, sp, Operand(shrink_slots * kPointerSize));
Ben Murdoch014dc512016-03-22 12:00:34 +00001724 }
1725
1726 // Save callee-saved FPU registers.
1727 if (saves_fpu != 0) {
1728 __ MultiPushFPU(saves_fpu);
Ben Murdoch014dc512016-03-22 12:00:34 +00001729 }
1730
1731 const RegList saves = descriptor->CalleeSavedRegisters();
1732 if (saves != 0) {
1733 // Save callee-saved registers.
1734 __ MultiPush(saves);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001735 DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1);
Emily Bernier958fae72015-03-24 16:35:39 -04001736 }
1737}
1738
1739
1740void CodeGenerator::AssembleReturn() {
1741 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch014dc512016-03-22 12:00:34 +00001742 int pop_count = static_cast<int>(descriptor->StackParameterCount());
1743
1744 // Restore GP registers.
1745 const RegList saves = descriptor->CalleeSavedRegisters();
1746 if (saves != 0) {
1747 __ MultiPop(saves);
1748 }
1749
1750 // Restore FPU registers.
1751 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1752 if (saves_fpu != 0) {
1753 __ MultiPopFPU(saves_fpu);
1754 }
1755
1756 if (descriptor->IsCFunctionCall()) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001757 AssembleDeconstructFrame();
1758 } else if (frame_access_state()->has_frame()) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001759 // Canonicalize JSFunction return sites for now.
1760 if (return_label_.is_bound()) {
1761 __ Branch(&return_label_);
1762 return;
1763 } else {
1764 __ bind(&return_label_);
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001765 AssembleDeconstructFrame();
Emily Bernier958fae72015-03-24 16:35:39 -04001766 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001767 }
1768 if (pop_count != 0) {
Emily Bernier958fae72015-03-24 16:35:39 -04001769 __ DropAndRet(pop_count);
Ben Murdoch014dc512016-03-22 12:00:34 +00001770 } else {
1771 __ Ret();
Emily Bernier958fae72015-03-24 16:35:39 -04001772 }
1773}
1774
1775
1776void CodeGenerator::AssembleMove(InstructionOperand* source,
1777 InstructionOperand* destination) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001778 MipsOperandConverter g(this, nullptr);
Emily Bernier958fae72015-03-24 16:35:39 -04001779 // Dispatch on the source and destination operand kinds. Not all
1780 // combinations are possible.
1781 if (source->IsRegister()) {
1782 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1783 Register src = g.ToRegister(source);
1784 if (destination->IsRegister()) {
1785 __ mov(g.ToRegister(destination), src);
1786 } else {
1787 __ sw(src, g.ToMemOperand(destination));
1788 }
1789 } else if (source->IsStackSlot()) {
1790 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1791 MemOperand src = g.ToMemOperand(source);
1792 if (destination->IsRegister()) {
1793 __ lw(g.ToRegister(destination), src);
1794 } else {
1795 Register temp = kScratchReg;
1796 __ lw(temp, src);
1797 __ sw(temp, g.ToMemOperand(destination));
1798 }
1799 } else if (source->IsConstant()) {
1800 Constant src = g.ToConstant(source);
1801 if (destination->IsRegister() || destination->IsStackSlot()) {
1802 Register dst =
1803 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
1804 switch (src.type()) {
1805 case Constant::kInt32:
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001806 if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
1807 src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
1808 __ li(dst, Operand(src.ToInt32(), src.rmode()));
1809 } else {
1810 __ li(dst, Operand(src.ToInt32()));
1811 }
Emily Bernier958fae72015-03-24 16:35:39 -04001812 break;
1813 case Constant::kFloat32:
1814 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1815 break;
1816 case Constant::kInt64:
1817 UNREACHABLE();
1818 break;
1819 case Constant::kFloat64:
1820 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1821 break;
1822 case Constant::kExternalReference:
1823 __ li(dst, Operand(src.ToExternalReference()));
1824 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001825 case Constant::kHeapObject: {
1826 Handle<HeapObject> src_object = src.ToHeapObject();
1827 Heap::RootListIndex index;
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001828 int slot;
1829 if (IsMaterializableFromFrame(src_object, &slot)) {
1830 __ lw(dst, g.SlotToMemOperand(slot));
Ben Murdoch014dc512016-03-22 12:00:34 +00001831 } else if (IsMaterializableFromRoot(src_object, &index)) {
1832 __ LoadRoot(dst, index);
1833 } else {
1834 __ li(dst, src_object);
1835 }
Emily Bernier958fae72015-03-24 16:35:39 -04001836 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001837 }
Emily Bernier958fae72015-03-24 16:35:39 -04001838 case Constant::kRpoNumber:
1839 UNREACHABLE(); // TODO(titzer): loading RPO numbers on mips.
1840 break;
1841 }
1842 if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
1843 } else if (src.type() == Constant::kFloat32) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001844 if (destination->IsFPStackSlot()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001845 MemOperand dst = g.ToMemOperand(destination);
1846 __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
1847 __ sw(at, dst);
1848 } else {
1849 FloatRegister dst = g.ToSingleRegister(destination);
1850 __ Move(dst, src.ToFloat32());
1851 }
1852 } else {
1853 DCHECK_EQ(Constant::kFloat64, src.type());
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001854 DoubleRegister dst = destination->IsFPRegister()
Emily Bernier958fae72015-03-24 16:35:39 -04001855 ? g.ToDoubleRegister(destination)
1856 : kScratchDoubleReg;
1857 __ Move(dst, src.ToFloat64());
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001858 if (destination->IsFPStackSlot()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001859 __ sdc1(dst, g.ToMemOperand(destination));
1860 }
1861 }
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001862 } else if (source->IsFPRegister()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001863 FPURegister src = g.ToDoubleRegister(source);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001864 if (destination->IsFPRegister()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001865 FPURegister dst = g.ToDoubleRegister(destination);
1866 __ Move(dst, src);
1867 } else {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001868 DCHECK(destination->IsFPStackSlot());
Emily Bernier958fae72015-03-24 16:35:39 -04001869 __ sdc1(src, g.ToMemOperand(destination));
1870 }
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001871 } else if (source->IsFPStackSlot()) {
1872 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Emily Bernier958fae72015-03-24 16:35:39 -04001873 MemOperand src = g.ToMemOperand(source);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001874 if (destination->IsFPRegister()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001875 __ ldc1(g.ToDoubleRegister(destination), src);
1876 } else {
1877 FPURegister temp = kScratchDoubleReg;
1878 __ ldc1(temp, src);
1879 __ sdc1(temp, g.ToMemOperand(destination));
1880 }
1881 } else {
1882 UNREACHABLE();
1883 }
1884}
1885
1886
1887void CodeGenerator::AssembleSwap(InstructionOperand* source,
1888 InstructionOperand* destination) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001889 MipsOperandConverter g(this, nullptr);
Emily Bernier958fae72015-03-24 16:35:39 -04001890 // Dispatch on the source and destination operand kinds. Not all
1891 // combinations are possible.
1892 if (source->IsRegister()) {
1893 // Register-register.
1894 Register temp = kScratchReg;
1895 Register src = g.ToRegister(source);
1896 if (destination->IsRegister()) {
1897 Register dst = g.ToRegister(destination);
1898 __ Move(temp, src);
1899 __ Move(src, dst);
1900 __ Move(dst, temp);
1901 } else {
1902 DCHECK(destination->IsStackSlot());
1903 MemOperand dst = g.ToMemOperand(destination);
1904 __ mov(temp, src);
1905 __ lw(src, dst);
1906 __ sw(temp, dst);
1907 }
1908 } else if (source->IsStackSlot()) {
1909 DCHECK(destination->IsStackSlot());
1910 Register temp_0 = kScratchReg;
1911 Register temp_1 = kCompareReg;
1912 MemOperand src = g.ToMemOperand(source);
1913 MemOperand dst = g.ToMemOperand(destination);
1914 __ lw(temp_0, src);
1915 __ lw(temp_1, dst);
1916 __ sw(temp_0, dst);
1917 __ sw(temp_1, src);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001918 } else if (source->IsFPRegister()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001919 FPURegister temp = kScratchDoubleReg;
1920 FPURegister src = g.ToDoubleRegister(source);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001921 if (destination->IsFPRegister()) {
Emily Bernier958fae72015-03-24 16:35:39 -04001922 FPURegister dst = g.ToDoubleRegister(destination);
1923 __ Move(temp, src);
1924 __ Move(src, dst);
1925 __ Move(dst, temp);
1926 } else {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001927 DCHECK(destination->IsFPStackSlot());
Emily Bernier958fae72015-03-24 16:35:39 -04001928 MemOperand dst = g.ToMemOperand(destination);
1929 __ Move(temp, src);
1930 __ ldc1(src, dst);
1931 __ sdc1(temp, dst);
1932 }
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001933 } else if (source->IsFPStackSlot()) {
1934 DCHECK(destination->IsFPStackSlot());
Emily Bernier958fae72015-03-24 16:35:39 -04001935 Register temp_0 = kScratchReg;
1936 FPURegister temp_1 = kScratchDoubleReg;
1937 MemOperand src0 = g.ToMemOperand(source);
Ben Murdoch014dc512016-03-22 12:00:34 +00001938 MemOperand src1(src0.rm(), src0.offset() + kIntSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001939 MemOperand dst0 = g.ToMemOperand(destination);
Ben Murdoch014dc512016-03-22 12:00:34 +00001940 MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001941 __ ldc1(temp_1, dst0); // Save destination in temp_1.
1942 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination.
1943 __ sw(temp_0, dst0);
1944 __ lw(temp_0, src1);
1945 __ sw(temp_0, dst1);
1946 __ sdc1(temp_1, src0);
1947 } else {
1948 // No other combinations are possible.
1949 UNREACHABLE();
1950 }
1951}
1952
1953
Ben Murdoch014dc512016-03-22 12:00:34 +00001954void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1955 // On 32-bit MIPS we emit the jump tables inline.
1956 UNREACHABLE();
1957}
1958
1959
Emily Bernier958fae72015-03-24 16:35:39 -04001960void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch014dc512016-03-22 12:00:34 +00001961 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1962 return;
1963 }
1964
Emily Bernier958fae72015-03-24 16:35:39 -04001965 int space_needed = Deoptimizer::patch_size();
Ben Murdoch014dc512016-03-22 12:00:34 +00001966 // Ensure that we have enough space after the previous lazy-bailout
1967 // instruction for patching the code here.
1968 int current_pc = masm()->pc_offset();
1969 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1970 // Block tramoline pool emission for duration of padding.
1971 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
1972 masm());
1973 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1974 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1975 while (padding_size > 0) {
1976 __ nop();
1977 padding_size -= v8::internal::Assembler::kInstrSize;
Emily Bernier958fae72015-03-24 16:35:39 -04001978 }
1979 }
Emily Bernier958fae72015-03-24 16:35:39 -04001980}
1981
1982#undef __
1983
1984} // namespace compiler
1985} // namespace internal
1986} // namespace v8