blob: 9d4201f39430c5b57e1ee13df2f50b7c140aee5c [file] [log] [blame]
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/ast/scopes.h"
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/compiler/osr.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/mips/macro-assembler-mips.h"
Emily Bernierd0a1eb72015-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 kScratchReg2 kLithiumScratchReg2
23#define kScratchDoubleReg kLithiumScratchDouble
24
25
26// TODO(plind): consider renaming these macros.
27#define TRACE_MSG(msg) \
28 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
29 __LINE__)
30
31#define TRACE_UNIMPL() \
32 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
33 __LINE__)
34
35
36// Adds Mips-specific methods to convert InstructionOperands.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037class MipsOperandConverter final : public InstructionOperandConverter {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 public:
39 MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
40 : InstructionOperandConverter(gen, instr) {}
41
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 FloatRegister OutputSingleRegister(size_t index = 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040043 return ToSingleRegister(instr_->OutputAt(index));
44 }
45
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 FloatRegister InputSingleRegister(size_t index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047 return ToSingleRegister(instr_->InputAt(index));
48 }
49
50 FloatRegister ToSingleRegister(InstructionOperand* op) {
51 // Single (Float) and Double register namespace is same on MIPS,
52 // both are typedefs of FPURegister.
53 return ToDoubleRegister(op);
54 }
55
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056 DoubleRegister InputOrZeroDoubleRegister(size_t index) {
57 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
58
59 return InputDoubleRegister(index);
60 }
61
62 DoubleRegister InputOrZeroSingleRegister(size_t index) {
63 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
64
65 return InputSingleRegister(index);
66 }
67
68 Operand InputImmediate(size_t index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040069 Constant constant = ToConstant(instr_->InputAt(index));
70 switch (constant.type()) {
71 case Constant::kInt32:
72 return Operand(constant.ToInt32());
73 case Constant::kInt64:
74 return Operand(constant.ToInt64());
75 case Constant::kFloat32:
76 return Operand(
77 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
78 case Constant::kFloat64:
79 return Operand(
80 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
81 case Constant::kExternalReference:
82 case Constant::kHeapObject:
83 // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
84 // maybe not done on arm due to const pool ??
85 break;
86 case Constant::kRpoNumber:
87 UNREACHABLE(); // TODO(titzer): RPO immediates on mips?
88 break;
89 }
90 UNREACHABLE();
91 return Operand(zero_reg);
92 }
93
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 Operand InputOperand(size_t index) {
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000102 MemOperand MemoryOperand(size_t* first_index) {
103 const size_t index = *first_index;
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000118 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119
120 MemOperand ToMemOperand(InstructionOperand* op) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 DCHECK_NOT_NULL(op);
Ben Murdochc5610432016-08-08 18:44:38 +0100122 DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
Ben Murdochda12d292016-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 Bernierd0a1eb72015-03-24 16:35:39 -0400128 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
129 }
130};
131
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133static inline bool HasRegisterInput(Instruction* instr, size_t index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400134 return instr->InputAt(index)->IsRegister();
135}
136
137
138namespace {
139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140class OutOfLineLoadSingle final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400141 public:
142 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
143 : OutOfLineCode(gen), result_(result) {}
144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 void Generate() final {
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000154class OutOfLineLoadDouble final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400155 public:
156 OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
157 : OutOfLineCode(gen), result_(result) {}
158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 void Generate() final {
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000168class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400169 public:
170 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
171 : OutOfLineCode(gen), result_(result) {}
172
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 void Generate() final { __ mov(result_, zero_reg); }
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000185 void Generate() final {
Emily Bernierd0a1eb72015-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 __ dsrl(at, kScratchReg, 31);
189 __ dsll(at, at, 31);
190 __ mthc1(at, result_);
191 }
192
193 private:
194 DoubleRegister const result_;
195};
196
197
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198class OutOfLineRound32 : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 public:
Ben Murdoch4a90d5f2016-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 Bernierd0a1eb72015-03-24 16:35:39 -0400213};
214
215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216class OutOfLineRecordWrite final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 public:
Ben Murdoch4a90d5f2016-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 Murdochda12d292016-06-02 14:46:10 +0100227 mode_(mode),
228 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229
230 void Generate() final {
231 if (mode_ > RecordWriteMode::kValueIsPointer) {
232 __ JumpIfSmi(value_, exit());
233 }
Ben Murdoch097c5b22016-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 Murdoch4a90d5f2016-03-22 12:00:34 +0000240 SaveFPRegsMode const save_fp_mode =
241 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
Ben Murdochda12d292016-06-02 14:46:10 +0100242 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100243 // We need to save and restore ra if the frame was elided.
244 __ Push(ra);
245 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 remembered_set_action, save_fp_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 __ Daddu(scratch1_, object_, index_);
249 __ CallStub(&stub);
Ben Murdochda12d292016-06-02 14:46:10 +0100250 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100251 __ Pop(ra);
252 }
Ben Murdoch4a90d5f2016-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 Murdochda12d292016-06-02 14:46:10 +0100262 bool must_save_lr_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263};
264
265
Ben Murdoch4a90d5f2016-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}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400297
298
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000299Condition 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
313Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
314 switch (condition) {
315 case kOverflow:
316 return ne;
317 case kNotOverflow:
318 return eq;
319 default:
320 break;
321 }
322 UNREACHABLE();
323 return kNoCondition;
324}
325
326
327FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
328 FlagsCondition condition) {
329 switch (condition) {
330 case kEqual:
331 predicate = true;
332 return EQ;
333 case kNotEqual:
334 predicate = false;
335 return EQ;
336 case kUnsignedLessThan:
337 predicate = true;
338 return OLT;
339 case kUnsignedGreaterThanOrEqual:
340 predicate = false;
341 return ULT;
342 case kUnsignedLessThanOrEqual:
343 predicate = true;
344 return OLE;
345 case kUnsignedGreaterThan:
346 predicate = false;
347 return ULE;
348 case kUnorderedEqual:
349 case kUnorderedNotEqual:
350 predicate = true;
351 break;
352 default:
353 predicate = true;
354 break;
355 }
356 UNREACHABLE();
357 return kNoFPUCondition;
358}
359
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360} // namespace
361
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400362#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \
363 do { \
364 auto result = i.Output##width##Register(); \
365 auto ool = new (zone()) OutOfLineLoad##width(this, result); \
366 if (instr->InputAt(0)->IsRegister()) { \
367 auto offset = i.InputRegister(0); \
368 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdochc5610432016-08-08 18:44:38 +0100369 __ And(kScratchReg, offset, Operand(0xffffffff)); \
370 __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 } else { \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 int offset = static_cast<int>(i.InputOperand(0).immediate()); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400374 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
375 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
376 } \
377 __ bind(ool->exit()); \
378 } while (0)
379
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
381 do { \
382 auto result = i.OutputRegister(); \
383 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
384 if (instr->InputAt(0)->IsRegister()) { \
385 auto offset = i.InputRegister(0); \
386 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdochc5610432016-08-08 18:44:38 +0100387 __ And(kScratchReg, offset, Operand(0xffffffff)); \
388 __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390 } else { \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391 int offset = static_cast<int>(i.InputOperand(0).immediate()); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400392 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
393 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
394 } \
395 __ bind(ool->exit()); \
396 } while (0)
397
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400398#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
399 do { \
400 Label done; \
401 if (instr->InputAt(0)->IsRegister()) { \
402 auto offset = i.InputRegister(0); \
403 auto value = i.Input##width##Register(2); \
404 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdochc5610432016-08-08 18:44:38 +0100405 __ And(kScratchReg, offset, Operand(0xffffffff)); \
406 __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400408 } else { \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409 int offset = static_cast<int>(i.InputOperand(0).immediate()); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400410 auto value = i.Input##width##Register(2); \
411 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
412 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
413 } \
414 __ bind(&done); \
415 } while (0)
416
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
418 do { \
419 Label done; \
420 if (instr->InputAt(0)->IsRegister()) { \
421 auto offset = i.InputRegister(0); \
422 auto value = i.InputRegister(2); \
423 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdochc5610432016-08-08 18:44:38 +0100424 __ And(kScratchReg, offset, Operand(0xffffffff)); \
425 __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400427 } else { \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 int offset = static_cast<int>(i.InputOperand(0).immediate()); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400429 auto value = i.InputRegister(2); \
430 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
431 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
432 } \
433 __ bind(&done); \
434 } while (0)
435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
437 if (kArchVariant == kMips64r6) { \
438 __ cfc1(kScratchReg, FCSR); \
439 __ li(at, Operand(mode_##mode)); \
440 __ ctc1(at, FCSR); \
441 __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
442 __ ctc1(kScratchReg, FCSR); \
443 } else { \
444 auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister()); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445 Label done; \
446 __ mfhc1(kScratchReg, i.InputDoubleRegister(0)); \
447 __ Ext(at, kScratchReg, HeapNumber::kExponentShift, \
448 HeapNumber::kExponentBits); \
449 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
450 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
451 __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400453 __ dmfc1(at, i.OutputDoubleRegister()); \
454 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
455 __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
456 __ bind(ool->exit()); \
457 __ bind(&done); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 }
459
460#define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode) \
461 if (kArchVariant == kMips64r6) { \
462 __ cfc1(kScratchReg, FCSR); \
463 __ li(at, Operand(mode_##mode)); \
464 __ ctc1(at, FCSR); \
465 __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
466 __ ctc1(kScratchReg, FCSR); \
467 } else { \
468 int32_t kFloat32ExponentBias = 127; \
469 int32_t kFloat32MantissaBits = 23; \
470 int32_t kFloat32ExponentBits = 8; \
471 auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
472 Label done; \
473 __ mfc1(kScratchReg, i.InputDoubleRegister(0)); \
474 __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits); \
475 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
476 Operand(kFloat32ExponentBias + kFloat32MantissaBits)); \
477 __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
478 __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
479 __ mfc1(at, i.OutputDoubleRegister()); \
480 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
481 __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
482 __ bind(ool->exit()); \
483 __ bind(&done); \
484 }
485
Ben Murdochc5610432016-08-08 18:44:38 +0100486#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \
487 do { \
488 __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
489 __ sync(); \
490 } while (0)
491
492#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
493 do { \
494 __ sync(); \
495 __ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
496 __ sync(); \
497 } while (0)
498
Ben Murdoch61f157c2016-09-16 13:49:30 +0100499#define ASSEMBLE_IEEE754_BINOP(name) \
500 do { \
501 FrameScope scope(masm(), StackFrame::MANUAL); \
502 __ PrepareCallCFunction(0, 2, kScratchReg); \
503 __ MovToFloatParameters(i.InputDoubleRegister(0), \
504 i.InputDoubleRegister(1)); \
505 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
506 0, 2); \
507 /* Move the result in the double result register. */ \
508 __ MovFromFloatResult(i.OutputDoubleRegister()); \
509 } while (0)
510
511#define ASSEMBLE_IEEE754_UNOP(name) \
512 do { \
513 FrameScope scope(masm(), StackFrame::MANUAL); \
514 __ PrepareCallCFunction(0, 1, kScratchReg); \
515 __ MovToFloatParameter(i.InputDoubleRegister(0)); \
516 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
517 0, 1); \
518 /* Move the result in the double result register. */ \
519 __ MovFromFloatResult(i.OutputDoubleRegister()); \
520 } while (0)
521
Ben Murdochda12d292016-06-02 14:46:10 +0100522void CodeGenerator::AssembleDeconstructFrame() {
523 __ mov(sp, fp);
524 __ Pop(ra, fp);
525}
526
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
528 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
529 if (sp_slot_delta > 0) {
530 __ daddiu(sp, sp, sp_slot_delta * kPointerSize);
531 }
532 frame_access_state()->SetFrameAccessToDefault();
533}
534
535
536void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
537 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
538 if (sp_slot_delta < 0) {
539 __ Dsubu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
540 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
541 }
Ben Murdochda12d292016-06-02 14:46:10 +0100542 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 __ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
544 __ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
545 }
546 frame_access_state()->SetFrameAccessToSP();
547}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400548
Ben Murdochda12d292016-06-02 14:46:10 +0100549void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
550 Register scratch1,
551 Register scratch2,
552 Register scratch3) {
553 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
554 Label done;
555
556 // Check if current frame is an arguments adaptor frame.
557 __ ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset));
558 __ Branch(&done, ne, scratch3,
559 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
560
561 // Load arguments count from current arguments adaptor frame (note, it
562 // does not include receiver).
563 Register caller_args_count_reg = scratch1;
564 __ ld(caller_args_count_reg,
565 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
566 __ SmiUntag(caller_args_count_reg);
567
568 ParameterCount callee_args_count(args_reg);
569 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
570 scratch3);
571 __ bind(&done);
572}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400573
574// Assembles an instruction after register allocation, producing machine code.
Ben Murdochc5610432016-08-08 18:44:38 +0100575CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
576 Instruction* instr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577 MipsOperandConverter i(this, instr);
578 InstructionCode opcode = instr->opcode();
Ben Murdochda12d292016-06-02 14:46:10 +0100579 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
580 switch (arch_opcode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400581 case kArchCallCodeObject: {
582 EnsureSpaceForLazyDeopt();
583 if (instr->InputAt(0)->IsImmediate()) {
584 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
585 RelocInfo::CODE_TARGET);
586 } else {
587 __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
588 __ Call(at);
589 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 RecordCallPosition(instr);
591 frame_access_state()->ClearSPDelta();
592 break;
593 }
Ben Murdochda12d292016-06-02 14:46:10 +0100594 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000595 case kArchTailCallCodeObject: {
596 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
597 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100598 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
599 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
600 i.TempRegister(0), i.TempRegister(1),
601 i.TempRegister(2));
602 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603 if (instr->InputAt(0)->IsImmediate()) {
604 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
605 RelocInfo::CODE_TARGET);
606 } else {
607 __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
608 __ Jump(at);
609 }
610 frame_access_state()->ClearSPDelta();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400611 break;
612 }
Ben Murdochc5610432016-08-08 18:44:38 +0100613 case kArchTailCallAddress: {
614 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
615 AssembleDeconstructActivationRecord(stack_param_delta);
616 CHECK(!instr->InputAt(0)->IsImmediate());
617 __ Jump(i.InputRegister(0));
618 frame_access_state()->ClearSPDelta();
619 break;
620 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400621 case kArchCallJSFunction: {
622 EnsureSpaceForLazyDeopt();
623 Register func = i.InputRegister(0);
624 if (FLAG_debug_code) {
625 // Check the function's context matches the context argument.
626 __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
627 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
628 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
630 __ Call(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 RecordCallPosition(instr);
632 frame_access_state()->ClearSPDelta();
633 break;
634 }
Ben Murdochda12d292016-06-02 14:46:10 +0100635 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 case kArchTailCallJSFunction: {
637 Register func = i.InputRegister(0);
638 if (FLAG_debug_code) {
639 // Check the function's context matches the context argument.
640 __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
641 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
642 }
643 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
644 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100645 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
646 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
647 i.TempRegister(0), i.TempRegister(1),
648 i.TempRegister(2));
649 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
651 __ Jump(at);
652 frame_access_state()->ClearSPDelta();
653 break;
654 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000655 case kArchPrepareCallCFunction: {
656 int const num_parameters = MiscField::decode(instr->opcode());
657 __ PrepareCallCFunction(num_parameters, kScratchReg);
658 // Frame alignment requires using FP-relative frame addressing.
659 frame_access_state()->SetFrameAccessToFP();
660 break;
661 }
662 case kArchPrepareTailCall:
663 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
664 break;
665 case kArchCallCFunction: {
666 int const num_parameters = MiscField::decode(instr->opcode());
667 if (instr->InputAt(0)->IsImmediate()) {
668 ExternalReference ref = i.InputExternalReference(0);
669 __ CallCFunction(ref, num_parameters);
670 } else {
671 Register func = i.InputRegister(0);
672 __ CallCFunction(func, num_parameters);
673 }
674 frame_access_state()->SetFrameAccessToDefault();
675 frame_access_state()->ClearSPDelta();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400676 break;
677 }
678 case kArchJmp:
679 AssembleArchJump(i.InputRpo(0));
680 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 case kArchLookupSwitch:
682 AssembleArchLookupSwitch(instr);
683 break;
684 case kArchTableSwitch:
685 AssembleArchTableSwitch(instr);
686 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100687 case kArchDebugBreak:
688 __ stop("kArchDebugBreak");
689 break;
690 case kArchComment: {
691 Address comment_string = i.InputExternalReference(0).address();
692 __ RecordComment(reinterpret_cast<const char*>(comment_string));
693 break;
694 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400695 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696 case kArchThrowTerminator:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697 // don't emit code for nops.
698 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 case kArchDeoptimize: {
700 int deopt_state_id =
701 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
702 Deoptimizer::BailoutType bailout_type =
703 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochc5610432016-08-08 18:44:38 +0100704 CodeGenResult result =
705 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
706 if (result != kSuccess) return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707 break;
708 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400709 case kArchRet:
710 AssembleReturn();
711 break;
712 case kArchStackPointer:
713 __ mov(i.OutputRegister(), sp);
714 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 case kArchFramePointer:
716 __ mov(i.OutputRegister(), fp);
717 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100718 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100719 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100720 __ ld(i.OutputRegister(), MemOperand(fp, 0));
721 } else {
722 __ mov(i.OutputRegister(), fp);
723 }
724 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400725 case kArchTruncateDoubleToI:
726 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
727 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 case kArchStoreWithWriteBarrier: {
729 RecordWriteMode mode =
730 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
731 Register object = i.InputRegister(0);
732 Register index = i.InputRegister(1);
733 Register value = i.InputRegister(2);
734 Register scratch0 = i.TempRegister(0);
735 Register scratch1 = i.TempRegister(1);
736 auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
737 scratch0, scratch1, mode);
738 __ Daddu(at, object, index);
739 __ sd(value, MemOperand(at));
740 __ CheckPageFlag(object, scratch0,
741 MemoryChunk::kPointersFromHereAreInterestingMask, ne,
742 ool->entry());
743 __ bind(ool->exit());
744 break;
745 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 case kArchStackSlot: {
747 FrameOffset offset =
748 frame_access_state()->GetFrameOffset(i.InputInt32(0));
749 __ Daddu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
750 Operand(offset.offset()));
751 break;
752 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100753 case kIeee754Float64Atan:
754 ASSEMBLE_IEEE754_UNOP(atan);
755 break;
756 case kIeee754Float64Atan2:
757 ASSEMBLE_IEEE754_BINOP(atan2);
758 break;
759 case kIeee754Float64Atanh:
760 ASSEMBLE_IEEE754_UNOP(atanh);
761 break;
762 case kIeee754Float64Cos:
763 ASSEMBLE_IEEE754_UNOP(cos);
764 break;
765 case kIeee754Float64Cbrt:
766 ASSEMBLE_IEEE754_UNOP(cbrt);
767 break;
768 case kIeee754Float64Exp:
769 ASSEMBLE_IEEE754_UNOP(exp);
770 break;
771 case kIeee754Float64Expm1:
772 ASSEMBLE_IEEE754_UNOP(expm1);
773 break;
774 case kIeee754Float64Log:
775 ASSEMBLE_IEEE754_UNOP(log);
776 break;
777 case kIeee754Float64Log1p:
778 ASSEMBLE_IEEE754_UNOP(log1p);
779 break;
780 case kIeee754Float64Log2:
781 ASSEMBLE_IEEE754_UNOP(log2);
782 break;
783 case kIeee754Float64Log10:
784 ASSEMBLE_IEEE754_UNOP(log10);
785 break;
786 case kIeee754Float64Sin:
787 ASSEMBLE_IEEE754_UNOP(sin);
788 break;
789 case kIeee754Float64Tan:
790 ASSEMBLE_IEEE754_UNOP(tan);
791 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400792 case kMips64Add:
793 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
794 break;
795 case kMips64Dadd:
796 __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
797 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 case kMips64DaddOvf:
799 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
800 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400801 case kMips64Sub:
802 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
803 break;
804 case kMips64Dsub:
805 __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
806 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000807 case kMips64DsubOvf:
808 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
809 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400810 case kMips64Mul:
811 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
812 break;
813 case kMips64MulHigh:
814 __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
815 break;
816 case kMips64MulHighU:
817 __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
818 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 case kMips64DMulHigh:
820 __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
821 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822 case kMips64Div:
823 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824 if (kArchVariant == kMips64r6) {
825 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
826 } else {
827 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
828 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400829 break;
830 case kMips64DivU:
831 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 if (kArchVariant == kMips64r6) {
833 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
834 } else {
835 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
836 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400837 break;
838 case kMips64Mod:
839 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
840 break;
841 case kMips64ModU:
842 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
843 break;
844 case kMips64Dmul:
845 __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
846 break;
847 case kMips64Ddiv:
848 __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849 if (kArchVariant == kMips64r6) {
850 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
851 } else {
852 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
853 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400854 break;
855 case kMips64DdivU:
856 __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000857 if (kArchVariant == kMips64r6) {
858 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
859 } else {
860 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
861 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400862 break;
863 case kMips64Dmod:
864 __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
865 break;
866 case kMips64DmodU:
867 __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
868 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100869 case kMips64Dlsa:
870 DCHECK(instr->InputAt(2)->IsImmediate());
871 __ Dlsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
872 i.InputInt8(2));
873 break;
874 case kMips64Lsa:
875 DCHECK(instr->InputAt(2)->IsImmediate());
876 __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
877 i.InputInt8(2));
878 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400879 case kMips64And:
880 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
881 break;
882 case kMips64Or:
883 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
884 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885 case kMips64Nor:
886 if (instr->InputAt(1)->IsRegister()) {
887 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
888 } else {
889 DCHECK(i.InputOperand(1).immediate() == 0);
890 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
891 }
892 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400893 case kMips64Xor:
894 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
895 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000896 case kMips64Clz:
897 __ Clz(i.OutputRegister(), i.InputRegister(0));
898 break;
899 case kMips64Dclz:
900 __ dclz(i.OutputRegister(), i.InputRegister(0));
901 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100902 case kMips64Ctz: {
903 Register reg1 = kScratchReg;
904 Register reg2 = kScratchReg2;
905 Label skip_for_zero;
906 Label end;
907 // Branch if the operand is zero
908 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
909 // Find the number of bits before the last bit set to 1.
910 __ Subu(reg2, zero_reg, i.InputRegister(0));
911 __ And(reg2, reg2, i.InputRegister(0));
912 __ clz(reg2, reg2);
913 // Get the number of bits after the last bit set to 1.
914 __ li(reg1, 0x1F);
915 __ Subu(i.OutputRegister(), reg1, reg2);
916 __ Branch(&end);
917 __ bind(&skip_for_zero);
918 // If the operand is zero, return word length as the result.
919 __ li(i.OutputRegister(), 0x20);
920 __ bind(&end);
921 } break;
922 case kMips64Dctz: {
923 Register reg1 = kScratchReg;
924 Register reg2 = kScratchReg2;
925 Label skip_for_zero;
926 Label end;
927 // Branch if the operand is zero
928 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
929 // Find the number of bits before the last bit set to 1.
930 __ Dsubu(reg2, zero_reg, i.InputRegister(0));
931 __ And(reg2, reg2, i.InputRegister(0));
932 __ dclz(reg2, reg2);
933 // Get the number of bits after the last bit set to 1.
934 __ li(reg1, 0x3F);
935 __ Subu(i.OutputRegister(), reg1, reg2);
936 __ Branch(&end);
937 __ bind(&skip_for_zero);
938 // If the operand is zero, return word length as the result.
939 __ li(i.OutputRegister(), 0x40);
940 __ bind(&end);
941 } break;
942 case kMips64Popcnt: {
943 Register reg1 = kScratchReg;
944 Register reg2 = kScratchReg2;
945 uint32_t m1 = 0x55555555;
946 uint32_t m2 = 0x33333333;
947 uint32_t m4 = 0x0f0f0f0f;
948 uint32_t m8 = 0x00ff00ff;
949 uint32_t m16 = 0x0000ffff;
950
951 // Put count of ones in every 2 bits into those 2 bits.
952 __ li(at, m1);
953 __ dsrl(reg1, i.InputRegister(0), 1);
954 __ And(reg2, i.InputRegister(0), at);
955 __ And(reg1, reg1, at);
956 __ Daddu(reg1, reg1, reg2);
957
958 // Put count of ones in every 4 bits into those 4 bits.
959 __ li(at, m2);
960 __ dsrl(reg2, reg1, 2);
961 __ And(reg2, reg2, at);
962 __ And(reg1, reg1, at);
963 __ Daddu(reg1, reg1, reg2);
964
965 // Put count of ones in every 8 bits into those 8 bits.
966 __ li(at, m4);
967 __ dsrl(reg2, reg1, 4);
968 __ And(reg2, reg2, at);
969 __ And(reg1, reg1, at);
970 __ Daddu(reg1, reg1, reg2);
971
972 // Put count of ones in every 16 bits into those 16 bits.
973 __ li(at, m8);
974 __ dsrl(reg2, reg1, 8);
975 __ And(reg2, reg2, at);
976 __ And(reg1, reg1, at);
977 __ Daddu(reg1, reg1, reg2);
978
979 // Calculate total number of ones.
980 __ li(at, m16);
981 __ dsrl(reg2, reg1, 16);
982 __ And(reg2, reg2, at);
983 __ And(reg1, reg1, at);
984 __ Daddu(i.OutputRegister(), reg1, reg2);
985 } break;
986 case kMips64Dpopcnt: {
987 Register reg1 = kScratchReg;
988 Register reg2 = kScratchReg2;
989 uint64_t m1 = 0x5555555555555555;
990 uint64_t m2 = 0x3333333333333333;
991 uint64_t m4 = 0x0f0f0f0f0f0f0f0f;
992 uint64_t m8 = 0x00ff00ff00ff00ff;
993 uint64_t m16 = 0x0000ffff0000ffff;
994 uint64_t m32 = 0x00000000ffffffff;
995
996 // Put count of ones in every 2 bits into those 2 bits.
997 __ li(at, m1);
998 __ dsrl(reg1, i.InputRegister(0), 1);
999 __ and_(reg2, i.InputRegister(0), at);
1000 __ and_(reg1, reg1, at);
1001 __ Daddu(reg1, reg1, reg2);
1002
1003 // Put count of ones in every 4 bits into those 4 bits.
1004 __ li(at, m2);
1005 __ dsrl(reg2, reg1, 2);
1006 __ and_(reg2, reg2, at);
1007 __ and_(reg1, reg1, at);
1008 __ Daddu(reg1, reg1, reg2);
1009
1010 // Put count of ones in every 8 bits into those 8 bits.
1011 __ li(at, m4);
1012 __ dsrl(reg2, reg1, 4);
1013 __ and_(reg2, reg2, at);
1014 __ and_(reg1, reg1, at);
1015 __ Daddu(reg1, reg1, reg2);
1016
1017 // Put count of ones in every 16 bits into those 16 bits.
1018 __ li(at, m8);
1019 __ dsrl(reg2, reg1, 8);
1020 __ and_(reg2, reg2, at);
1021 __ and_(reg1, reg1, at);
1022 __ Daddu(reg1, reg1, reg2);
1023
1024 // Put count of ones in every 32 bits into those 32 bits.
1025 __ li(at, m16);
1026 __ dsrl(reg2, reg1, 16);
1027 __ and_(reg2, reg2, at);
1028 __ and_(reg1, reg1, at);
1029 __ Daddu(reg1, reg1, reg2);
1030
1031 // Calculate total number of ones.
1032 __ li(at, m32);
1033 __ dsrl32(reg2, reg1, 0);
1034 __ and_(reg2, reg2, at);
1035 __ and_(reg1, reg1, at);
1036 __ Daddu(i.OutputRegister(), reg1, reg2);
1037 } break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038 case kMips64Shl:
1039 if (instr->InputAt(1)->IsRegister()) {
1040 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1041 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001042 int64_t imm = i.InputOperand(1).immediate();
1043 __ sll(i.OutputRegister(), i.InputRegister(0),
1044 static_cast<uint16_t>(imm));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001045 }
1046 break;
1047 case kMips64Shr:
1048 if (instr->InputAt(1)->IsRegister()) {
1049 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1050 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051 int64_t imm = i.InputOperand(1).immediate();
1052 __ srl(i.OutputRegister(), i.InputRegister(0),
1053 static_cast<uint16_t>(imm));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001054 }
1055 break;
1056 case kMips64Sar:
1057 if (instr->InputAt(1)->IsRegister()) {
1058 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1059 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001060 int64_t imm = i.InputOperand(1).immediate();
1061 __ sra(i.OutputRegister(), i.InputRegister(0),
1062 static_cast<uint16_t>(imm));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001063 }
1064 break;
1065 case kMips64Ext:
1066 __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1067 i.InputInt8(2));
1068 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001069 case kMips64Ins:
1070 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1071 __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1072 } else {
1073 __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1074 i.InputInt8(2));
1075 }
1076 break;
1077 case kMips64Dext: {
1078 int16_t pos = i.InputInt8(1);
1079 int16_t size = i.InputInt8(2);
1080 if (size > 0 && size <= 32 && pos >= 0 && pos < 32) {
1081 __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1082 i.InputInt8(2));
1083 } else if (size > 32 && size <= 64 && pos > 0 && pos < 32) {
1084 __ Dextm(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1085 i.InputInt8(2));
1086 } else {
1087 DCHECK(size > 0 && size <= 32 && pos >= 32 && pos < 64);
1088 __ Dextu(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1089 i.InputInt8(2));
1090 }
1091 break;
1092 }
1093 case kMips64Dins:
1094 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1095 __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
1096 } else {
1097 __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
1098 i.InputInt8(2));
1099 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001100 break;
1101 case kMips64Dshl:
1102 if (instr->InputAt(1)->IsRegister()) {
1103 __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1104 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001105 int64_t imm = i.InputOperand(1).immediate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001106 if (imm < 32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001107 __ dsll(i.OutputRegister(), i.InputRegister(0),
1108 static_cast<uint16_t>(imm));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001109 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110 __ dsll32(i.OutputRegister(), i.InputRegister(0),
1111 static_cast<uint16_t>(imm - 32));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001112 }
1113 }
1114 break;
1115 case kMips64Dshr:
1116 if (instr->InputAt(1)->IsRegister()) {
1117 __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1118 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001119 int64_t imm = i.InputOperand(1).immediate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001120 if (imm < 32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121 __ dsrl(i.OutputRegister(), i.InputRegister(0),
1122 static_cast<uint16_t>(imm));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124 __ dsrl32(i.OutputRegister(), i.InputRegister(0),
1125 static_cast<uint16_t>(imm - 32));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001126 }
1127 }
1128 break;
1129 case kMips64Dsar:
1130 if (instr->InputAt(1)->IsRegister()) {
1131 __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1132 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133 int64_t imm = i.InputOperand(1).immediate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001134 if (imm < 32) {
1135 __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
1136 } else {
1137 __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
1138 }
1139 }
1140 break;
1141 case kMips64Ror:
1142 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1143 break;
1144 case kMips64Dror:
1145 __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1146 break;
1147 case kMips64Tst:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001148 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1149 break;
1150 case kMips64Cmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001151 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1152 break;
1153 case kMips64Mov:
1154 // TODO(plind): Should we combine mov/li like this, or use separate instr?
1155 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1156 if (HasRegisterInput(instr, 0)) {
1157 __ mov(i.OutputRegister(), i.InputRegister(0));
1158 } else {
1159 __ li(i.OutputRegister(), i.InputOperand(0));
1160 }
1161 break;
1162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 case kMips64CmpS:
1164 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
1165 break;
1166 case kMips64AddS:
1167 // TODO(plind): add special case: combine mult & add.
1168 __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1169 i.InputDoubleRegister(1));
1170 break;
1171 case kMips64SubS:
1172 __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1173 i.InputDoubleRegister(1));
1174 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001175 case kMips64SubPreserveNanS:
1176 __ SubNanPreservePayloadAndSign_s(i.OutputDoubleRegister(),
1177 i.InputDoubleRegister(0),
1178 i.InputDoubleRegister(1));
1179 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 case kMips64MulS:
1181 // TODO(plind): add special case: right op is -1.0, see arm port.
1182 __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1183 i.InputDoubleRegister(1));
1184 break;
1185 case kMips64DivS:
1186 __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1187 i.InputDoubleRegister(1));
1188 break;
1189 case kMips64ModS: {
1190 // TODO(bmeurer): We should really get rid of this special instruction,
1191 // and generate a CallAddress instruction instead.
1192 FrameScope scope(masm(), StackFrame::MANUAL);
1193 __ PrepareCallCFunction(0, 2, kScratchReg);
1194 __ MovToFloatParameters(i.InputDoubleRegister(0),
1195 i.InputDoubleRegister(1));
1196 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
1197 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1198 0, 2);
1199 // Move the result in the double result register.
1200 __ MovFromFloatResult(i.OutputSingleRegister());
1201 break;
1202 }
1203 case kMips64AbsS:
1204 __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1205 break;
1206 case kMips64SqrtS: {
1207 __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1208 break;
1209 }
1210 case kMips64MaxS:
1211 __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1212 i.InputDoubleRegister(1));
1213 break;
1214 case kMips64MinS:
1215 __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1216 i.InputDoubleRegister(1));
1217 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001218 case kMips64CmpD:
1219 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
1220 break;
1221 case kMips64AddD:
1222 // TODO(plind): add special case: combine mult & add.
1223 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1224 i.InputDoubleRegister(1));
1225 break;
1226 case kMips64SubD:
1227 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1228 i.InputDoubleRegister(1));
1229 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001230 case kMips64SubPreserveNanD:
1231 __ SubNanPreservePayloadAndSign_d(i.OutputDoubleRegister(),
1232 i.InputDoubleRegister(0),
1233 i.InputDoubleRegister(1));
1234 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001235 case kMips64MulD:
1236 // TODO(plind): add special case: right op is -1.0, see arm port.
1237 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1238 i.InputDoubleRegister(1));
1239 break;
1240 case kMips64DivD:
1241 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1242 i.InputDoubleRegister(1));
1243 break;
1244 case kMips64ModD: {
1245 // TODO(bmeurer): We should really get rid of this special instruction,
1246 // and generate a CallAddress instruction instead.
1247 FrameScope scope(masm(), StackFrame::MANUAL);
1248 __ PrepareCallCFunction(0, 2, kScratchReg);
1249 __ MovToFloatParameters(i.InputDoubleRegister(0),
1250 i.InputDoubleRegister(1));
1251 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1252 0, 2);
1253 // Move the result in the double result register.
1254 __ MovFromFloatResult(i.OutputDoubleRegister());
1255 break;
1256 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 case kMips64AbsD:
1258 __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001259 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001260 case kMips64SqrtD: {
1261 __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1262 break;
1263 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 case kMips64MaxD:
1265 __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1266 i.InputDoubleRegister(1));
1267 break;
1268 case kMips64MinD:
1269 __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1270 i.InputDoubleRegister(1));
1271 break;
1272 case kMips64Float64RoundDown: {
1273 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
1274 break;
1275 }
1276 case kMips64Float32RoundDown: {
1277 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
1278 break;
1279 }
1280 case kMips64Float64RoundTruncate: {
1281 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
1282 break;
1283 }
1284 case kMips64Float32RoundTruncate: {
1285 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
1286 break;
1287 }
1288 case kMips64Float64RoundUp: {
1289 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
1290 break;
1291 }
1292 case kMips64Float32RoundUp: {
1293 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
1294 break;
1295 }
1296 case kMips64Float64RoundTiesEven: {
1297 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
1298 break;
1299 }
1300 case kMips64Float32RoundTiesEven: {
1301 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
1302 break;
1303 }
1304 case kMips64Float64Max: {
1305 // (b < a) ? a : b
1306 if (kArchVariant == kMips64r6) {
1307 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1308 i.InputDoubleRegister(0));
1309 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1310 i.InputDoubleRegister(0));
1311 } else {
1312 __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1313 // Left operand is result, passthrough if false.
1314 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1315 }
1316 break;
1317 }
1318 case kMips64Float64Min: {
1319 // (a < b) ? a : b
1320 if (kArchVariant == kMips64r6) {
1321 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1322 i.InputDoubleRegister(1));
1323 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1324 i.InputDoubleRegister(0));
1325 } else {
1326 __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1327 // Right operand is result, passthrough if false.
1328 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1329 }
1330 break;
1331 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001332 case kMips64Float64SilenceNaN:
1333 __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1334 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001335 case kMips64Float32Max: {
1336 // (b < a) ? a : b
1337 if (kArchVariant == kMips64r6) {
1338 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1339 i.InputDoubleRegister(0));
1340 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1341 i.InputDoubleRegister(0));
1342 } else {
1343 __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1344 // Left operand is result, passthrough if false.
1345 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1346 }
1347 break;
1348 }
1349 case kMips64Float32Min: {
1350 // (a < b) ? a : b
1351 if (kArchVariant == kMips64r6) {
1352 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1353 i.InputDoubleRegister(1));
1354 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1355 i.InputDoubleRegister(0));
1356 } else {
1357 __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1358 // Right operand is result, passthrough if false.
1359 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1360 }
1361 break;
1362 }
1363 case kMips64CvtSD:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001364 __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1365 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001366 case kMips64CvtDS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001367 __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1368 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001369 case kMips64CvtDW: {
1370 FPURegister scratch = kScratchDoubleReg;
1371 __ mtc1(i.InputRegister(0), scratch);
1372 __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1373 break;
1374 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 case kMips64CvtSW: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001376 FPURegister scratch = kScratchDoubleReg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 __ mtc1(i.InputRegister(0), scratch);
1378 __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1379 break;
1380 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001381 case kMips64CvtSUw: {
1382 __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1383 break;
1384 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 case kMips64CvtSL: {
1386 FPURegister scratch = kScratchDoubleReg;
1387 __ dmtc1(i.InputRegister(0), scratch);
1388 __ cvt_s_l(i.OutputDoubleRegister(), scratch);
1389 break;
1390 }
1391 case kMips64CvtDL: {
1392 FPURegister scratch = kScratchDoubleReg;
1393 __ dmtc1(i.InputRegister(0), scratch);
1394 __ cvt_d_l(i.OutputDoubleRegister(), scratch);
1395 break;
1396 }
1397 case kMips64CvtDUw: {
1398 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1399 break;
1400 }
1401 case kMips64CvtDUl: {
1402 __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1403 break;
1404 }
1405 case kMips64CvtSUl: {
1406 __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1407 break;
1408 }
1409 case kMips64FloorWD: {
1410 FPURegister scratch = kScratchDoubleReg;
1411 __ floor_w_d(scratch, i.InputDoubleRegister(0));
1412 __ mfc1(i.OutputRegister(), scratch);
1413 break;
1414 }
1415 case kMips64CeilWD: {
1416 FPURegister scratch = kScratchDoubleReg;
1417 __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1418 __ mfc1(i.OutputRegister(), scratch);
1419 break;
1420 }
1421 case kMips64RoundWD: {
1422 FPURegister scratch = kScratchDoubleReg;
1423 __ round_w_d(scratch, i.InputDoubleRegister(0));
1424 __ mfc1(i.OutputRegister(), scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001425 break;
1426 }
1427 case kMips64TruncWD: {
1428 FPURegister scratch = kScratchDoubleReg;
1429 // Other arches use round to zero here, so we follow.
1430 __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1431 __ mfc1(i.OutputRegister(), scratch);
1432 break;
1433 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 case kMips64FloorWS: {
1435 FPURegister scratch = kScratchDoubleReg;
1436 __ floor_w_s(scratch, i.InputDoubleRegister(0));
1437 __ mfc1(i.OutputRegister(), scratch);
1438 break;
1439 }
1440 case kMips64CeilWS: {
1441 FPURegister scratch = kScratchDoubleReg;
1442 __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1443 __ mfc1(i.OutputRegister(), scratch);
1444 break;
1445 }
1446 case kMips64RoundWS: {
1447 FPURegister scratch = kScratchDoubleReg;
1448 __ round_w_s(scratch, i.InputDoubleRegister(0));
1449 __ mfc1(i.OutputRegister(), scratch);
1450 break;
1451 }
1452 case kMips64TruncWS: {
1453 FPURegister scratch = kScratchDoubleReg;
1454 __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1455 __ mfc1(i.OutputRegister(), scratch);
1456 break;
1457 }
1458 case kMips64TruncLS: {
1459 FPURegister scratch = kScratchDoubleReg;
1460 Register tmp_fcsr = kScratchReg;
1461 Register result = kScratchReg2;
1462
1463 bool load_status = instr->OutputCount() > 1;
1464 if (load_status) {
1465 // Save FCSR.
1466 __ cfc1(tmp_fcsr, FCSR);
1467 // Clear FPU flags.
1468 __ ctc1(zero_reg, FCSR);
1469 }
1470 // Other arches use round to zero here, so we follow.
1471 __ trunc_l_s(scratch, i.InputDoubleRegister(0));
1472 __ dmfc1(i.OutputRegister(), scratch);
1473 if (load_status) {
1474 __ cfc1(result, FCSR);
1475 // Check for overflow and NaNs.
1476 __ andi(result, result,
1477 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1478 __ Slt(result, zero_reg, result);
1479 __ xori(result, result, 1);
1480 __ mov(i.OutputRegister(1), result);
1481 // Restore FCSR
1482 __ ctc1(tmp_fcsr, FCSR);
1483 }
1484 break;
1485 }
1486 case kMips64TruncLD: {
1487 FPURegister scratch = kScratchDoubleReg;
1488 Register tmp_fcsr = kScratchReg;
1489 Register result = kScratchReg2;
1490
1491 bool load_status = instr->OutputCount() > 1;
1492 if (load_status) {
1493 // Save FCSR.
1494 __ cfc1(tmp_fcsr, FCSR);
1495 // Clear FPU flags.
1496 __ ctc1(zero_reg, FCSR);
1497 }
1498 // Other arches use round to zero here, so we follow.
1499 __ trunc_l_d(scratch, i.InputDoubleRegister(0));
1500 __ dmfc1(i.OutputRegister(0), scratch);
1501 if (load_status) {
1502 __ cfc1(result, FCSR);
1503 // Check for overflow and NaNs.
1504 __ andi(result, result,
1505 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
1506 __ Slt(result, zero_reg, result);
1507 __ xori(result, result, 1);
1508 __ mov(i.OutputRegister(1), result);
1509 // Restore FCSR
1510 __ ctc1(tmp_fcsr, FCSR);
1511 }
1512 break;
1513 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001514 case kMips64TruncUwD: {
1515 FPURegister scratch = kScratchDoubleReg;
1516 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1517 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1518 break;
1519 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001520 case kMips64TruncUwS: {
1521 FPURegister scratch = kScratchDoubleReg;
1522 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1523 __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1524 break;
1525 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 case kMips64TruncUlS: {
1527 FPURegister scratch = kScratchDoubleReg;
1528 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1529 // TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function.
1530 __ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch,
1531 result);
1532 break;
1533 }
1534 case kMips64TruncUlD: {
1535 FPURegister scratch = kScratchDoubleReg;
1536 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1537 // TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
1538 __ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
1539 result);
1540 break;
1541 }
1542 case kMips64BitcastDL:
1543 __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0));
1544 break;
1545 case kMips64BitcastLD:
1546 __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister());
1547 break;
1548 case kMips64Float64ExtractLowWord32:
1549 __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1550 break;
1551 case kMips64Float64ExtractHighWord32:
1552 __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1553 break;
1554 case kMips64Float64InsertLowWord32:
1555 __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1556 break;
1557 case kMips64Float64InsertHighWord32:
1558 __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1559 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001560 // ... more basic instructions ...
1561
1562 case kMips64Lbu:
1563 __ lbu(i.OutputRegister(), i.MemoryOperand());
1564 break;
1565 case kMips64Lb:
1566 __ lb(i.OutputRegister(), i.MemoryOperand());
1567 break;
1568 case kMips64Sb:
1569 __ sb(i.InputRegister(2), i.MemoryOperand());
1570 break;
1571 case kMips64Lhu:
1572 __ lhu(i.OutputRegister(), i.MemoryOperand());
1573 break;
1574 case kMips64Lh:
1575 __ lh(i.OutputRegister(), i.MemoryOperand());
1576 break;
1577 case kMips64Sh:
1578 __ sh(i.InputRegister(2), i.MemoryOperand());
1579 break;
1580 case kMips64Lw:
1581 __ lw(i.OutputRegister(), i.MemoryOperand());
1582 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001583 case kMips64Lwu:
1584 __ lwu(i.OutputRegister(), i.MemoryOperand());
1585 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001586 case kMips64Ld:
1587 __ ld(i.OutputRegister(), i.MemoryOperand());
1588 break;
1589 case kMips64Sw:
1590 __ sw(i.InputRegister(2), i.MemoryOperand());
1591 break;
1592 case kMips64Sd:
1593 __ sd(i.InputRegister(2), i.MemoryOperand());
1594 break;
1595 case kMips64Lwc1: {
1596 __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1597 break;
1598 }
1599 case kMips64Swc1: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001600 size_t index = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001601 MemOperand operand = i.MemoryOperand(&index);
1602 __ swc1(i.InputSingleRegister(index), operand);
1603 break;
1604 }
1605 case kMips64Ldc1:
1606 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1607 break;
1608 case kMips64Sdc1:
1609 __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
1610 break;
1611 case kMips64Push:
Ben Murdochc5610432016-08-08 18:44:38 +01001612 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001613 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1614 __ Subu(sp, sp, Operand(kDoubleSize));
1615 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1616 } else {
1617 __ Push(i.InputRegister(0));
1618 frame_access_state()->IncreaseSPDelta(1);
1619 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001620 break;
1621 case kMips64StackClaim: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001622 __ Dsubu(sp, sp, Operand(i.InputInt32(0)));
1623 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001624 break;
1625 }
1626 case kMips64StoreToStackSlot: {
Ben Murdochc5610432016-08-08 18:44:38 +01001627 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1629 } else {
1630 __ sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1631 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001632 break;
1633 }
1634 case kCheckedLoadInt8:
1635 ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
1636 break;
1637 case kCheckedLoadUint8:
1638 ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
1639 break;
1640 case kCheckedLoadInt16:
1641 ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
1642 break;
1643 case kCheckedLoadUint16:
1644 ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
1645 break;
1646 case kCheckedLoadWord32:
1647 ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
1648 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001649 case kCheckedLoadWord64:
1650 ASSEMBLE_CHECKED_LOAD_INTEGER(ld);
1651 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001652 case kCheckedLoadFloat32:
1653 ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
1654 break;
1655 case kCheckedLoadFloat64:
1656 ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
1657 break;
1658 case kCheckedStoreWord8:
1659 ASSEMBLE_CHECKED_STORE_INTEGER(sb);
1660 break;
1661 case kCheckedStoreWord16:
1662 ASSEMBLE_CHECKED_STORE_INTEGER(sh);
1663 break;
1664 case kCheckedStoreWord32:
1665 ASSEMBLE_CHECKED_STORE_INTEGER(sw);
1666 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 case kCheckedStoreWord64:
1668 ASSEMBLE_CHECKED_STORE_INTEGER(sd);
1669 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001670 case kCheckedStoreFloat32:
1671 ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
1672 break;
1673 case kCheckedStoreFloat64:
1674 ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
1675 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001676 case kAtomicLoadInt8:
1677 ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
1678 break;
1679 case kAtomicLoadUint8:
1680 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
1681 break;
1682 case kAtomicLoadInt16:
1683 ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
1684 break;
1685 case kAtomicLoadUint16:
1686 ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
1687 break;
1688 case kAtomicLoadWord32:
1689 ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
1690 break;
1691 case kAtomicStoreWord8:
1692 ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
1693 break;
1694 case kAtomicStoreWord16:
1695 ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
1696 break;
1697 case kAtomicStoreWord32:
1698 ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
1699 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001700 }
Ben Murdochc5610432016-08-08 18:44:38 +01001701 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702} // NOLINT(readability/fn_size)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001703
1704
1705#define UNSUPPORTED_COND(opcode, condition) \
1706 OFStream out(stdout); \
1707 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
1708 UNIMPLEMENTED();
1709
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001710static bool convertCondition(FlagsCondition condition, Condition& cc) {
1711 switch (condition) {
1712 case kEqual:
1713 cc = eq;
1714 return true;
1715 case kNotEqual:
1716 cc = ne;
1717 return true;
1718 case kUnsignedLessThan:
1719 cc = lt;
1720 return true;
1721 case kUnsignedGreaterThanOrEqual:
1722 cc = uge;
1723 return true;
1724 case kUnsignedLessThanOrEqual:
1725 cc = le;
1726 return true;
1727 case kUnsignedGreaterThan:
1728 cc = ugt;
1729 return true;
1730 default:
1731 break;
1732 }
1733 return false;
1734}
1735
1736
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001737// Assembles branches after an instruction.
1738void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1739 MipsOperandConverter i(this, instr);
1740 Label* tlabel = branch->true_label;
1741 Label* flabel = branch->false_label;
1742 Condition cc = kNoCondition;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001743 // MIPS does not have condition code flags, so compare and branch are
1744 // implemented differently than on the other arch's. The compare operations
1745 // emit mips psuedo-instructions, which are handled here by branch
1746 // instructions that do the actual comparison. Essential that the input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 // registers to compare pseudo-op are not modified before this branch op, as
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001748 // they are tested here.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001749
1750 if (instr->arch_opcode() == kMips64Tst) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 cc = FlagsConditionToConditionTst(branch->condition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001752 __ And(at, i.InputRegister(0), i.InputOperand(1));
1753 __ Branch(tlabel, cc, at, Operand(zero_reg));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001754 } else if (instr->arch_opcode() == kMips64Dadd ||
1755 instr->arch_opcode() == kMips64Dsub) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001756 cc = FlagsConditionToConditionOvf(branch->condition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001757 __ dsra32(kScratchReg, i.OutputRegister(), 0);
1758 __ sra(at, i.OutputRegister(), 31);
1759 __ Branch(tlabel, cc, at, Operand(kScratchReg));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001760 } else if (instr->arch_opcode() == kMips64DaddOvf) {
1761 switch (branch->condition) {
1762 case kOverflow:
1763 __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1764 i.InputOperand(1), tlabel, flabel);
1765 break;
1766 case kNotOverflow:
1767 __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1768 i.InputOperand(1), flabel, tlabel);
1769 break;
1770 default:
1771 UNSUPPORTED_COND(kMips64DaddOvf, branch->condition);
1772 break;
1773 }
1774 } else if (instr->arch_opcode() == kMips64DsubOvf) {
1775 switch (branch->condition) {
1776 case kOverflow:
1777 __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1778 i.InputOperand(1), tlabel, flabel);
1779 break;
1780 case kNotOverflow:
1781 __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1782 i.InputOperand(1), flabel, tlabel);
1783 break;
1784 default:
1785 UNSUPPORTED_COND(kMips64DsubOvf, branch->condition);
1786 break;
1787 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001788 } else if (instr->arch_opcode() == kMips64Cmp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001789 cc = FlagsConditionToConditionCmp(branch->condition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001790 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791 } else if (instr->arch_opcode() == kMips64CmpS) {
1792 if (!convertCondition(branch->condition, cc)) {
1793 UNSUPPORTED_COND(kMips64CmpS, branch->condition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001794 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001795 FPURegister left = i.InputOrZeroSingleRegister(0);
1796 FPURegister right = i.InputOrZeroSingleRegister(1);
1797 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1798 !__ IsDoubleZeroRegSet()) {
1799 __ Move(kDoubleRegZero, 0.0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001800 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001801 __ BranchF32(tlabel, nullptr, cc, left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001802 } else if (instr->arch_opcode() == kMips64CmpD) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001803 if (!convertCondition(branch->condition, cc)) {
1804 UNSUPPORTED_COND(kMips64CmpD, branch->condition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001805 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001806 FPURegister left = i.InputOrZeroDoubleRegister(0);
1807 FPURegister right = i.InputOrZeroDoubleRegister(1);
1808 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1809 !__ IsDoubleZeroRegSet()) {
1810 __ Move(kDoubleRegZero, 0.0);
1811 }
1812 __ BranchF64(tlabel, nullptr, cc, left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001813 } else {
1814 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
1815 instr->arch_opcode());
1816 UNIMPLEMENTED();
1817 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001819}
1820
1821
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001822void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001823 if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
1824}
1825
1826
1827// Assembles boolean materializations after an instruction.
1828void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1829 FlagsCondition condition) {
1830 MipsOperandConverter i(this, instr);
1831 Label done;
1832
1833 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1834 // last output of the instruction.
1835 Label false_value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001836 DCHECK_NE(0u, instr->OutputCount());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001837 Register result = i.OutputRegister(instr->OutputCount() - 1);
1838 Condition cc = kNoCondition;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001839 // MIPS does not have condition code flags, so compare and branch are
1840 // implemented differently than on the other arch's. The compare operations
1841 // emit mips pseudo-instructions, which are checked and handled here.
1842
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001843 if (instr->arch_opcode() == kMips64Tst) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 cc = FlagsConditionToConditionTst(condition);
1845 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1846 __ Sltu(result, zero_reg, kScratchReg);
1847 if (cc == eq) {
1848 // Sltu produces 0 for equality, invert the result.
1849 __ xori(result, result, 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001850 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001851 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001852 } else if (instr->arch_opcode() == kMips64Dadd ||
1853 instr->arch_opcode() == kMips64Dsub) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001854 cc = FlagsConditionToConditionOvf(condition);
1855 // Check for overflow creates 1 or 0 for result.
1856 __ dsrl32(kScratchReg, i.OutputRegister(), 31);
1857 __ srl(at, i.OutputRegister(), 31);
1858 __ xor_(result, kScratchReg, at);
1859 if (cc == eq) // Toggle result for not overflow.
1860 __ xori(result, result, 1);
1861 return;
1862 } else if (instr->arch_opcode() == kMips64DaddOvf ||
1863 instr->arch_opcode() == kMips64DsubOvf) {
1864 Label flabel, tlabel;
1865 switch (instr->arch_opcode()) {
1866 case kMips64DaddOvf:
1867 __ DaddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1868 i.InputOperand(1), &flabel);
1869
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001870 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001871 case kMips64DsubOvf:
1872 __ DsubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1873 i.InputOperand(1), &flabel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001874 break;
1875 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001877 break;
1878 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001879 __ li(result, 1);
1880 __ Branch(&tlabel);
1881 __ bind(&flabel);
1882 __ li(result, 0);
1883 __ bind(&tlabel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001884 } else if (instr->arch_opcode() == kMips64Cmp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001885 cc = FlagsConditionToConditionCmp(condition);
1886 switch (cc) {
1887 case eq:
1888 case ne: {
1889 Register left = i.InputRegister(0);
1890 Operand right = i.InputOperand(1);
1891 Register select;
1892 if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) {
1893 // Pass left operand if right is zero.
1894 select = left;
1895 } else {
1896 __ Dsubu(kScratchReg, left, right);
1897 select = kScratchReg;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001898 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 __ Sltu(result, zero_reg, select);
1900 if (cc == eq) {
1901 // Sltu produces 0 for equality, invert the result.
1902 __ xori(result, result, 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001903 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001904 } break;
1905 case lt:
1906 case ge: {
1907 Register left = i.InputRegister(0);
1908 Operand right = i.InputOperand(1);
1909 __ Slt(result, left, right);
1910 if (cc == ge) {
1911 __ xori(result, result, 1);
1912 }
1913 } break;
1914 case gt:
1915 case le: {
1916 Register left = i.InputRegister(1);
1917 Operand right = i.InputOperand(0);
1918 __ Slt(result, left, right);
1919 if (cc == le) {
1920 __ xori(result, result, 1);
1921 }
1922 } break;
1923 case lo:
1924 case hs: {
1925 Register left = i.InputRegister(0);
1926 Operand right = i.InputOperand(1);
1927 __ Sltu(result, left, right);
1928 if (cc == hs) {
1929 __ xori(result, result, 1);
1930 }
1931 } break;
1932 case hi:
1933 case ls: {
1934 Register left = i.InputRegister(1);
1935 Operand right = i.InputOperand(0);
1936 __ Sltu(result, left, right);
1937 if (cc == ls) {
1938 __ xori(result, result, 1);
1939 }
1940 } break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001941 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001942 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001943 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944 return;
1945 } else if (instr->arch_opcode() == kMips64CmpD ||
1946 instr->arch_opcode() == kMips64CmpS) {
1947 FPURegister left = i.InputOrZeroDoubleRegister(0);
1948 FPURegister right = i.InputOrZeroDoubleRegister(1);
1949 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1950 !__ IsDoubleZeroRegSet()) {
1951 __ Move(kDoubleRegZero, 0.0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001952 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001953 bool predicate;
1954 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
1955 if (kArchVariant != kMips64r6) {
1956 __ li(result, Operand(1));
1957 if (instr->arch_opcode() == kMips64CmpD) {
1958 __ c(cc, D, left, right);
1959 } else {
1960 DCHECK(instr->arch_opcode() == kMips64CmpS);
1961 __ c(cc, S, left, right);
1962 }
1963 if (predicate) {
1964 __ Movf(result, zero_reg);
1965 } else {
1966 __ Movt(result, zero_reg);
1967 }
1968 } else {
1969 if (instr->arch_opcode() == kMips64CmpD) {
1970 __ cmp(cc, L, kDoubleCompareReg, left, right);
1971 } else {
1972 DCHECK(instr->arch_opcode() == kMips64CmpS);
1973 __ cmp(cc, W, kDoubleCompareReg, left, right);
1974 }
1975 __ dmfc1(result, kDoubleCompareReg);
1976 __ andi(result, result, 1); // Cmp returns all 1's/0's, use only LSB.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001977
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001978 if (!predicate) // Toggle result for not equal.
1979 __ xori(result, result, 1);
1980 }
1981 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001982 } else {
1983 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
1984 instr->arch_opcode());
1985 TRACE_UNIMPL();
1986 UNIMPLEMENTED();
1987 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001988}
1989
1990
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001991void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1992 MipsOperandConverter i(this, instr);
1993 Register input = i.InputRegister(0);
1994 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1995 __ li(at, Operand(i.InputInt32(index + 0)));
1996 __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
1997 }
1998 __ nop(); // Branch delay slot of the last beq.
1999 AssembleArchJump(i.InputRpo(1));
2000}
2001
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002002void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2003 MipsOperandConverter i(this, instr);
2004 Register input = i.InputRegister(0);
2005 size_t const case_count = instr->InputCount() - 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002006
2007 __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002008 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
2009 return GetLabel(i.InputRpo(index + 2));
2010 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002011}
2012
Ben Murdochc5610432016-08-08 18:44:38 +01002013CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002014 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002015 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002016 isolate(), deoptimization_id, bailout_type);
Ben Murdochc5610432016-08-08 18:44:38 +01002017 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002018 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochc5610432016-08-08 18:44:38 +01002019 return kSuccess;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002020}
2021
Ben Murdochc5610432016-08-08 18:44:38 +01002022void CodeGenerator::FinishFrame(Frame* frame) {
2023 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002024
Ben Murdochc5610432016-08-08 18:44:38 +01002025 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2026 if (saves_fpu != 0) {
2027 int count = base::bits::CountPopulation32(saves_fpu);
2028 DCHECK(kNumCalleeSavedFPU == count);
2029 frame->AllocateSavedCalleeRegisterSlots(count *
2030 (kDoubleSize / kPointerSize));
2031 }
2032
2033 const RegList saves = descriptor->CalleeSavedRegisters();
2034 if (saves != 0) {
2035 int count = base::bits::CountPopulation32(saves);
2036 DCHECK(kNumCalleeSaved == count + 1);
2037 frame->AllocateSavedCalleeRegisterSlots(count);
2038 }
2039}
2040
2041void CodeGenerator::AssembleConstructFrame() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002042 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01002043 if (frame_access_state()->has_frame()) {
2044 if (descriptor->IsCFunctionCall()) {
2045 __ Push(ra, fp);
2046 __ mov(fp, sp);
2047 } else if (descriptor->IsJSFunctionCall()) {
2048 __ Prologue(this->info()->GeneratePreagedPrologue());
2049 } else {
2050 __ StubPrologue(info()->GetOutputStackFrameType());
2051 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002052 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002053
Ben Murdochc5610432016-08-08 18:44:38 +01002054 int shrink_slots = frame()->GetSpillSlotCount();
2055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002056 if (info()->is_osr()) {
2057 // TurboFan OSR-compiled functions cannot be entered directly.
2058 __ Abort(kShouldNotDirectlyEnterOsrFunction);
2059
2060 // Unoptimized code jumps directly to this entrypoint while the unoptimized
2061 // frame is still on the stack. Optimized code uses OSR values directly from
2062 // the unoptimized frame. Thus, all that needs to be done is to allocate the
2063 // remaining stack slots.
2064 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2065 osr_pc_offset_ = __ pc_offset();
Ben Murdochc5610432016-08-08 18:44:38 +01002066 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 }
2068
Ben Murdochc5610432016-08-08 18:44:38 +01002069 if (shrink_slots > 0) {
2070 __ Dsubu(sp, sp, Operand(shrink_slots * kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002071 }
2072
2073 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2074 if (saves_fpu != 0) {
2075 // Save callee-saved FPU registers.
2076 __ MultiPushFPU(saves_fpu);
Ben Murdochc5610432016-08-08 18:44:38 +01002077 DCHECK(kNumCalleeSavedFPU == base::bits::CountPopulation32(saves_fpu));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002078 }
2079
2080 const RegList saves = descriptor->CalleeSavedRegisters();
2081 if (saves != 0) {
2082 // Save callee-saved registers.
2083 __ MultiPush(saves);
Ben Murdochc5610432016-08-08 18:44:38 +01002084 DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002085 }
2086}
2087
2088
2089void CodeGenerator::AssembleReturn() {
2090 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002091
2092 // Restore GP registers.
2093 const RegList saves = descriptor->CalleeSavedRegisters();
2094 if (saves != 0) {
2095 __ MultiPop(saves);
2096 }
2097
2098 // Restore FPU registers.
2099 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
2100 if (saves_fpu != 0) {
2101 __ MultiPopFPU(saves_fpu);
2102 }
2103
2104 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002105 AssembleDeconstructFrame();
2106 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002107 // Canonicalize JSFunction return sites for now.
2108 if (return_label_.is_bound()) {
2109 __ Branch(&return_label_);
2110 return;
2111 } else {
2112 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01002113 AssembleDeconstructFrame();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002114 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002115 }
2116 int pop_count = static_cast<int>(descriptor->StackParameterCount());
2117 if (pop_count != 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002118 __ DropAndRet(pop_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002119 } else {
2120 __ Ret();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002121 }
2122}
2123
2124
2125void CodeGenerator::AssembleMove(InstructionOperand* source,
2126 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002127 MipsOperandConverter g(this, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002128 // Dispatch on the source and destination operand kinds. Not all
2129 // combinations are possible.
2130 if (source->IsRegister()) {
2131 DCHECK(destination->IsRegister() || destination->IsStackSlot());
2132 Register src = g.ToRegister(source);
2133 if (destination->IsRegister()) {
2134 __ mov(g.ToRegister(destination), src);
2135 } else {
2136 __ sd(src, g.ToMemOperand(destination));
2137 }
2138 } else if (source->IsStackSlot()) {
2139 DCHECK(destination->IsRegister() || destination->IsStackSlot());
2140 MemOperand src = g.ToMemOperand(source);
2141 if (destination->IsRegister()) {
2142 __ ld(g.ToRegister(destination), src);
2143 } else {
2144 Register temp = kScratchReg;
2145 __ ld(temp, src);
2146 __ sd(temp, g.ToMemOperand(destination));
2147 }
2148 } else if (source->IsConstant()) {
2149 Constant src = g.ToConstant(source);
2150 if (destination->IsRegister() || destination->IsStackSlot()) {
2151 Register dst =
2152 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
2153 switch (src.type()) {
2154 case Constant::kInt32:
Ben Murdochc5610432016-08-08 18:44:38 +01002155 if (src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
2156 __ li(dst, Operand(src.ToInt32(), src.rmode()));
2157 } else {
2158 __ li(dst, Operand(src.ToInt32()));
2159 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002160 break;
2161 case Constant::kFloat32:
2162 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
2163 break;
2164 case Constant::kInt64:
Ben Murdoch61f157c2016-09-16 13:49:30 +01002165 if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
2166 src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
Ben Murdochc5610432016-08-08 18:44:38 +01002167 __ li(dst, Operand(src.ToInt64(), src.rmode()));
2168 } else {
2169 DCHECK(src.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
2170 __ li(dst, Operand(src.ToInt64()));
2171 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002172 break;
2173 case Constant::kFloat64:
2174 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
2175 break;
2176 case Constant::kExternalReference:
2177 __ li(dst, Operand(src.ToExternalReference()));
2178 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002179 case Constant::kHeapObject: {
2180 Handle<HeapObject> src_object = src.ToHeapObject();
2181 Heap::RootListIndex index;
Ben Murdochda12d292016-06-02 14:46:10 +01002182 int slot;
2183 if (IsMaterializableFromFrame(src_object, &slot)) {
2184 __ ld(dst, g.SlotToMemOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002185 } else if (IsMaterializableFromRoot(src_object, &index)) {
2186 __ LoadRoot(dst, index);
2187 } else {
2188 __ li(dst, src_object);
2189 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002190 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002191 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002192 case Constant::kRpoNumber:
2193 UNREACHABLE(); // TODO(titzer): loading RPO numbers on mips64.
2194 break;
2195 }
2196 if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
2197 } else if (src.type() == Constant::kFloat32) {
Ben Murdochc5610432016-08-08 18:44:38 +01002198 if (destination->IsFPStackSlot()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002199 MemOperand dst = g.ToMemOperand(destination);
2200 __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
2201 __ sw(at, dst);
2202 } else {
2203 FloatRegister dst = g.ToSingleRegister(destination);
2204 __ Move(dst, src.ToFloat32());
2205 }
2206 } else {
2207 DCHECK_EQ(Constant::kFloat64, src.type());
Ben Murdochc5610432016-08-08 18:44:38 +01002208 DoubleRegister dst = destination->IsFPRegister()
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002209 ? g.ToDoubleRegister(destination)
2210 : kScratchDoubleReg;
2211 __ Move(dst, src.ToFloat64());
Ben Murdochc5610432016-08-08 18:44:38 +01002212 if (destination->IsFPStackSlot()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002213 __ sdc1(dst, g.ToMemOperand(destination));
2214 }
2215 }
Ben Murdochc5610432016-08-08 18:44:38 +01002216 } else if (source->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002217 FPURegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01002218 if (destination->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002219 FPURegister dst = g.ToDoubleRegister(destination);
2220 __ Move(dst, src);
2221 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002222 DCHECK(destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002223 __ sdc1(src, g.ToMemOperand(destination));
2224 }
Ben Murdochc5610432016-08-08 18:44:38 +01002225 } else if (source->IsFPStackSlot()) {
2226 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002227 MemOperand src = g.ToMemOperand(source);
Ben Murdochc5610432016-08-08 18:44:38 +01002228 if (destination->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002229 __ ldc1(g.ToDoubleRegister(destination), src);
2230 } else {
2231 FPURegister temp = kScratchDoubleReg;
2232 __ ldc1(temp, src);
2233 __ sdc1(temp, g.ToMemOperand(destination));
2234 }
2235 } else {
2236 UNREACHABLE();
2237 }
2238}
2239
2240
2241void CodeGenerator::AssembleSwap(InstructionOperand* source,
2242 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002243 MipsOperandConverter g(this, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002244 // Dispatch on the source and destination operand kinds. Not all
2245 // combinations are possible.
2246 if (source->IsRegister()) {
2247 // Register-register.
2248 Register temp = kScratchReg;
2249 Register src = g.ToRegister(source);
2250 if (destination->IsRegister()) {
2251 Register dst = g.ToRegister(destination);
2252 __ Move(temp, src);
2253 __ Move(src, dst);
2254 __ Move(dst, temp);
2255 } else {
2256 DCHECK(destination->IsStackSlot());
2257 MemOperand dst = g.ToMemOperand(destination);
2258 __ mov(temp, src);
2259 __ ld(src, dst);
2260 __ sd(temp, dst);
2261 }
2262 } else if (source->IsStackSlot()) {
2263 DCHECK(destination->IsStackSlot());
2264 Register temp_0 = kScratchReg;
2265 Register temp_1 = kScratchReg2;
2266 MemOperand src = g.ToMemOperand(source);
2267 MemOperand dst = g.ToMemOperand(destination);
2268 __ ld(temp_0, src);
2269 __ ld(temp_1, dst);
2270 __ sd(temp_0, dst);
2271 __ sd(temp_1, src);
Ben Murdochc5610432016-08-08 18:44:38 +01002272 } else if (source->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002273 FPURegister temp = kScratchDoubleReg;
2274 FPURegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01002275 if (destination->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002276 FPURegister dst = g.ToDoubleRegister(destination);
2277 __ Move(temp, src);
2278 __ Move(src, dst);
2279 __ Move(dst, temp);
2280 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002281 DCHECK(destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002282 MemOperand dst = g.ToMemOperand(destination);
2283 __ Move(temp, src);
2284 __ ldc1(src, dst);
2285 __ sdc1(temp, dst);
2286 }
Ben Murdochc5610432016-08-08 18:44:38 +01002287 } else if (source->IsFPStackSlot()) {
2288 DCHECK(destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002289 Register temp_0 = kScratchReg;
2290 FPURegister temp_1 = kScratchDoubleReg;
2291 MemOperand src0 = g.ToMemOperand(source);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002292 MemOperand src1(src0.rm(), src0.offset() + kIntSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002293 MemOperand dst0 = g.ToMemOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002294 MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002295 __ ldc1(temp_1, dst0); // Save destination in temp_1.
2296 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination.
2297 __ sw(temp_0, dst0);
2298 __ lw(temp_0, src1);
2299 __ sw(temp_0, dst1);
2300 __ sdc1(temp_1, src0);
2301 } else {
2302 // No other combinations are possible.
2303 UNREACHABLE();
2304 }
2305}
2306
2307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002308void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2309 // On 64-bit MIPS we emit the jump tables inline.
2310 UNREACHABLE();
2311}
2312
2313
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002314void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002315 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2316 return;
2317 }
2318
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002319 int space_needed = Deoptimizer::patch_size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002320 // Ensure that we have enough space after the previous lazy-bailout
2321 // instruction for patching the code here.
2322 int current_pc = masm()->pc_offset();
2323 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2324 // Block tramoline pool emission for duration of padding.
2325 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
2326 masm());
2327 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2328 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
2329 while (padding_size > 0) {
2330 __ nop();
2331 padding_size -= v8::internal::Assembler::kInstrSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002332 }
2333 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002334}
2335
2336#undef __
2337
2338} // namespace compiler
2339} // namespace internal
2340} // namespace v8