blob: 9b0d706327e95a20528b22c0ed8c4ebba32ebb50 [file] [log] [blame]
Emily Bernier958fae72015-03-24 16:35:39 -04001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdoch014dc512016-03-22 12:00:34 +00005#include "src/ast/scopes.h"
Emily Bernier958fae72015-03-24 16:35:39 -04006#include "src/compiler/code-generator.h"
7#include "src/compiler/code-generator-impl.h"
8#include "src/compiler/gap-resolver.h"
9#include "src/compiler/node-matchers.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000010#include "src/compiler/osr.h"
Emily Bernier958fae72015-03-24 16:35:39 -040011#include "src/mips/macro-assembler-mips.h"
Emily Bernier958fae72015-03-24 16:35:39 -040012
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17#define __ masm()->
18
19
20// TODO(plind): Possibly avoid using these lithium names.
21#define kScratchReg kLithiumScratchReg
22#define kCompareReg kLithiumScratchReg2
23#define kScratchReg2 kLithiumScratchReg2
24#define kScratchDoubleReg kLithiumScratchDouble
25
26
27// TODO(plind): consider renaming these macros.
28#define TRACE_MSG(msg) \
29 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
30 __LINE__)
31
32#define TRACE_UNIMPL() \
33 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
34 __LINE__)
35
36
37// Adds Mips-specific methods to convert InstructionOperands.
Ben Murdoch014dc512016-03-22 12:00:34 +000038class MipsOperandConverter final : public InstructionOperandConverter {
Emily Bernier958fae72015-03-24 16:35:39 -040039 public:
40 MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
41 : InstructionOperandConverter(gen, instr) {}
42
Ben Murdoch014dc512016-03-22 12:00:34 +000043 FloatRegister OutputSingleRegister(size_t index = 0) {
Emily Bernier958fae72015-03-24 16:35:39 -040044 return ToSingleRegister(instr_->OutputAt(index));
45 }
46
Ben Murdoch014dc512016-03-22 12:00:34 +000047 FloatRegister InputSingleRegister(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040048 return ToSingleRegister(instr_->InputAt(index));
49 }
50
51 FloatRegister ToSingleRegister(InstructionOperand* op) {
52 // Single (Float) and Double register namespace is same on MIPS,
53 // both are typedefs of FPURegister.
54 return ToDoubleRegister(op);
55 }
56
Ben Murdoch014dc512016-03-22 12:00:34 +000057 DoubleRegister InputOrZeroDoubleRegister(size_t index) {
58 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
59
60 return InputDoubleRegister(index);
61 }
62
63 DoubleRegister InputOrZeroSingleRegister(size_t index) {
64 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
65
66 return InputSingleRegister(index);
67 }
68
69 Operand InputImmediate(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040070 Constant constant = ToConstant(instr_->InputAt(index));
71 switch (constant.type()) {
72 case Constant::kInt32:
73 return Operand(constant.ToInt32());
74 case Constant::kFloat32:
75 return Operand(
76 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
77 case Constant::kFloat64:
78 return Operand(
79 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
80 case Constant::kInt64:
81 case Constant::kExternalReference:
82 case Constant::kHeapObject:
83 // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
84 // maybe not done on arm due to const pool ??
85 break;
86 case Constant::kRpoNumber:
87 UNREACHABLE(); // TODO(titzer): RPO immediates on mips?
88 break;
89 }
90 UNREACHABLE();
91 return Operand(zero_reg);
92 }
93
Ben Murdoch014dc512016-03-22 12:00:34 +000094 Operand InputOperand(size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -040095 InstructionOperand* op = instr_->InputAt(index);
96 if (op->IsRegister()) {
97 return Operand(ToRegister(op));
98 }
99 return InputImmediate(index);
100 }
101
Ben Murdoch014dc512016-03-22 12:00:34 +0000102 MemOperand MemoryOperand(size_t* first_index) {
103 const size_t index = *first_index;
Emily Bernier958fae72015-03-24 16:35:39 -0400104 switch (AddressingModeField::decode(instr_->opcode())) {
105 case kMode_None:
106 break;
107 case kMode_MRI:
108 *first_index += 2;
109 return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
110 case kMode_MRR:
111 // TODO(plind): r6 address mode, to be implemented ...
112 UNREACHABLE();
113 }
114 UNREACHABLE();
115 return MemOperand(no_reg);
116 }
117
Ben Murdoch014dc512016-03-22 12:00:34 +0000118 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
Emily Bernier958fae72015-03-24 16:35:39 -0400119
120 MemOperand ToMemOperand(InstructionOperand* op) const {
Ben Murdoch014dc512016-03-22 12:00:34 +0000121 DCHECK_NOT_NULL(op);
Emily Bernier958fae72015-03-24 16:35:39 -0400122 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100123 return SlotToMemOperand(AllocatedOperand::cast(op)->index());
124 }
125
126 MemOperand SlotToMemOperand(int slot) const {
127 FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
Emily Bernier958fae72015-03-24 16:35:39 -0400128 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
129 }
130};
131
132
Ben Murdoch014dc512016-03-22 12:00:34 +0000133static inline bool HasRegisterInput(Instruction* instr, size_t index) {
Emily Bernier958fae72015-03-24 16:35:39 -0400134 return instr->InputAt(index)->IsRegister();
135}
136
137
138namespace {
139
Ben Murdoch014dc512016-03-22 12:00:34 +0000140class OutOfLineLoadSingle final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400141 public:
142 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
143 : OutOfLineCode(gen), result_(result) {}
144
Ben Murdoch014dc512016-03-22 12:00:34 +0000145 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400146 __ Move(result_, std::numeric_limits<float>::quiet_NaN());
147 }
148
149 private:
150 FloatRegister const result_;
151};
152
153
Ben Murdoch014dc512016-03-22 12:00:34 +0000154class OutOfLineLoadDouble final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400155 public:
156 OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
157 : OutOfLineCode(gen), result_(result) {}
158
Ben Murdoch014dc512016-03-22 12:00:34 +0000159 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400160 __ Move(result_, std::numeric_limits<double>::quiet_NaN());
161 }
162
163 private:
164 DoubleRegister const result_;
165};
166
167
Ben Murdoch014dc512016-03-22 12:00:34 +0000168class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400169 public:
170 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
171 : OutOfLineCode(gen), result_(result) {}
172
Ben Murdoch014dc512016-03-22 12:00:34 +0000173 void Generate() final { __ mov(result_, zero_reg); }
Emily Bernier958fae72015-03-24 16:35:39 -0400174
175 private:
176 Register const result_;
177};
178
179
180class OutOfLineRound : public OutOfLineCode {
181 public:
182 OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
183 : OutOfLineCode(gen), result_(result) {}
184
Ben Murdoch014dc512016-03-22 12:00:34 +0000185 void Generate() final {
Emily Bernier958fae72015-03-24 16:35:39 -0400186 // Handle rounding to zero case where sign has to be preserved.
187 // High bits of double input already in kScratchReg.
188 __ srl(at, kScratchReg, 31);
189 __ sll(at, at, 31);
190 __ Mthc1(at, result_);
191 }
192
193 private:
194 DoubleRegister const result_;
195};
196
197
Ben Murdoch014dc512016-03-22 12:00:34 +0000198class OutOfLineRound32 : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400199 public:
Ben Murdoch014dc512016-03-22 12:00:34 +0000200 OutOfLineRound32(CodeGenerator* gen, DoubleRegister result)
201 : OutOfLineCode(gen), result_(result) {}
202
203 void Generate() final {
204 // Handle rounding to zero case where sign has to be preserved.
205 // High bits of float input already in kScratchReg.
206 __ srl(at, kScratchReg, 31);
207 __ sll(at, at, 31);
208 __ mtc1(at, result_);
209 }
210
211 private:
212 DoubleRegister const result_;
Emily Bernier958fae72015-03-24 16:35:39 -0400213};
214
215
Ben Murdoch014dc512016-03-22 12:00:34 +0000216class OutOfLineRecordWrite final : public OutOfLineCode {
Emily Bernier958fae72015-03-24 16:35:39 -0400217 public:
Ben Murdoch014dc512016-03-22 12:00:34 +0000218 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
219 Register value, Register scratch0, Register scratch1,
220 RecordWriteMode mode)
221 : OutOfLineCode(gen),
222 object_(object),
223 index_(index),
224 value_(value),
225 scratch0_(scratch0),
226 scratch1_(scratch1),
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100227 mode_(mode),
228 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch014dc512016-03-22 12:00:34 +0000229
230 void Generate() final {
231 if (mode_ > RecordWriteMode::kValueIsPointer) {
232 __ JumpIfSmi(value_, exit());
233 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100234 __ CheckPageFlag(value_, scratch0_,
235 MemoryChunk::kPointersToHereAreInterestingMask, eq,
236 exit());
237 RememberedSetAction const remembered_set_action =
238 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
239 : OMIT_REMEMBERED_SET;
Ben Murdoch014dc512016-03-22 12:00:34 +0000240 SaveFPRegsMode const save_fp_mode =
241 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100242 if (must_save_lr_) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100243 // We need to save and restore ra if the frame was elided.
244 __ Push(ra);
245 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000246 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch109988c2016-05-18 11:27:45 +0100247 remembered_set_action, save_fp_mode);
Ben Murdoch014dc512016-03-22 12:00:34 +0000248 __ Addu(scratch1_, object_, index_);
249 __ CallStub(&stub);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100250 if (must_save_lr_) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100251 __ Pop(ra);
252 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000253 }
254
255 private:
256 Register const object_;
257 Register const index_;
258 Register const value_;
259 Register const scratch0_;
260 Register const scratch1_;
261 RecordWriteMode const mode_;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100262 bool must_save_lr_;
Emily Bernier958fae72015-03-24 16:35:39 -0400263};
264
265
Ben Murdoch014dc512016-03-22 12:00:34 +0000266Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
267 switch (condition) {
268 case kEqual:
269 return eq;
270 case kNotEqual:
271 return ne;
272 case kSignedLessThan:
273 return lt;
274 case kSignedGreaterThanOrEqual:
275 return ge;
276 case kSignedLessThanOrEqual:
277 return le;
278 case kSignedGreaterThan:
279 return gt;
280 case kUnsignedLessThan:
281 return lo;
282 case kUnsignedGreaterThanOrEqual:
283 return hs;
284 case kUnsignedLessThanOrEqual:
285 return ls;
286 case kUnsignedGreaterThan:
287 return hi;
288 case kUnorderedEqual:
289 case kUnorderedNotEqual:
290 break;
291 default:
292 break;
293 }
294 UNREACHABLE();
295 return kNoCondition;
296}
297
298
299Condition FlagsConditionToConditionTst(FlagsCondition condition) {
300 switch (condition) {
301 case kNotEqual:
302 return ne;
303 case kEqual:
304 return eq;
305 default:
306 break;
307 }
308 UNREACHABLE();
309 return kNoCondition;
310}
311
312
313FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
314 FlagsCondition condition) {
315 switch (condition) {
316 case kEqual:
317 predicate = true;
318 return EQ;
319 case kNotEqual:
320 predicate = false;
321 return EQ;
322 case kUnsignedLessThan:
323 predicate = true;
324 return OLT;
325 case kUnsignedGreaterThanOrEqual:
326 predicate = false;
327 return ULT;
328 case kUnsignedLessThanOrEqual:
329 predicate = true;
330 return OLE;
331 case kUnsignedGreaterThan:
332 predicate = false;
333 return ULE;
334 case kUnorderedEqual:
335 case kUnorderedNotEqual:
336 predicate = true;
337 break;
338 default:
339 predicate = true;
340 break;
341 }
342 UNREACHABLE();
343 return kNoFPUCondition;
344}
Emily Bernier958fae72015-03-24 16:35:39 -0400345
346} // namespace
347
348
349#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \
350 do { \
351 auto result = i.Output##width##Register(); \
352 auto ool = new (zone()) OutOfLineLoad##width(this, result); \
353 if (instr->InputAt(0)->IsRegister()) { \
354 auto offset = i.InputRegister(0); \
355 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000356 __ addu(kScratchReg, i.InputRegister(2), offset); \
357 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400358 } else { \
359 auto offset = i.InputOperand(0).immediate(); \
360 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
361 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
362 } \
363 __ bind(ool->exit()); \
364 } while (0)
365
366
367#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
368 do { \
369 auto result = i.OutputRegister(); \
370 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
371 if (instr->InputAt(0)->IsRegister()) { \
372 auto offset = i.InputRegister(0); \
373 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000374 __ addu(kScratchReg, i.InputRegister(2), offset); \
375 __ asm_instr(result, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400376 } else { \
377 auto offset = i.InputOperand(0).immediate(); \
378 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \
379 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \
380 } \
381 __ bind(ool->exit()); \
382 } while (0)
383
384
385#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
386 do { \
387 Label done; \
388 if (instr->InputAt(0)->IsRegister()) { \
389 auto offset = i.InputRegister(0); \
390 auto value = i.Input##width##Register(2); \
391 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000392 __ addu(kScratchReg, i.InputRegister(3), offset); \
393 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400394 } else { \
395 auto offset = i.InputOperand(0).immediate(); \
396 auto value = i.Input##width##Register(2); \
397 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
398 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
399 } \
400 __ bind(&done); \
401 } while (0)
402
403
404#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
405 do { \
406 Label done; \
407 if (instr->InputAt(0)->IsRegister()) { \
408 auto offset = i.InputRegister(0); \
409 auto value = i.InputRegister(2); \
410 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000411 __ addu(kScratchReg, i.InputRegister(3), offset); \
412 __ asm_instr(value, MemOperand(kScratchReg, 0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400413 } else { \
414 auto offset = i.InputOperand(0).immediate(); \
415 auto value = i.InputRegister(2); \
416 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
417 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
418 } \
419 __ bind(&done); \
420 } while (0)
421
422
Ben Murdoch014dc512016-03-22 12:00:34 +0000423#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
424 if (IsMipsArchVariant(kMips32r6)) { \
425 __ cfc1(kScratchReg, FCSR); \
426 __ li(at, Operand(mode_##mode)); \
427 __ ctc1(at, FCSR); \
428 __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
429 __ ctc1(kScratchReg, FCSR); \
430 } else { \
431 auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister()); \
Emily Bernier958fae72015-03-24 16:35:39 -0400432 Label done; \
433 __ Mfhc1(kScratchReg, i.InputDoubleRegister(0)); \
434 __ Ext(at, kScratchReg, HeapNumber::kExponentShift, \
435 HeapNumber::kExponentBits); \
436 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
437 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
438 __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000439 __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
Emily Bernier958fae72015-03-24 16:35:39 -0400440 __ Move(at, kScratchReg2, i.OutputDoubleRegister()); \
441 __ or_(at, at, kScratchReg2); \
442 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
443 __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
444 __ bind(ool->exit()); \
445 __ bind(&done); \
Ben Murdoch014dc512016-03-22 12:00:34 +0000446 }
447
448
449#define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode) \
450 if (IsMipsArchVariant(kMips32r6)) { \
451 __ cfc1(kScratchReg, FCSR); \
452 __ li(at, Operand(mode_##mode)); \
453 __ ctc1(at, FCSR); \
454 __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
455 __ ctc1(kScratchReg, FCSR); \
456 } else { \
457 int32_t kFloat32ExponentBias = 127; \
458 int32_t kFloat32MantissaBits = 23; \
459 int32_t kFloat32ExponentBits = 8; \
460 auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \
461 Label done; \
462 __ mfc1(kScratchReg, i.InputDoubleRegister(0)); \
463 __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits); \
464 __ Branch(USE_DELAY_SLOT, &done, hs, at, \
465 Operand(kFloat32ExponentBias + kFloat32MantissaBits)); \
466 __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
467 __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
468 __ mfc1(at, i.OutputDoubleRegister()); \
469 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \
470 __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
471 __ bind(ool->exit()); \
472 __ bind(&done); \
473 }
474
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100475void CodeGenerator::AssembleDeconstructFrame() {
476 __ mov(sp, fp);
477 __ Pop(ra, fp);
478}
479
480void CodeGenerator::AssembleSetupStackPointer() {}
481
Ben Murdoch014dc512016-03-22 12:00:34 +0000482void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
483 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
484 if (sp_slot_delta > 0) {
485 __ addiu(sp, sp, sp_slot_delta * kPointerSize);
486 }
487 frame_access_state()->SetFrameAccessToDefault();
488}
489
490
491void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
492 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
493 if (sp_slot_delta < 0) {
494 __ Subu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
495 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
496 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100497 if (frame_access_state()->has_frame()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000498 __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
499 __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
500 }
501 frame_access_state()->SetFrameAccessToSP();
502}
Emily Bernier958fae72015-03-24 16:35:39 -0400503
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100504void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
505 Register scratch1,
506 Register scratch2,
507 Register scratch3) {
508 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
509 Label done;
510
511 // Check if current frame is an arguments adaptor frame.
512 __ lw(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
513 __ Branch(&done, ne, scratch1,
514 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
515
516 // Load arguments count from current arguments adaptor frame (note, it
517 // does not include receiver).
518 Register caller_args_count_reg = scratch1;
519 __ lw(caller_args_count_reg,
520 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
521 __ SmiUntag(caller_args_count_reg);
522
523 ParameterCount callee_args_count(args_reg);
524 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
525 scratch3);
526 __ bind(&done);
527}
Emily Bernier958fae72015-03-24 16:35:39 -0400528
529// Assembles an instruction after register allocation, producing machine code.
530void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
531 MipsOperandConverter i(this, instr);
532 InstructionCode opcode = instr->opcode();
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100533 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
534 switch (arch_opcode) {
Emily Bernier958fae72015-03-24 16:35:39 -0400535 case kArchCallCodeObject: {
536 EnsureSpaceForLazyDeopt();
537 if (instr->InputAt(0)->IsImmediate()) {
538 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
539 RelocInfo::CODE_TARGET);
540 } else {
541 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
542 __ Call(at);
543 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000544 RecordCallPosition(instr);
545 frame_access_state()->ClearSPDelta();
546 break;
547 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100548 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch014dc512016-03-22 12:00:34 +0000549 case kArchTailCallCodeObject: {
550 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
551 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100552 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
553 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
554 i.TempRegister(0), i.TempRegister(1),
555 i.TempRegister(2));
556 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000557 if (instr->InputAt(0)->IsImmediate()) {
558 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
559 RelocInfo::CODE_TARGET);
560 } else {
561 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
562 __ Jump(at);
563 }
564 frame_access_state()->ClearSPDelta();
Emily Bernier958fae72015-03-24 16:35:39 -0400565 break;
566 }
567 case kArchCallJSFunction: {
568 EnsureSpaceForLazyDeopt();
569 Register func = i.InputRegister(0);
570 if (FLAG_debug_code) {
571 // Check the function's context matches the context argument.
572 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
573 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
574 }
575
576 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
577 __ Call(at);
Ben Murdoch014dc512016-03-22 12:00:34 +0000578 RecordCallPosition(instr);
579 frame_access_state()->ClearSPDelta();
580 break;
581 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100582 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch014dc512016-03-22 12:00:34 +0000583 case kArchTailCallJSFunction: {
584 Register func = i.InputRegister(0);
585 if (FLAG_debug_code) {
586 // Check the function's context matches the context argument.
587 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
588 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
589 }
590
591 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
592 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100593 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
594 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
595 i.TempRegister(0), i.TempRegister(1),
596 i.TempRegister(2));
597 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000598 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
599 __ Jump(at);
600 frame_access_state()->ClearSPDelta();
601 break;
602 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000603 case kArchPrepareCallCFunction: {
604 int const num_parameters = MiscField::decode(instr->opcode());
605 __ PrepareCallCFunction(num_parameters, kScratchReg);
606 // Frame alignment requires using FP-relative frame addressing.
607 frame_access_state()->SetFrameAccessToFP();
608 break;
609 }
610 case kArchPrepareTailCall:
611 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
612 break;
613 case kArchCallCFunction: {
614 int const num_parameters = MiscField::decode(instr->opcode());
615 if (instr->InputAt(0)->IsImmediate()) {
616 ExternalReference ref = i.InputExternalReference(0);
617 __ CallCFunction(ref, num_parameters);
618 } else {
619 Register func = i.InputRegister(0);
620 __ CallCFunction(func, num_parameters);
621 }
622 frame_access_state()->SetFrameAccessToDefault();
623 frame_access_state()->ClearSPDelta();
Emily Bernier958fae72015-03-24 16:35:39 -0400624 break;
625 }
626 case kArchJmp:
627 AssembleArchJump(i.InputRpo(0));
628 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000629 case kArchLookupSwitch:
630 AssembleArchLookupSwitch(instr);
631 break;
632 case kArchTableSwitch:
633 AssembleArchTableSwitch(instr);
634 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400635 case kArchNop:
Ben Murdoch014dc512016-03-22 12:00:34 +0000636 case kArchThrowTerminator:
Emily Bernier958fae72015-03-24 16:35:39 -0400637 // don't emit code for nops.
638 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000639 case kArchDeoptimize: {
640 int deopt_state_id =
641 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
642 Deoptimizer::BailoutType bailout_type =
643 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
644 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
645 break;
646 }
Emily Bernier958fae72015-03-24 16:35:39 -0400647 case kArchRet:
648 AssembleReturn();
649 break;
650 case kArchStackPointer:
651 __ mov(i.OutputRegister(), sp);
652 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000653 case kArchFramePointer:
654 __ mov(i.OutputRegister(), fp);
655 break;
Ben Murdoch109988c2016-05-18 11:27:45 +0100656 case kArchParentFramePointer:
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100657 if (frame_access_state()->has_frame()) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100658 __ lw(i.OutputRegister(), MemOperand(fp, 0));
659 } else {
660 __ mov(i.OutputRegister(), fp);
661 }
662 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400663 case kArchTruncateDoubleToI:
664 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
665 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000666 case kArchStoreWithWriteBarrier: {
667 RecordWriteMode mode =
668 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
669 Register object = i.InputRegister(0);
670 Register index = i.InputRegister(1);
671 Register value = i.InputRegister(2);
672 Register scratch0 = i.TempRegister(0);
673 Register scratch1 = i.TempRegister(1);
674 auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
675 scratch0, scratch1, mode);
676 __ Addu(at, object, index);
677 __ sw(value, MemOperand(at));
678 __ CheckPageFlag(object, scratch0,
679 MemoryChunk::kPointersFromHereAreInterestingMask, ne,
680 ool->entry());
681 __ bind(ool->exit());
682 break;
683 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100684 case kArchStackSlot: {
685 FrameOffset offset =
686 frame_access_state()->GetFrameOffset(i.InputInt32(0));
687 __ Addu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
688 Operand(offset.offset()));
689 break;
690 }
Emily Bernier958fae72015-03-24 16:35:39 -0400691 case kMipsAdd:
692 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
693 break;
694 case kMipsAddOvf:
Ben Murdoch014dc512016-03-22 12:00:34 +0000695 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
Emily Bernier958fae72015-03-24 16:35:39 -0400696 break;
697 case kMipsSub:
698 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
699 break;
700 case kMipsSubOvf:
Ben Murdoch014dc512016-03-22 12:00:34 +0000701 // Pseudo-instruction used for overflow/branch. No opcode emitted here.
Emily Bernier958fae72015-03-24 16:35:39 -0400702 break;
703 case kMipsMul:
704 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
705 break;
706 case kMipsMulHigh:
707 __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
708 break;
709 case kMipsMulHighU:
710 __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
711 break;
712 case kMipsDiv:
713 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +0000714 if (IsMipsArchVariant(kMips32r6)) {
715 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
716 } else {
717 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
718 }
Emily Bernier958fae72015-03-24 16:35:39 -0400719 break;
720 case kMipsDivU:
721 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +0000722 if (IsMipsArchVariant(kMips32r6)) {
723 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
724 } else {
725 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
726 }
Emily Bernier958fae72015-03-24 16:35:39 -0400727 break;
728 case kMipsMod:
729 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
730 break;
731 case kMipsModU:
732 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
733 break;
734 case kMipsAnd:
735 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
736 break;
737 case kMipsOr:
738 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
739 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000740 case kMipsNor:
741 if (instr->InputAt(1)->IsRegister()) {
742 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
743 } else {
744 DCHECK(i.InputOperand(1).immediate() == 0);
745 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
746 }
747 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400748 case kMipsXor:
749 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
750 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000751 case kMipsClz:
752 __ Clz(i.OutputRegister(), i.InputRegister(0));
753 break;
Ben Murdoch109988c2016-05-18 11:27:45 +0100754 case kMipsCtz: {
755 Register reg1 = kScratchReg;
756 Register reg2 = kScratchReg2;
757 Label skip_for_zero;
758 Label end;
759 // Branch if the operand is zero
760 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg));
761 // Find the number of bits before the last bit set to 1.
762 __ Subu(reg2, zero_reg, i.InputRegister(0));
763 __ And(reg2, reg2, i.InputRegister(0));
764 __ clz(reg2, reg2);
765 // Get the number of bits after the last bit set to 1.
766 __ li(reg1, 0x1F);
767 __ Subu(i.OutputRegister(), reg1, reg2);
768 __ Branch(&end);
769 __ bind(&skip_for_zero);
770 // If the operand is zero, return word length as the result.
771 __ li(i.OutputRegister(), 0x20);
772 __ bind(&end);
773 } break;
774 case kMipsPopcnt: {
775 Register reg1 = kScratchReg;
776 Register reg2 = kScratchReg2;
777 uint32_t m1 = 0x55555555;
778 uint32_t m2 = 0x33333333;
779 uint32_t m4 = 0x0f0f0f0f;
780 uint32_t m8 = 0x00ff00ff;
781 uint32_t m16 = 0x0000ffff;
782
783 // Put count of ones in every 2 bits into those 2 bits.
784 __ li(at, m1);
785 __ srl(reg1, i.InputRegister(0), 1);
786 __ And(reg2, i.InputRegister(0), at);
787 __ And(reg1, reg1, at);
788 __ addu(reg1, reg1, reg2);
789
790 // Put count of ones in every 4 bits into those 4 bits.
791 __ li(at, m2);
792 __ srl(reg2, reg1, 2);
793 __ And(reg2, reg2, at);
794 __ And(reg1, reg1, at);
795 __ addu(reg1, reg1, reg2);
796
797 // Put count of ones in every 8 bits into those 8 bits.
798 __ li(at, m4);
799 __ srl(reg2, reg1, 4);
800 __ And(reg2, reg2, at);
801 __ And(reg1, reg1, at);
802 __ addu(reg1, reg1, reg2);
803
804 // Put count of ones in every 16 bits into those 16 bits.
805 __ li(at, m8);
806 __ srl(reg2, reg1, 8);
807 __ And(reg2, reg2, at);
808 __ And(reg1, reg1, at);
809 __ addu(reg1, reg1, reg2);
810
811 // Calculate total number of ones.
812 __ li(at, m16);
813 __ srl(reg2, reg1, 16);
814 __ And(reg2, reg2, at);
815 __ And(reg1, reg1, at);
816 __ addu(i.OutputRegister(), reg1, reg2);
817 } break;
Emily Bernier958fae72015-03-24 16:35:39 -0400818 case kMipsShl:
819 if (instr->InputAt(1)->IsRegister()) {
820 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
821 } else {
822 int32_t imm = i.InputOperand(1).immediate();
823 __ sll(i.OutputRegister(), i.InputRegister(0), imm);
824 }
825 break;
826 case kMipsShr:
827 if (instr->InputAt(1)->IsRegister()) {
828 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
829 } else {
830 int32_t imm = i.InputOperand(1).immediate();
831 __ srl(i.OutputRegister(), i.InputRegister(0), imm);
832 }
833 break;
834 case kMipsSar:
835 if (instr->InputAt(1)->IsRegister()) {
836 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
837 } else {
838 int32_t imm = i.InputOperand(1).immediate();
839 __ sra(i.OutputRegister(), i.InputRegister(0), imm);
840 }
841 break;
Ben Murdoch014dc512016-03-22 12:00:34 +0000842 case kMipsExt:
843 __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
844 i.InputInt8(2));
845 break;
846 case kMipsIns:
847 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
848 __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
849 } else {
850 __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
851 i.InputInt8(2));
852 }
853 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400854 case kMipsRor:
855 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
856 break;
857 case kMipsTst:
858 // Pseudo-instruction used for tst/branch. No opcode emitted here.
859 break;
860 case kMipsCmp:
861 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
862 break;
863 case kMipsMov:
864 // TODO(plind): Should we combine mov/li like this, or use separate instr?
865 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
866 if (HasRegisterInput(instr, 0)) {
867 __ mov(i.OutputRegister(), i.InputRegister(0));
868 } else {
869 __ li(i.OutputRegister(), i.InputOperand(0));
870 }
871 break;
872
Ben Murdoch014dc512016-03-22 12:00:34 +0000873 case kMipsCmpS:
874 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
875 break;
876 case kMipsAddS:
877 // TODO(plind): add special case: combine mult & add.
878 __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
879 i.InputDoubleRegister(1));
880 break;
881 case kMipsSubS:
882 __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
883 i.InputDoubleRegister(1));
884 break;
885 case kMipsMulS:
886 // TODO(plind): add special case: right op is -1.0, see arm port.
887 __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
888 i.InputDoubleRegister(1));
889 break;
890 case kMipsDivS:
891 __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
892 i.InputDoubleRegister(1));
893 break;
894 case kMipsModS: {
895 // TODO(bmeurer): We should really get rid of this special instruction,
896 // and generate a CallAddress instruction instead.
897 FrameScope scope(masm(), StackFrame::MANUAL);
898 __ PrepareCallCFunction(0, 2, kScratchReg);
899 __ MovToFloatParameters(i.InputDoubleRegister(0),
900 i.InputDoubleRegister(1));
901 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
902 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
903 0, 2);
904 // Move the result in the double result register.
905 __ MovFromFloatResult(i.OutputSingleRegister());
906 break;
907 }
908 case kMipsAbsS:
909 __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
910 break;
911 case kMipsSqrtS: {
912 __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
913 break;
914 }
915 case kMipsMaxS:
916 __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
917 i.InputDoubleRegister(1));
918 break;
919 case kMipsMinS:
920 __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
921 i.InputDoubleRegister(1));
922 break;
Emily Bernier958fae72015-03-24 16:35:39 -0400923 case kMipsCmpD:
924 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
925 break;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100926 case kMipsMulPair: {
927 __ Mulu(i.OutputRegister(1), i.OutputRegister(0), i.InputRegister(0),
928 i.InputRegister(2));
929 __ mul(kScratchReg, i.InputRegister(0), i.InputRegister(3));
930 __ mul(kScratchReg2, i.InputRegister(1), i.InputRegister(2));
931 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg);
932 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg2);
933 } break;
Emily Bernier958fae72015-03-24 16:35:39 -0400934 case kMipsAddD:
935 // TODO(plind): add special case: combine mult & add.
936 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
937 i.InputDoubleRegister(1));
938 break;
939 case kMipsSubD:
940 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
941 i.InputDoubleRegister(1));
942 break;
943 case kMipsMulD:
944 // TODO(plind): add special case: right op is -1.0, see arm port.
945 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
946 i.InputDoubleRegister(1));
947 break;
948 case kMipsDivD:
949 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
950 i.InputDoubleRegister(1));
951 break;
952 case kMipsModD: {
953 // TODO(bmeurer): We should really get rid of this special instruction,
954 // and generate a CallAddress instruction instead.
955 FrameScope scope(masm(), StackFrame::MANUAL);
956 __ PrepareCallCFunction(0, 2, kScratchReg);
957 __ MovToFloatParameters(i.InputDoubleRegister(0),
958 i.InputDoubleRegister(1));
959 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
960 0, 2);
961 // Move the result in the double result register.
962 __ MovFromFloatResult(i.OutputDoubleRegister());
963 break;
964 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000965 case kMipsAbsD:
966 __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
967 break;
968 case kMipsSqrtD: {
969 __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
Emily Bernier958fae72015-03-24 16:35:39 -0400970 break;
971 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000972 case kMipsMaxD:
973 __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
974 i.InputDoubleRegister(1));
975 break;
976 case kMipsMinD:
977 __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
978 i.InputDoubleRegister(1));
979 break;
980 case kMipsFloat64RoundDown: {
981 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor);
982 break;
983 }
984 case kMipsFloat32RoundDown: {
985 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor);
Emily Bernier958fae72015-03-24 16:35:39 -0400986 break;
987 }
988 case kMipsFloat64RoundTruncate: {
Ben Murdoch014dc512016-03-22 12:00:34 +0000989 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc);
Emily Bernier958fae72015-03-24 16:35:39 -0400990 break;
991 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000992 case kMipsFloat32RoundTruncate: {
993 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc);
994 break;
995 }
996 case kMipsFloat64RoundUp: {
997 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil);
998 break;
999 }
1000 case kMipsFloat32RoundUp: {
1001 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil);
1002 break;
1003 }
1004 case kMipsFloat64RoundTiesEven: {
1005 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round);
1006 break;
1007 }
1008 case kMipsFloat32RoundTiesEven: {
1009 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round);
1010 break;
1011 }
1012 case kMipsFloat64Max: {
1013 // (b < a) ? a : b
1014 if (IsMipsArchVariant(kMips32r6)) {
1015 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1016 i.InputDoubleRegister(0));
1017 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1018 i.InputDoubleRegister(0));
1019 } else {
1020 __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1021 // Left operand is result, passthrough if false.
1022 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1023 }
1024 break;
1025 }
1026 case kMipsFloat64Min: {
1027 // (a < b) ? a : b
1028 if (IsMipsArchVariant(kMips32r6)) {
1029 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1030 i.InputDoubleRegister(1));
1031 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1032 i.InputDoubleRegister(0));
1033 } else {
1034 __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1035 // Right operand is result, passthrough if false.
1036 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1037 }
1038 break;
1039 }
1040 case kMipsFloat32Max: {
1041 // (b < a) ? a : b
1042 if (IsMipsArchVariant(kMips32r6)) {
1043 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1044 i.InputDoubleRegister(0));
1045 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1046 i.InputDoubleRegister(0));
1047 } else {
1048 __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1049 // Left operand is result, passthrough if false.
1050 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1051 }
1052 break;
1053 }
1054 case kMipsFloat32Min: {
1055 // (a < b) ? a : b
1056 if (IsMipsArchVariant(kMips32r6)) {
1057 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1058 i.InputDoubleRegister(1));
1059 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
1060 i.InputDoubleRegister(0));
1061 } else {
1062 __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0));
1063 // Right operand is result, passthrough if false.
1064 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1065 }
Emily Bernier958fae72015-03-24 16:35:39 -04001066 break;
1067 }
1068 case kMipsCvtSD: {
1069 __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1070 break;
1071 }
1072 case kMipsCvtDS: {
1073 __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1074 break;
1075 }
1076 case kMipsCvtDW: {
1077 FPURegister scratch = kScratchDoubleReg;
1078 __ mtc1(i.InputRegister(0), scratch);
1079 __ cvt_d_w(i.OutputDoubleRegister(), scratch);
1080 break;
1081 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001082 case kMipsCvtSW: {
1083 FPURegister scratch = kScratchDoubleReg;
1084 __ mtc1(i.InputRegister(0), scratch);
1085 __ cvt_s_w(i.OutputDoubleRegister(), scratch);
1086 break;
1087 }
Ben Murdoch109988c2016-05-18 11:27:45 +01001088 case kMipsCvtSUw: {
1089 FPURegister scratch = kScratchDoubleReg;
1090 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1091 __ cvt_s_d(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1092 break;
1093 }
Emily Bernier958fae72015-03-24 16:35:39 -04001094 case kMipsCvtDUw: {
1095 FPURegister scratch = kScratchDoubleReg;
1096 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
1097 break;
1098 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001099 case kMipsFloorWD: {
1100 FPURegister scratch = kScratchDoubleReg;
1101 __ floor_w_d(scratch, i.InputDoubleRegister(0));
1102 __ mfc1(i.OutputRegister(), scratch);
1103 break;
1104 }
1105 case kMipsCeilWD: {
1106 FPURegister scratch = kScratchDoubleReg;
1107 __ ceil_w_d(scratch, i.InputDoubleRegister(0));
1108 __ mfc1(i.OutputRegister(), scratch);
1109 break;
1110 }
1111 case kMipsRoundWD: {
1112 FPURegister scratch = kScratchDoubleReg;
1113 __ round_w_d(scratch, i.InputDoubleRegister(0));
1114 __ mfc1(i.OutputRegister(), scratch);
1115 break;
1116 }
Emily Bernier958fae72015-03-24 16:35:39 -04001117 case kMipsTruncWD: {
1118 FPURegister scratch = kScratchDoubleReg;
1119 // Other arches use round to zero here, so we follow.
1120 __ trunc_w_d(scratch, i.InputDoubleRegister(0));
1121 __ mfc1(i.OutputRegister(), scratch);
1122 break;
1123 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001124 case kMipsFloorWS: {
1125 FPURegister scratch = kScratchDoubleReg;
1126 __ floor_w_s(scratch, i.InputDoubleRegister(0));
1127 __ mfc1(i.OutputRegister(), scratch);
1128 break;
1129 }
1130 case kMipsCeilWS: {
1131 FPURegister scratch = kScratchDoubleReg;
1132 __ ceil_w_s(scratch, i.InputDoubleRegister(0));
1133 __ mfc1(i.OutputRegister(), scratch);
1134 break;
1135 }
1136 case kMipsRoundWS: {
1137 FPURegister scratch = kScratchDoubleReg;
1138 __ round_w_s(scratch, i.InputDoubleRegister(0));
1139 __ mfc1(i.OutputRegister(), scratch);
1140 break;
1141 }
1142 case kMipsTruncWS: {
1143 FPURegister scratch = kScratchDoubleReg;
1144 __ trunc_w_s(scratch, i.InputDoubleRegister(0));
1145 __ mfc1(i.OutputRegister(), scratch);
1146 break;
1147 }
Emily Bernier958fae72015-03-24 16:35:39 -04001148 case kMipsTruncUwD: {
1149 FPURegister scratch = kScratchDoubleReg;
1150 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
1151 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1152 break;
1153 }
Ben Murdoch109988c2016-05-18 11:27:45 +01001154 case kMipsTruncUwS: {
1155 FPURegister scratch = kScratchDoubleReg;
1156 // TODO(plind): Fix wrong param order of Trunc_uw_s() macro-asm function.
1157 __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
1158 break;
1159 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001160 case kMipsFloat64ExtractLowWord32:
1161 __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1162 break;
1163 case kMipsFloat64ExtractHighWord32:
1164 __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
1165 break;
1166 case kMipsFloat64InsertLowWord32:
1167 __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1168 break;
1169 case kMipsFloat64InsertHighWord32:
1170 __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
1171 break;
Emily Bernier958fae72015-03-24 16:35:39 -04001172 // ... more basic instructions ...
1173
1174 case kMipsLbu:
1175 __ lbu(i.OutputRegister(), i.MemoryOperand());
1176 break;
1177 case kMipsLb:
1178 __ lb(i.OutputRegister(), i.MemoryOperand());
1179 break;
1180 case kMipsSb:
1181 __ sb(i.InputRegister(2), i.MemoryOperand());
1182 break;
1183 case kMipsLhu:
1184 __ lhu(i.OutputRegister(), i.MemoryOperand());
1185 break;
1186 case kMipsLh:
1187 __ lh(i.OutputRegister(), i.MemoryOperand());
1188 break;
1189 case kMipsSh:
1190 __ sh(i.InputRegister(2), i.MemoryOperand());
1191 break;
1192 case kMipsLw:
1193 __ lw(i.OutputRegister(), i.MemoryOperand());
1194 break;
1195 case kMipsSw:
1196 __ sw(i.InputRegister(2), i.MemoryOperand());
1197 break;
1198 case kMipsLwc1: {
1199 __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
1200 break;
1201 }
1202 case kMipsSwc1: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001203 size_t index = 0;
Emily Bernier958fae72015-03-24 16:35:39 -04001204 MemOperand operand = i.MemoryOperand(&index);
1205 __ swc1(i.InputSingleRegister(index), operand);
1206 break;
1207 }
1208 case kMipsLdc1:
1209 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1210 break;
1211 case kMipsSdc1:
1212 __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
1213 break;
1214 case kMipsPush:
Ben Murdoch014dc512016-03-22 12:00:34 +00001215 if (instr->InputAt(0)->IsDoubleRegister()) {
1216 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1217 __ Subu(sp, sp, Operand(kDoubleSize));
1218 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1219 } else {
1220 __ Push(i.InputRegister(0));
1221 frame_access_state()->IncreaseSPDelta(1);
1222 }
Emily Bernier958fae72015-03-24 16:35:39 -04001223 break;
1224 case kMipsStackClaim: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001225 __ Subu(sp, sp, Operand(i.InputInt32(0)));
1226 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001227 break;
1228 }
1229 case kMipsStoreToStackSlot: {
Ben Murdoch014dc512016-03-22 12:00:34 +00001230 if (instr->InputAt(0)->IsDoubleRegister()) {
1231 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1232 } else {
1233 __ sw(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1234 }
Emily Bernier958fae72015-03-24 16:35:39 -04001235 break;
1236 }
1237 case kCheckedLoadInt8:
1238 ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
1239 break;
1240 case kCheckedLoadUint8:
1241 ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
1242 break;
1243 case kCheckedLoadInt16:
1244 ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
1245 break;
1246 case kCheckedLoadUint16:
1247 ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
1248 break;
1249 case kCheckedLoadWord32:
1250 ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
1251 break;
1252 case kCheckedLoadFloat32:
1253 ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
1254 break;
1255 case kCheckedLoadFloat64:
1256 ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
1257 break;
1258 case kCheckedStoreWord8:
1259 ASSEMBLE_CHECKED_STORE_INTEGER(sb);
1260 break;
1261 case kCheckedStoreWord16:
1262 ASSEMBLE_CHECKED_STORE_INTEGER(sh);
1263 break;
1264 case kCheckedStoreWord32:
1265 ASSEMBLE_CHECKED_STORE_INTEGER(sw);
1266 break;
1267 case kCheckedStoreFloat32:
1268 ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
1269 break;
1270 case kCheckedStoreFloat64:
1271 ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
1272 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001273 case kCheckedLoadWord64:
1274 case kCheckedStoreWord64:
1275 UNREACHABLE(); // currently unsupported checked int64 load/store.
1276 break;
Emily Bernier958fae72015-03-24 16:35:39 -04001277 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001278} // NOLINT(readability/fn_size)
Emily Bernier958fae72015-03-24 16:35:39 -04001279
1280
1281#define UNSUPPORTED_COND(opcode, condition) \
1282 OFStream out(stdout); \
1283 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
1284 UNIMPLEMENTED();
1285
Ben Murdoch014dc512016-03-22 12:00:34 +00001286static bool convertCondition(FlagsCondition condition, Condition& cc) {
1287 switch (condition) {
1288 case kEqual:
1289 cc = eq;
1290 return true;
1291 case kNotEqual:
1292 cc = ne;
1293 return true;
1294 case kUnsignedLessThan:
1295 cc = lt;
1296 return true;
1297 case kUnsignedGreaterThanOrEqual:
1298 cc = uge;
1299 return true;
1300 case kUnsignedLessThanOrEqual:
1301 cc = le;
1302 return true;
1303 case kUnsignedGreaterThan:
1304 cc = ugt;
1305 return true;
1306 default:
1307 break;
1308 }
1309 return false;
1310}
1311
1312
Emily Bernier958fae72015-03-24 16:35:39 -04001313// Assembles branches after an instruction.
1314void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1315 MipsOperandConverter i(this, instr);
1316 Label* tlabel = branch->true_label;
1317 Label* flabel = branch->false_label;
1318 Condition cc = kNoCondition;
Emily Bernier958fae72015-03-24 16:35:39 -04001319 // MIPS does not have condition code flags, so compare and branch are
1320 // implemented differently than on the other arch's. The compare operations
1321 // emit mips pseudo-instructions, which are handled here by branch
1322 // instructions that do the actual comparison. Essential that the input
1323 // registers to compare pseudo-op are not modified before this branch op, as
1324 // they are tested here.
Emily Bernier958fae72015-03-24 16:35:39 -04001325
1326 if (instr->arch_opcode() == kMipsTst) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001327 cc = FlagsConditionToConditionTst(branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001328 __ And(at, i.InputRegister(0), i.InputOperand(1));
1329 __ Branch(tlabel, cc, at, Operand(zero_reg));
Ben Murdoch014dc512016-03-22 12:00:34 +00001330 } else if (instr->arch_opcode() == kMipsAddOvf) {
Emily Bernier958fae72015-03-24 16:35:39 -04001331 switch (branch->condition) {
1332 case kOverflow:
Ben Murdoch014dc512016-03-22 12:00:34 +00001333 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1334 i.InputOperand(1), tlabel, flabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001335 break;
1336 case kNotOverflow:
Ben Murdoch014dc512016-03-22 12:00:34 +00001337 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0),
1338 i.InputOperand(1), flabel, tlabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001339 break;
1340 default:
1341 UNSUPPORTED_COND(kMipsAddOvf, branch->condition);
1342 break;
1343 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001344 } else if (instr->arch_opcode() == kMipsSubOvf) {
1345 switch (branch->condition) {
1346 case kOverflow:
1347 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1348 i.InputOperand(1), tlabel, flabel);
1349 break;
1350 case kNotOverflow:
1351 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0),
1352 i.InputOperand(1), flabel, tlabel);
1353 break;
1354 default:
1355 UNSUPPORTED_COND(kMipsAddOvf, branch->condition);
1356 break;
1357 }
Emily Bernier958fae72015-03-24 16:35:39 -04001358 } else if (instr->arch_opcode() == kMipsCmp) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001359 cc = FlagsConditionToConditionCmp(branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001360 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
Ben Murdoch014dc512016-03-22 12:00:34 +00001361 } else if (instr->arch_opcode() == kMipsCmpS) {
1362 if (!convertCondition(branch->condition, cc)) {
1363 UNSUPPORTED_COND(kMips64CmpS, branch->condition);
Emily Bernier958fae72015-03-24 16:35:39 -04001364 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001365 FPURegister left = i.InputOrZeroSingleRegister(0);
1366 FPURegister right = i.InputOrZeroSingleRegister(1);
1367 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1368 !__ IsDoubleZeroRegSet()) {
1369 __ Move(kDoubleRegZero, 0.0);
1370 }
1371 __ BranchF32(tlabel, nullptr, cc, left, right);
1372 } else if (instr->arch_opcode() == kMipsCmpD) {
1373 if (!convertCondition(branch->condition, cc)) {
1374 UNSUPPORTED_COND(kMips64CmpD, branch->condition);
1375 }
1376 FPURegister left = i.InputOrZeroDoubleRegister(0);
1377 FPURegister right = i.InputOrZeroDoubleRegister(1);
1378 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1379 !__ IsDoubleZeroRegSet()) {
1380 __ Move(kDoubleRegZero, 0.0);
1381 }
1382 __ BranchF64(tlabel, nullptr, cc, left, right);
Emily Bernier958fae72015-03-24 16:35:39 -04001383 } else {
1384 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
1385 instr->arch_opcode());
1386 UNIMPLEMENTED();
1387 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001388 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel.
Emily Bernier958fae72015-03-24 16:35:39 -04001389}
1390
1391
Ben Murdoch014dc512016-03-22 12:00:34 +00001392void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernier958fae72015-03-24 16:35:39 -04001393 if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
1394}
1395
1396
1397// Assembles boolean materializations after an instruction.
1398void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1399 FlagsCondition condition) {
1400 MipsOperandConverter i(this, instr);
1401 Label done;
1402
1403 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1404 // last output of the instruction.
1405 Label false_value;
Ben Murdoch014dc512016-03-22 12:00:34 +00001406 DCHECK_NE(0u, instr->OutputCount());
Emily Bernier958fae72015-03-24 16:35:39 -04001407 Register result = i.OutputRegister(instr->OutputCount() - 1);
1408 Condition cc = kNoCondition;
Emily Bernier958fae72015-03-24 16:35:39 -04001409 // MIPS does not have condition code flags, so compare and branch are
1410 // implemented differently than on the other arch's. The compare operations
1411 // emit mips psuedo-instructions, which are checked and handled here.
1412
Emily Bernier958fae72015-03-24 16:35:39 -04001413 if (instr->arch_opcode() == kMipsTst) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001414 cc = FlagsConditionToConditionTst(condition);
1415 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1416 __ Sltu(result, zero_reg, kScratchReg);
1417 if (cc == eq) {
1418 // Sltu produces 0 for equality, invert the result.
1419 __ xori(result, result, 1);
Emily Bernier958fae72015-03-24 16:35:39 -04001420 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001421 return;
Emily Bernier958fae72015-03-24 16:35:39 -04001422 } else if (instr->arch_opcode() == kMipsAddOvf ||
1423 instr->arch_opcode() == kMipsSubOvf) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001424 Label flabel, tlabel;
1425 switch (instr->arch_opcode()) {
1426 case kMipsAddOvf:
1427 __ AddBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1428 i.InputOperand(1), &flabel);
1429
Emily Bernier958fae72015-03-24 16:35:39 -04001430 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001431 case kMipsSubOvf:
1432 __ SubBranchNoOvf(i.OutputRegister(), i.InputRegister(0),
1433 i.InputOperand(1), &flabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001434 break;
1435 default:
Ben Murdoch014dc512016-03-22 12:00:34 +00001436 UNREACHABLE();
Emily Bernier958fae72015-03-24 16:35:39 -04001437 break;
1438 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001439 __ li(result, 1);
1440 __ Branch(&tlabel);
1441 __ bind(&flabel);
1442 __ li(result, 0);
1443 __ bind(&tlabel);
Emily Bernier958fae72015-03-24 16:35:39 -04001444 } else if (instr->arch_opcode() == kMipsCmp) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001445 cc = FlagsConditionToConditionCmp(condition);
1446 switch (cc) {
1447 case eq:
1448 case ne: {
1449 Register left = i.InputRegister(0);
1450 Operand right = i.InputOperand(1);
1451 Register select;
1452 if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) {
1453 // Pass left operand if right is zero.
1454 select = left;
1455 } else {
1456 __ Subu(kScratchReg, left, right);
1457 select = kScratchReg;
1458 }
1459 __ Sltu(result, zero_reg, select);
1460 if (cc == eq) {
1461 // Sltu produces 0 for equality, invert the result.
1462 __ xori(result, result, 1);
1463 }
1464 } break;
1465 case lt:
1466 case ge: {
1467 Register left = i.InputRegister(0);
1468 Operand right = i.InputOperand(1);
1469 __ Slt(result, left, right);
1470 if (cc == ge) {
1471 __ xori(result, result, 1);
1472 }
1473 } break;
1474 case gt:
1475 case le: {
1476 Register left = i.InputRegister(1);
1477 Operand right = i.InputOperand(0);
1478 __ Slt(result, left, right);
1479 if (cc == le) {
1480 __ xori(result, result, 1);
1481 }
1482 } break;
1483 case lo:
1484 case hs: {
1485 Register left = i.InputRegister(0);
1486 Operand right = i.InputOperand(1);
1487 __ Sltu(result, left, right);
1488 if (cc == hs) {
1489 __ xori(result, result, 1);
1490 }
1491 } break;
1492 case hi:
1493 case ls: {
1494 Register left = i.InputRegister(1);
1495 Operand right = i.InputOperand(0);
1496 __ Sltu(result, left, right);
1497 if (cc == ls) {
1498 __ xori(result, result, 1);
1499 }
1500 } break;
Emily Bernier958fae72015-03-24 16:35:39 -04001501 default:
Ben Murdoch014dc512016-03-22 12:00:34 +00001502 UNREACHABLE();
Emily Bernier958fae72015-03-24 16:35:39 -04001503 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001504 return;
1505 } else if (instr->arch_opcode() == kMipsCmpD ||
1506 instr->arch_opcode() == kMipsCmpS) {
1507 FPURegister left = i.InputOrZeroDoubleRegister(0);
1508 FPURegister right = i.InputOrZeroDoubleRegister(1);
1509 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) &&
1510 !__ IsDoubleZeroRegSet()) {
1511 __ Move(kDoubleRegZero, 0.0);
Emily Bernier958fae72015-03-24 16:35:39 -04001512 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001513 bool predicate;
1514 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
1515 if (!IsMipsArchVariant(kMips32r6)) {
1516 __ li(result, Operand(1));
1517 if (instr->arch_opcode() == kMipsCmpD) {
1518 __ c(cc, D, left, right);
1519 } else {
1520 DCHECK(instr->arch_opcode() == kMipsCmpS);
1521 __ c(cc, S, left, right);
1522 }
1523 if (predicate) {
1524 __ Movf(result, zero_reg);
1525 } else {
1526 __ Movt(result, zero_reg);
1527 }
1528 } else {
1529 if (instr->arch_opcode() == kMipsCmpD) {
1530 __ cmp(cc, L, kDoubleCompareReg, left, right);
1531 } else {
1532 DCHECK(instr->arch_opcode() == kMipsCmpS);
1533 __ cmp(cc, W, kDoubleCompareReg, left, right);
1534 }
1535 __ mfc1(result, kDoubleCompareReg);
1536 __ andi(result, result, 1); // Cmp returns all 1's/0's, use only LSB.
1537 if (!predicate) // Toggle result for not equal.
1538 __ xori(result, result, 1);
1539 }
1540 return;
Emily Bernier958fae72015-03-24 16:35:39 -04001541 } else {
1542 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
1543 instr->arch_opcode());
1544 TRACE_UNIMPL();
1545 UNIMPLEMENTED();
1546 }
Emily Bernier958fae72015-03-24 16:35:39 -04001547}
1548
1549
Ben Murdoch014dc512016-03-22 12:00:34 +00001550void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1551 MipsOperandConverter i(this, instr);
1552 Register input = i.InputRegister(0);
1553 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1554 __ li(at, Operand(i.InputInt32(index + 0)));
1555 __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
1556 }
1557 __ nop(); // Branch delay slot of the last beq.
1558 AssembleArchJump(i.InputRpo(1));
1559}
1560
1561
1562void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1563 MipsOperandConverter i(this, instr);
1564 Register input = i.InputRegister(0);
1565 size_t const case_count = instr->InputCount() - 2;
Ben Murdoch014dc512016-03-22 12:00:34 +00001566 __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
Ben Murdoch109988c2016-05-18 11:27:45 +01001567 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
1568 return GetLabel(i.InputRpo(index + 2));
1569 });
Ben Murdoch014dc512016-03-22 12:00:34 +00001570}
1571
1572
1573void CodeGenerator::AssembleDeoptimizerCall(
1574 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Emily Bernier958fae72015-03-24 16:35:39 -04001575 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch014dc512016-03-22 12:00:34 +00001576 isolate(), deoptimization_id, bailout_type);
Emily Bernier958fae72015-03-24 16:35:39 -04001577 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1578}
1579
1580
1581void CodeGenerator::AssemblePrologue() {
1582 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch014dc512016-03-22 12:00:34 +00001583 int stack_shrink_slots = frame()->GetSpillSlotCount();
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001584 if (frame_access_state()->has_frame()) {
1585 if (descriptor->IsCFunctionCall()) {
1586 __ Push(ra, fp);
1587 __ mov(fp, sp);
1588 } else if (descriptor->IsJSFunctionCall()) {
1589 __ Prologue(this->info()->GeneratePreagedPrologue());
1590 } else {
1591 __ StubPrologue(info()->GetOutputStackFrameType());
1592 }
Emily Bernier958fae72015-03-24 16:35:39 -04001593 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001594
1595 if (info()->is_osr()) {
1596 // TurboFan OSR-compiled functions cannot be entered directly.
1597 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1598
1599 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1600 // frame is still on the stack. Optimized code uses OSR values directly from
1601 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1602 // remaining stack slots.
1603 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1604 osr_pc_offset_ = __ pc_offset();
Ben Murdoch014dc512016-03-22 12:00:34 +00001605 stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
1606 }
1607
1608 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1609 if (saves_fpu != 0) {
1610 stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots();
1611 }
1612 if (stack_shrink_slots > 0) {
1613 __ Subu(sp, sp, Operand(stack_shrink_slots * kPointerSize));
1614 }
1615
1616 // Save callee-saved FPU registers.
1617 if (saves_fpu != 0) {
1618 __ MultiPushFPU(saves_fpu);
1619 int count = base::bits::CountPopulation32(saves_fpu);
1620 DCHECK(kNumCalleeSavedFPU == count);
1621 frame()->AllocateSavedCalleeRegisterSlots(count *
1622 (kDoubleSize / kPointerSize));
1623 }
1624
1625 const RegList saves = descriptor->CalleeSavedRegisters();
1626 if (saves != 0) {
1627 // Save callee-saved registers.
1628 __ MultiPush(saves);
1629 // kNumCalleeSaved includes the fp register, but the fp register
1630 // is saved separately in TF.
1631 int count = base::bits::CountPopulation32(saves);
1632 DCHECK(kNumCalleeSaved == count + 1);
1633 frame()->AllocateSavedCalleeRegisterSlots(count);
Emily Bernier958fae72015-03-24 16:35:39 -04001634 }
1635}
1636
1637
1638void CodeGenerator::AssembleReturn() {
1639 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch014dc512016-03-22 12:00:34 +00001640 int pop_count = static_cast<int>(descriptor->StackParameterCount());
1641
1642 // Restore GP registers.
1643 const RegList saves = descriptor->CalleeSavedRegisters();
1644 if (saves != 0) {
1645 __ MultiPop(saves);
1646 }
1647
1648 // Restore FPU registers.
1649 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
1650 if (saves_fpu != 0) {
1651 __ MultiPopFPU(saves_fpu);
1652 }
1653
1654 if (descriptor->IsCFunctionCall()) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001655 AssembleDeconstructFrame();
1656 } else if (frame_access_state()->has_frame()) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001657 // Canonicalize JSFunction return sites for now.
1658 if (return_label_.is_bound()) {
1659 __ Branch(&return_label_);
1660 return;
1661 } else {
1662 __ bind(&return_label_);
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001663 AssembleDeconstructFrame();
Emily Bernier958fae72015-03-24 16:35:39 -04001664 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001665 }
1666 if (pop_count != 0) {
Emily Bernier958fae72015-03-24 16:35:39 -04001667 __ DropAndRet(pop_count);
Ben Murdoch014dc512016-03-22 12:00:34 +00001668 } else {
1669 __ Ret();
Emily Bernier958fae72015-03-24 16:35:39 -04001670 }
1671}
1672
1673
1674void CodeGenerator::AssembleMove(InstructionOperand* source,
1675 InstructionOperand* destination) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001676 MipsOperandConverter g(this, nullptr);
Emily Bernier958fae72015-03-24 16:35:39 -04001677 // Dispatch on the source and destination operand kinds. Not all
1678 // combinations are possible.
1679 if (source->IsRegister()) {
1680 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1681 Register src = g.ToRegister(source);
1682 if (destination->IsRegister()) {
1683 __ mov(g.ToRegister(destination), src);
1684 } else {
1685 __ sw(src, g.ToMemOperand(destination));
1686 }
1687 } else if (source->IsStackSlot()) {
1688 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1689 MemOperand src = g.ToMemOperand(source);
1690 if (destination->IsRegister()) {
1691 __ lw(g.ToRegister(destination), src);
1692 } else {
1693 Register temp = kScratchReg;
1694 __ lw(temp, src);
1695 __ sw(temp, g.ToMemOperand(destination));
1696 }
1697 } else if (source->IsConstant()) {
1698 Constant src = g.ToConstant(source);
1699 if (destination->IsRegister() || destination->IsStackSlot()) {
1700 Register dst =
1701 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
1702 switch (src.type()) {
1703 case Constant::kInt32:
1704 __ li(dst, Operand(src.ToInt32()));
1705 break;
1706 case Constant::kFloat32:
1707 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1708 break;
1709 case Constant::kInt64:
1710 UNREACHABLE();
1711 break;
1712 case Constant::kFloat64:
1713 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1714 break;
1715 case Constant::kExternalReference:
1716 __ li(dst, Operand(src.ToExternalReference()));
1717 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001718 case Constant::kHeapObject: {
1719 Handle<HeapObject> src_object = src.ToHeapObject();
1720 Heap::RootListIndex index;
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001721 int slot;
1722 if (IsMaterializableFromFrame(src_object, &slot)) {
1723 __ lw(dst, g.SlotToMemOperand(slot));
Ben Murdoch014dc512016-03-22 12:00:34 +00001724 } else if (IsMaterializableFromRoot(src_object, &index)) {
1725 __ LoadRoot(dst, index);
1726 } else {
1727 __ li(dst, src_object);
1728 }
Emily Bernier958fae72015-03-24 16:35:39 -04001729 break;
Ben Murdoch014dc512016-03-22 12:00:34 +00001730 }
Emily Bernier958fae72015-03-24 16:35:39 -04001731 case Constant::kRpoNumber:
1732 UNREACHABLE(); // TODO(titzer): loading RPO numbers on mips.
1733 break;
1734 }
1735 if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
1736 } else if (src.type() == Constant::kFloat32) {
1737 if (destination->IsDoubleStackSlot()) {
1738 MemOperand dst = g.ToMemOperand(destination);
1739 __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
1740 __ sw(at, dst);
1741 } else {
1742 FloatRegister dst = g.ToSingleRegister(destination);
1743 __ Move(dst, src.ToFloat32());
1744 }
1745 } else {
1746 DCHECK_EQ(Constant::kFloat64, src.type());
1747 DoubleRegister dst = destination->IsDoubleRegister()
1748 ? g.ToDoubleRegister(destination)
1749 : kScratchDoubleReg;
1750 __ Move(dst, src.ToFloat64());
1751 if (destination->IsDoubleStackSlot()) {
1752 __ sdc1(dst, g.ToMemOperand(destination));
1753 }
1754 }
1755 } else if (source->IsDoubleRegister()) {
1756 FPURegister src = g.ToDoubleRegister(source);
1757 if (destination->IsDoubleRegister()) {
1758 FPURegister dst = g.ToDoubleRegister(destination);
1759 __ Move(dst, src);
1760 } else {
1761 DCHECK(destination->IsDoubleStackSlot());
1762 __ sdc1(src, g.ToMemOperand(destination));
1763 }
1764 } else if (source->IsDoubleStackSlot()) {
1765 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1766 MemOperand src = g.ToMemOperand(source);
1767 if (destination->IsDoubleRegister()) {
1768 __ ldc1(g.ToDoubleRegister(destination), src);
1769 } else {
1770 FPURegister temp = kScratchDoubleReg;
1771 __ ldc1(temp, src);
1772 __ sdc1(temp, g.ToMemOperand(destination));
1773 }
1774 } else {
1775 UNREACHABLE();
1776 }
1777}
1778
1779
1780void CodeGenerator::AssembleSwap(InstructionOperand* source,
1781 InstructionOperand* destination) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001782 MipsOperandConverter g(this, nullptr);
Emily Bernier958fae72015-03-24 16:35:39 -04001783 // Dispatch on the source and destination operand kinds. Not all
1784 // combinations are possible.
1785 if (source->IsRegister()) {
1786 // Register-register.
1787 Register temp = kScratchReg;
1788 Register src = g.ToRegister(source);
1789 if (destination->IsRegister()) {
1790 Register dst = g.ToRegister(destination);
1791 __ Move(temp, src);
1792 __ Move(src, dst);
1793 __ Move(dst, temp);
1794 } else {
1795 DCHECK(destination->IsStackSlot());
1796 MemOperand dst = g.ToMemOperand(destination);
1797 __ mov(temp, src);
1798 __ lw(src, dst);
1799 __ sw(temp, dst);
1800 }
1801 } else if (source->IsStackSlot()) {
1802 DCHECK(destination->IsStackSlot());
1803 Register temp_0 = kScratchReg;
1804 Register temp_1 = kCompareReg;
1805 MemOperand src = g.ToMemOperand(source);
1806 MemOperand dst = g.ToMemOperand(destination);
1807 __ lw(temp_0, src);
1808 __ lw(temp_1, dst);
1809 __ sw(temp_0, dst);
1810 __ sw(temp_1, src);
1811 } else if (source->IsDoubleRegister()) {
1812 FPURegister temp = kScratchDoubleReg;
1813 FPURegister src = g.ToDoubleRegister(source);
1814 if (destination->IsDoubleRegister()) {
1815 FPURegister dst = g.ToDoubleRegister(destination);
1816 __ Move(temp, src);
1817 __ Move(src, dst);
1818 __ Move(dst, temp);
1819 } else {
1820 DCHECK(destination->IsDoubleStackSlot());
1821 MemOperand dst = g.ToMemOperand(destination);
1822 __ Move(temp, src);
1823 __ ldc1(src, dst);
1824 __ sdc1(temp, dst);
1825 }
1826 } else if (source->IsDoubleStackSlot()) {
1827 DCHECK(destination->IsDoubleStackSlot());
1828 Register temp_0 = kScratchReg;
1829 FPURegister temp_1 = kScratchDoubleReg;
1830 MemOperand src0 = g.ToMemOperand(source);
Ben Murdoch014dc512016-03-22 12:00:34 +00001831 MemOperand src1(src0.rm(), src0.offset() + kIntSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001832 MemOperand dst0 = g.ToMemOperand(destination);
Ben Murdoch014dc512016-03-22 12:00:34 +00001833 MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
Emily Bernier958fae72015-03-24 16:35:39 -04001834 __ ldc1(temp_1, dst0); // Save destination in temp_1.
1835 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination.
1836 __ sw(temp_0, dst0);
1837 __ lw(temp_0, src1);
1838 __ sw(temp_0, dst1);
1839 __ sdc1(temp_1, src0);
1840 } else {
1841 // No other combinations are possible.
1842 UNREACHABLE();
1843 }
1844}
1845
1846
Ben Murdoch014dc512016-03-22 12:00:34 +00001847void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1848 // On 32-bit MIPS we emit the jump tables inline.
1849 UNREACHABLE();
1850}
1851
1852
Emily Bernier958fae72015-03-24 16:35:39 -04001853void CodeGenerator::AddNopForSmiCodeInlining() {
1854 // Unused on 32-bit ARM. Still exists on 64-bit arm.
1855 // TODO(plind): Unclear when this is called now. Understand, fix if needed.
1856 __ nop(); // Maybe PROPERTY_ACCESS_INLINED?
1857}
1858
1859
1860void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch014dc512016-03-22 12:00:34 +00001861 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1862 return;
1863 }
1864
Emily Bernier958fae72015-03-24 16:35:39 -04001865 int space_needed = Deoptimizer::patch_size();
Ben Murdoch014dc512016-03-22 12:00:34 +00001866 // Ensure that we have enough space after the previous lazy-bailout
1867 // instruction for patching the code here.
1868 int current_pc = masm()->pc_offset();
1869 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1870 // Block tramoline pool emission for duration of padding.
1871 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
1872 masm());
1873 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1874 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1875 while (padding_size > 0) {
1876 __ nop();
1877 padding_size -= v8::internal::Assembler::kInstrSize;
Emily Bernier958fae72015-03-24 16:35:39 -04001878 }
1879 }
Emily Bernier958fae72015-03-24 16:35:39 -04001880}
1881
1882#undef __
1883
1884} // namespace compiler
1885} // namespace internal
1886} // namespace v8