Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: runtime/vm/assembler_mips.h

Issue 2858623002: Remove MIPS support (Closed)
Patch Set: Rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #ifndef RUNTIME_VM_ASSEMBLER_MIPS_H_
6 #define RUNTIME_VM_ASSEMBLER_MIPS_H_
7
8 #ifndef RUNTIME_VM_ASSEMBLER_H_
9 #error Do not include assembler_mips.h directly; use assembler.h instead.
10 #endif
11
12 #include "platform/assert.h"
13 #include "platform/utils.h"
14 #include "vm/constants_mips.h"
15 #include "vm/hash_map.h"
16 #include "vm/object.h"
17 #include "vm/simulator.h"
18
19 // References to documentation in this file refer to:
20 // "MIPS® Architecture For Programmers Volume I-A:
21 // Introduction to the MIPS32® Architecture" in short "VolI-A"
22 // and
23 // "MIPS® Architecture For Programmers Volume II-A:
24 // The MIPS32® Instruction Set" in short "VolII-A"
25 namespace dart {
26
27 // Forward declarations.
28 class RuntimeEntry;
29 class StubEntry;
30
31 class Immediate : public ValueObject {
32 public:
33 explicit Immediate(int32_t value) : value_(value) {}
34
35 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) {}
36 Immediate& operator=(const Immediate& other) {
37 value_ = other.value_;
38 return *this;
39 }
40
41 private:
42 int32_t value_;
43
44 int32_t value() const { return value_; }
45
46 friend class Assembler;
47 };
48
49
50 class Address : public ValueObject {
51 public:
52 explicit Address(Register base, int32_t offset = 0)
53 : ValueObject(), base_(base), offset_(offset) {}
54
55 // This addressing mode does not exist.
56 Address(Register base, Register offset);
57
58 Address(const Address& other)
59 : ValueObject(), base_(other.base_), offset_(other.offset_) {}
60 Address& operator=(const Address& other) {
61 base_ = other.base_;
62 offset_ = other.offset_;
63 return *this;
64 }
65
66 uint32_t encoding() const {
67 ASSERT(Utils::IsInt(kImmBits, offset_));
68 uint16_t imm_value = static_cast<uint16_t>(offset_);
69 return (base_ << kRsShift) | imm_value;
70 }
71
72 static bool CanHoldOffset(int32_t offset) {
73 return Utils::IsInt(kImmBits, offset);
74 }
75
76 Register base() const { return base_; }
77 int32_t offset() const { return offset_; }
78
79 private:
80 Register base_;
81 int32_t offset_;
82 };
83
84
85 class FieldAddress : public Address {
86 public:
87 FieldAddress(Register base, int32_t disp)
88 : Address(base, disp - kHeapObjectTag) {}
89
90 FieldAddress(const FieldAddress& other) : Address(other) {}
91
92 FieldAddress& operator=(const FieldAddress& other) {
93 Address::operator=(other);
94 return *this;
95 }
96 };
97
98
99 class Label : public ValueObject {
100 public:
101 Label() : position_(0) {}
102
103 ~Label() {
104 // Assert if label is being destroyed with unresolved branches pending.
105 ASSERT(!IsLinked());
106 }
107
108 // Returns the position for bound and linked labels. Cannot be used
109 // for unused labels.
110 intptr_t Position() const {
111 ASSERT(!IsUnused());
112 return IsBound() ? -position_ - kWordSize : position_ - kWordSize;
113 }
114
115 bool IsBound() const { return position_ < 0; }
116 bool IsUnused() const { return position_ == 0; }
117 bool IsLinked() const { return position_ > 0; }
118
119 private:
120 intptr_t position_;
121
122 void Reinitialize() { position_ = 0; }
123
124 void BindTo(intptr_t position) {
125 ASSERT(!IsBound());
126 position_ = -position - kWordSize;
127 ASSERT(IsBound());
128 }
129
130 void LinkTo(intptr_t position) {
131 ASSERT(!IsBound());
132 position_ = position + kWordSize;
133 ASSERT(IsLinked());
134 }
135
136 friend class Assembler;
137 DISALLOW_COPY_AND_ASSIGN(Label);
138 };
139
140
141 // There is no dedicated status register on MIPS, but Condition values are used
142 // and passed around by the intermediate language, so we need a Condition type.
143 // We delay code generation of a comparison that would result in a traditional
144 // condition code in the status register by keeping both register operands and
145 // the relational operator between them as the Condition.
146 class Condition : public ValueObject {
147 public:
148 enum Bits {
149 kLeftPos = 0,
150 kLeftSize = 6,
151 kRightPos = kLeftPos + kLeftSize,
152 kRightSize = 6,
153 kRelOpPos = kRightPos + kRightSize,
154 kRelOpSize = 4,
155 kImmPos = kRelOpPos + kRelOpSize,
156 kImmSize = 16,
157 };
158
159 class LeftBits : public BitField<uword, Register, kLeftPos, kLeftSize> {};
160 class RightBits : public BitField<uword, Register, kRightPos, kRightSize> {};
161 class RelOpBits
162 : public BitField<uword, RelationOperator, kRelOpPos, kRelOpSize> {};
163 class ImmBits : public BitField<uword, uint16_t, kImmPos, kImmSize> {};
164
165 Register left() const { return LeftBits::decode(bits_); }
166 Register right() const { return RightBits::decode(bits_); }
167 RelationOperator rel_op() const { return RelOpBits::decode(bits_); }
168 int16_t imm() const { return static_cast<int16_t>(ImmBits::decode(bits_)); }
169
170 static bool IsValidImm(int32_t value) {
171 // We want both value and value + 1 to fit in an int16_t.
172 return (-0x08000 <= value) && (value < 0x7fff);
173 }
174
175 void set_rel_op(RelationOperator value) {
176 ASSERT(IsValidRelOp(value));
177 bits_ = RelOpBits::update(value, bits_);
178 }
179
180 // Uninitialized condition.
181 Condition() : ValueObject(), bits_(0) {}
182
183 // Copy constructor.
184 Condition(const Condition& other) : ValueObject(), bits_(other.bits_) {}
185
186 // Copy assignment operator.
187 Condition& operator=(const Condition& other) {
188 bits_ = other.bits_;
189 return *this;
190 }
191
192 Condition(Register left,
193 Register right,
194 RelationOperator rel_op,
195 int16_t imm = 0) {
196 // At most one constant, ZR or immediate.
197 ASSERT(!(((left == ZR) || (left == IMM)) &&
198 ((right == ZR) || (right == IMM))));
199 // Non-zero immediate value is only allowed for IMM.
200 ASSERT((imm != 0) == ((left == IMM) || (right == IMM)));
201 set_left(left);
202 set_right(right);
203 set_rel_op(rel_op);
204 set_imm(imm);
205 }
206
207 private:
208 static bool IsValidRelOp(RelationOperator value) {
209 return (AL <= value) && (value <= ULE);
210 }
211
212 static bool IsValidRegister(Register value) {
213 return (ZR <= value) && (value <= IMM) && (value != AT);
214 }
215
216 void set_left(Register value) {
217 ASSERT(IsValidRegister(value));
218 bits_ = LeftBits::update(value, bits_);
219 }
220
221 void set_right(Register value) {
222 ASSERT(IsValidRegister(value));
223 bits_ = RightBits::update(value, bits_);
224 }
225
226 void set_imm(int16_t value) {
227 ASSERT(IsValidImm(value));
228 bits_ = ImmBits::update(static_cast<uint16_t>(value), bits_);
229 }
230
231 uword bits_;
232 };
233
234
235 class Assembler : public ValueObject {
236 public:
237 explicit Assembler(bool use_far_branches = false)
238 : buffer_(),
239 prologue_offset_(-1),
240 has_single_entry_point_(true),
241 use_far_branches_(use_far_branches),
242 delay_slot_available_(false),
243 in_delay_slot_(false),
244 comments_(),
245 constant_pool_allowed_(true) {}
246 ~Assembler() {}
247
248 void PopRegister(Register r) { Pop(r); }
249
250 void Bind(Label* label);
251 void Jump(Label* label) { b(label); }
252
253 // Misc. functionality
254 intptr_t CodeSize() const { return buffer_.Size(); }
255 intptr_t prologue_offset() const { return prologue_offset_; }
256 bool has_single_entry_point() const { return has_single_entry_point_; }
257
258 // Count the fixups that produce a pointer offset, without processing
259 // the fixups.
260 intptr_t CountPointerOffsets() const { return buffer_.CountPointerOffsets(); }
261
262 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const {
263 return buffer_.pointer_offsets();
264 }
265
266 ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; }
267
268 RawObjectPool* MakeObjectPool() {
269 return object_pool_wrapper_.MakeObjectPool();
270 }
271
272 void FinalizeInstructions(const MemoryRegion& region) {
273 buffer_.FinalizeInstructions(region);
274 }
275
276 bool use_far_branches() const {
277 return FLAG_use_far_branches || use_far_branches_;
278 }
279
280 void set_use_far_branches(bool b) { use_far_branches_ = b; }
281
282 void EnterFrame();
283 void LeaveFrameAndReturn();
284
285 // Set up a stub frame so that the stack traversal code can easily identify
286 // a stub frame.
287 void EnterStubFrame(intptr_t frame_size = 0);
288 void LeaveStubFrame();
289 // A separate macro for when a Ret immediately follows, so that we can use
290 // the branch delay slot.
291 void LeaveStubFrameAndReturn(Register ra = RA);
292
293 void MonomorphicCheckedEntry();
294
295 void UpdateAllocationStats(intptr_t cid,
296 Register temp_reg,
297 Heap::Space space);
298
299 void UpdateAllocationStatsWithSize(intptr_t cid,
300 Register size_reg,
301 Register temp_reg,
302 Heap::Space space);
303
304
305 void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace);
306
307 // Inlined allocation of an instance of class 'cls', code has no runtime
308 // calls. Jump to 'failure' if the instance cannot be allocated here.
309 // Allocated instance is returned in 'instance_reg'.
310 // Only the tags field of the object is initialized.
311 void TryAllocate(const Class& cls,
312 Label* failure,
313 Register instance_reg,
314 Register temp_reg);
315
316 void TryAllocateArray(intptr_t cid,
317 intptr_t instance_size,
318 Label* failure,
319 Register instance,
320 Register end_address,
321 Register temp1,
322 Register temp2);
323
324 // Debugging and bringup support.
325 void Stop(const char* message);
326 void Unimplemented(const char* message);
327 void Untested(const char* message);
328 void Unreachable(const char* message);
329
330 static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
331
332 void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
333 static bool EmittingComments();
334
335 const Code::Comments& GetCodeComments() const;
336
337 static const char* RegisterName(Register reg);
338
339 static const char* FpuRegisterName(FpuRegister reg);
340
341 void SetPrologueOffset() {
342 if (prologue_offset_ == -1) {
343 prologue_offset_ = CodeSize();
344 }
345 }
346
347 // A utility to be able to assemble an instruction into the delay slot.
348 Assembler* delay_slot() {
349 ASSERT(delay_slot_available_);
350 ASSERT(buffer_.Load<int32_t>(buffer_.GetPosition() - sizeof(int32_t)) ==
351 Instr::kNopInstruction);
352 buffer_.Remit<int32_t>();
353 delay_slot_available_ = false;
354 in_delay_slot_ = true;
355 return this;
356 }
357
358 // CPU instructions in alphabetical order.
359 void addd(DRegister dd, DRegister ds, DRegister dt) {
360 // DRegisters start at the even FRegisters.
361 FRegister fd = static_cast<FRegister>(dd * 2);
362 FRegister fs = static_cast<FRegister>(ds * 2);
363 FRegister ft = static_cast<FRegister>(dt * 2);
364 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_ADD);
365 }
366
367 void addiu(Register rt, Register rs, const Immediate& imm) {
368 ASSERT(Utils::IsInt(kImmBits, imm.value()));
369 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
370 EmitIType(ADDIU, rs, rt, imm_value);
371 }
372
373 void addu(Register rd, Register rs, Register rt) {
374 EmitRType(SPECIAL, rs, rt, rd, 0, ADDU);
375 }
376
377 void and_(Register rd, Register rs, Register rt) {
378 EmitRType(SPECIAL, rs, rt, rd, 0, AND);
379 }
380
381 void andi(Register rt, Register rs, const Immediate& imm) {
382 ASSERT(Utils::IsUint(kImmBits, imm.value()));
383 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
384 EmitIType(ANDI, rs, rt, imm_value);
385 }
386
387 // Unconditional branch.
388 void b(Label* l) { beq(R0, R0, l); }
389
390 void bal(Label* l) {
391 ASSERT(!in_delay_slot_);
392 EmitRegImmBranch(BGEZAL, R0, l);
393 EmitBranchDelayNop();
394 }
395
396 // Branch on floating point false.
397 void bc1f(Label* l) {
398 EmitFpuBranch(false, l);
399 EmitBranchDelayNop();
400 }
401
402 // Branch on floating point true.
403 void bc1t(Label* l) {
404 EmitFpuBranch(true, l);
405 EmitBranchDelayNop();
406 }
407
408 // Branch if equal.
409 void beq(Register rs, Register rt, Label* l) {
410 ASSERT(!in_delay_slot_);
411 EmitBranch(BEQ, rs, rt, l);
412 EmitBranchDelayNop();
413 }
414
415 // Branch if equal, likely taken.
416 // Delay slot executed only when branch taken.
417 void beql(Register rs, Register rt, Label* l) {
418 ASSERT(!in_delay_slot_);
419 EmitBranch(BEQL, rs, rt, l);
420 EmitBranchDelayNop();
421 }
422
423 // Branch if rs >= 0.
424 void bgez(Register rs, Label* l) {
425 ASSERT(!in_delay_slot_);
426 EmitRegImmBranch(BGEZ, rs, l);
427 EmitBranchDelayNop();
428 }
429
430 // Branch if rs >= 0, likely taken.
431 // Delay slot executed only when branch taken.
432 void bgezl(Register rs, Label* l) {
433 ASSERT(!in_delay_slot_);
434 EmitRegImmBranch(BGEZL, rs, l);
435 EmitBranchDelayNop();
436 }
437
438 // Branch if rs > 0.
439 void bgtz(Register rs, Label* l) {
440 ASSERT(!in_delay_slot_);
441 EmitBranch(BGTZ, rs, R0, l);
442 EmitBranchDelayNop();
443 }
444
445 // Branch if rs > 0, likely taken.
446 // Delay slot executed only when branch taken.
447 void bgtzl(Register rs, Label* l) {
448 ASSERT(!in_delay_slot_);
449 EmitBranch(BGTZL, rs, R0, l);
450 EmitBranchDelayNop();
451 }
452
453 // Branch if rs <= 0.
454 void blez(Register rs, Label* l) {
455 ASSERT(!in_delay_slot_);
456 EmitBranch(BLEZ, rs, R0, l);
457 EmitBranchDelayNop();
458 }
459
460 // Branch if rs <= 0, likely taken.
461 // Delay slot executed only when branch taken.
462 void blezl(Register rs, Label* l) {
463 ASSERT(!in_delay_slot_);
464 EmitBranch(BLEZL, rs, R0, l);
465 EmitBranchDelayNop();
466 }
467
468 // Branch if rs < 0.
469 void bltz(Register rs, Label* l) {
470 ASSERT(!in_delay_slot_);
471 EmitRegImmBranch(BLTZ, rs, l);
472 EmitBranchDelayNop();
473 }
474
475 // Branch if rs < 0, likely taken.
476 // Delay slot executed only when branch taken.
477 void bltzl(Register rs, Label* l) {
478 ASSERT(!in_delay_slot_);
479 EmitRegImmBranch(BLTZL, rs, l);
480 EmitBranchDelayNop();
481 }
482
483 // Branch if not equal.
484 void bne(Register rs, Register rt, Label* l) {
485 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
486 EmitBranch(BNE, rs, rt, l);
487 EmitBranchDelayNop();
488 }
489
490 // Branch if not equal, likely taken.
491 // Delay slot executed only when branch taken.
492 void bnel(Register rs, Register rt, Label* l) {
493 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
494 EmitBranch(BNEL, rs, rt, l);
495 EmitBranchDelayNop();
496 }
497
498 static int32_t BreakEncoding(int32_t code) {
499 ASSERT(Utils::IsUint(20, code));
500 return SPECIAL << kOpcodeShift | code << kBreakCodeShift |
501 BREAK << kFunctionShift;
502 }
503
504
505 void break_(int32_t code) { Emit(BreakEncoding(code)); }
506
507 static uword GetBreakInstructionFiller() { return BreakEncoding(0); }
508
509 // FPU compare, always false.
510 void cfd(DRegister ds, DRegister dt) {
511 FRegister fs = static_cast<FRegister>(ds * 2);
512 FRegister ft = static_cast<FRegister>(dt * 2);
513 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_F);
514 }
515
516 // FPU compare, true if unordered, i.e. one is NaN.
517 void cund(DRegister ds, DRegister dt) {
518 FRegister fs = static_cast<FRegister>(ds * 2);
519 FRegister ft = static_cast<FRegister>(dt * 2);
520 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UN);
521 }
522
523 // FPU compare, true if equal.
524 void ceqd(DRegister ds, DRegister dt) {
525 FRegister fs = static_cast<FRegister>(ds * 2);
526 FRegister ft = static_cast<FRegister>(dt * 2);
527 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_EQ);
528 }
529
530 // FPU compare, true if unordered or equal.
531 void cueqd(DRegister ds, DRegister dt) {
532 FRegister fs = static_cast<FRegister>(ds * 2);
533 FRegister ft = static_cast<FRegister>(dt * 2);
534 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UEQ);
535 }
536
537 // FPU compare, true if less than.
538 void coltd(DRegister ds, DRegister dt) {
539 FRegister fs = static_cast<FRegister>(ds * 2);
540 FRegister ft = static_cast<FRegister>(dt * 2);
541 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLT);
542 }
543
544 // FPU compare, true if unordered or less than.
545 void cultd(DRegister ds, DRegister dt) {
546 FRegister fs = static_cast<FRegister>(ds * 2);
547 FRegister ft = static_cast<FRegister>(dt * 2);
548 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULT);
549 }
550
551 // FPU compare, true if less or equal.
552 void coled(DRegister ds, DRegister dt) {
553 FRegister fs = static_cast<FRegister>(ds * 2);
554 FRegister ft = static_cast<FRegister>(dt * 2);
555 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLE);
556 }
557
558 // FPU compare, true if unordered or less or equal.
559 void culed(DRegister ds, DRegister dt) {
560 FRegister fs = static_cast<FRegister>(ds * 2);
561 FRegister ft = static_cast<FRegister>(dt * 2);
562 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULE);
563 }
564
565 void clo(Register rd, Register rs) {
566 EmitRType(SPECIAL2, rs, rd, rd, 0, CLO);
567 }
568
569 void clz(Register rd, Register rs) {
570 EmitRType(SPECIAL2, rs, rd, rd, 0, CLZ);
571 }
572
573 // Convert a double in ds to a 32-bit signed int in fd rounding towards 0.
574 void truncwd(FRegister fd, DRegister ds) {
575 FRegister fs = static_cast<FRegister>(ds * 2);
576 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_TRUNC_W);
577 }
578
579 // Convert a 32-bit float in fs to a 64-bit double in dd.
580 void cvtds(DRegister dd, FRegister fs) {
581 FRegister fd = static_cast<FRegister>(dd * 2);
582 EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_CVT_D);
583 }
584
585 // Converts a 32-bit signed int in fs to a double in fd.
586 void cvtdw(DRegister dd, FRegister fs) {
587 FRegister fd = static_cast<FRegister>(dd * 2);
588 EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D);
589 }
590
591 // Convert a 64-bit double in ds to a 32-bit float in fd.
592 void cvtsd(FRegister fd, DRegister ds) {
593 FRegister fs = static_cast<FRegister>(ds * 2);
594 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S);
595 }
596
597 void div(Register rs, Register rt) { EmitRType(SPECIAL, rs, rt, R0, 0, DIV); }
598
599 void divd(DRegister dd, DRegister ds, DRegister dt) {
600 FRegister fd = static_cast<FRegister>(dd * 2);
601 FRegister fs = static_cast<FRegister>(ds * 2);
602 FRegister ft = static_cast<FRegister>(dt * 2);
603 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_DIV);
604 }
605
606 void divu(Register rs, Register rt) {
607 EmitRType(SPECIAL, rs, rt, R0, 0, DIVU);
608 }
609
610 void jalr(Register rs, Register rd = RA) {
611 ASSERT(rs != rd);
612 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
613 EmitRType(SPECIAL, rs, R0, rd, 0, JALR);
614 EmitBranchDelayNop();
615 }
616
617 void jr(Register rs) {
618 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
619 EmitRType(SPECIAL, rs, R0, R0, 0, JR);
620 EmitBranchDelayNop();
621 }
622
623 void lb(Register rt, const Address& addr) { EmitLoadStore(LB, rt, addr); }
624
625 void lbu(Register rt, const Address& addr) { EmitLoadStore(LBU, rt, addr); }
626
627 void ldc1(DRegister dt, const Address& addr) {
628 FRegister ft = static_cast<FRegister>(dt * 2);
629 EmitFpuLoadStore(LDC1, ft, addr);
630 }
631
632 void lh(Register rt, const Address& addr) { EmitLoadStore(LH, rt, addr); }
633
634 void lhu(Register rt, const Address& addr) { EmitLoadStore(LHU, rt, addr); }
635
636 void ll(Register rt, const Address& addr) { EmitLoadStore(LL, rt, addr); }
637
638 void lui(Register rt, const Immediate& imm) {
639 ASSERT(Utils::IsUint(kImmBits, imm.value()));
640 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
641 EmitIType(LUI, R0, rt, imm_value);
642 }
643
644 void lw(Register rt, const Address& addr) { EmitLoadStore(LW, rt, addr); }
645
646 void lwc1(FRegister ft, const Address& addr) {
647 EmitFpuLoadStore(LWC1, ft, addr);
648 }
649
650 void madd(Register rs, Register rt) {
651 EmitRType(SPECIAL2, rs, rt, R0, 0, MADD);
652 }
653
654 void maddu(Register rs, Register rt) {
655 EmitRType(SPECIAL2, rs, rt, R0, 0, MADDU);
656 }
657
658 void mfc1(Register rt, FRegister fs) {
659 Emit(COP1 << kOpcodeShift | COP1_MF << kCop1SubShift | rt << kRtShift |
660 fs << kFsShift);
661 }
662
663 void mfhi(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFHI); }
664
665 void mflo(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFLO); }
666
667 void mov(Register rd, Register rs) { or_(rd, rs, ZR); }
668
669 void movd(DRegister dd, DRegister ds) {
670 FRegister fd = static_cast<FRegister>(dd * 2);
671 FRegister fs = static_cast<FRegister>(ds * 2);
672 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV);
673 }
674
675 // Move if floating point false.
676 void movf(Register rd, Register rs) {
677 EmitRType(SPECIAL, rs, R0, rd, 0, MOVCI);
678 }
679
680 void movn(Register rd, Register rs, Register rt) {
681 EmitRType(SPECIAL, rs, rt, rd, 0, MOVN);
682 }
683
684 // Move if floating point true.
685 void movt(Register rd, Register rs) {
686 EmitRType(SPECIAL, rs, R1, rd, 0, MOVCI);
687 }
688
689 // rd <- (rt == 0) ? rs : rd;
690 void movz(Register rd, Register rs, Register rt) {
691 EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ);
692 }
693
694 void movs(FRegister fd, FRegister fs) {
695 EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_MOV);
696 }
697
698 void mtc1(Register rt, FRegister fs) {
699 Emit(COP1 << kOpcodeShift | COP1_MT << kCop1SubShift | rt << kRtShift |
700 fs << kFsShift);
701 }
702
703 void mthi(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTHI); }
704
705 void mtlo(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTLO); }
706
707 void muld(DRegister dd, DRegister ds, DRegister dt) {
708 FRegister fd = static_cast<FRegister>(dd * 2);
709 FRegister fs = static_cast<FRegister>(ds * 2);
710 FRegister ft = static_cast<FRegister>(dt * 2);
711 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_MUL);
712 }
713
714 void mult(Register rs, Register rt) {
715 EmitRType(SPECIAL, rs, rt, R0, 0, MULT);
716 }
717
718 void multu(Register rs, Register rt) {
719 EmitRType(SPECIAL, rs, rt, R0, 0, MULTU);
720 }
721
722 void negd(DRegister dd, DRegister ds) {
723 FRegister fd = static_cast<FRegister>(dd * 2);
724 FRegister fs = static_cast<FRegister>(ds * 2);
725 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_NEG);
726 }
727
728 void nop() { Emit(Instr::kNopInstruction); }
729
730 void nor(Register rd, Register rs, Register rt) {
731 EmitRType(SPECIAL, rs, rt, rd, 0, NOR);
732 }
733
734 void or_(Register rd, Register rs, Register rt) {
735 EmitRType(SPECIAL, rs, rt, rd, 0, OR);
736 }
737
738 void ori(Register rt, Register rs, const Immediate& imm) {
739 ASSERT(Utils::IsUint(kImmBits, imm.value()));
740 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
741 EmitIType(ORI, rs, rt, imm_value);
742 }
743
744 void sb(Register rt, const Address& addr) { EmitLoadStore(SB, rt, addr); }
745
746 // rt = 1 on success, 0 on failure.
747 void sc(Register rt, const Address& addr) { EmitLoadStore(SC, rt, addr); }
748
749 void sdc1(DRegister dt, const Address& addr) {
750 FRegister ft = static_cast<FRegister>(dt * 2);
751 EmitFpuLoadStore(SDC1, ft, addr);
752 }
753
754 void sh(Register rt, const Address& addr) { EmitLoadStore(SH, rt, addr); }
755
756 void sll(Register rd, Register rt, int sa) {
757 EmitRType(SPECIAL, R0, rt, rd, sa, SLL);
758 }
759
760 void sllv(Register rd, Register rt, Register rs) {
761 EmitRType(SPECIAL, rs, rt, rd, 0, SLLV);
762 }
763
764 void slt(Register rd, Register rs, Register rt) {
765 EmitRType(SPECIAL, rs, rt, rd, 0, SLT);
766 }
767
768 void slti(Register rt, Register rs, const Immediate& imm) {
769 ASSERT(Utils::IsInt(kImmBits, imm.value()));
770 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
771 EmitIType(SLTI, rs, rt, imm_value);
772 }
773
774 // Although imm argument is int32_t, it is interpreted as an uint32_t.
775 // For example, -1 stands for 0xffffffffUL: it is encoded as 0xffff in the
776 // instruction imm field and is then sign extended back to 0xffffffffUL.
777 void sltiu(Register rt, Register rs, const Immediate& imm) {
778 ASSERT(Utils::IsInt(kImmBits, imm.value()));
779 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
780 EmitIType(SLTIU, rs, rt, imm_value);
781 }
782
783 void sltu(Register rd, Register rs, Register rt) {
784 EmitRType(SPECIAL, rs, rt, rd, 0, SLTU);
785 }
786
787 void sqrtd(DRegister dd, DRegister ds) {
788 FRegister fd = static_cast<FRegister>(dd * 2);
789 FRegister fs = static_cast<FRegister>(ds * 2);
790 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_SQRT);
791 }
792
793 void sra(Register rd, Register rt, int sa) {
794 EmitRType(SPECIAL, R0, rt, rd, sa, SRA);
795 }
796
797 void srav(Register rd, Register rt, Register rs) {
798 EmitRType(SPECIAL, rs, rt, rd, 0, SRAV);
799 }
800
801 void srl(Register rd, Register rt, int sa) {
802 EmitRType(SPECIAL, R0, rt, rd, sa, SRL);
803 }
804
805 void srlv(Register rd, Register rt, Register rs) {
806 EmitRType(SPECIAL, rs, rt, rd, 0, SRLV);
807 }
808
809 void subd(DRegister dd, DRegister ds, DRegister dt) {
810 FRegister fd = static_cast<FRegister>(dd * 2);
811 FRegister fs = static_cast<FRegister>(ds * 2);
812 FRegister ft = static_cast<FRegister>(dt * 2);
813 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_SUB);
814 }
815
816 void subu(Register rd, Register rs, Register rt) {
817 EmitRType(SPECIAL, rs, rt, rd, 0, SUBU);
818 }
819
820 void sw(Register rt, const Address& addr) { EmitLoadStore(SW, rt, addr); }
821
822 void swc1(FRegister ft, const Address& addr) {
823 EmitFpuLoadStore(SWC1, ft, addr);
824 }
825
826 void xori(Register rt, Register rs, const Immediate& imm) {
827 ASSERT(Utils::IsUint(kImmBits, imm.value()));
828 const uint16_t imm_value = static_cast<uint16_t>(imm.value());
829 EmitIType(XORI, rs, rt, imm_value);
830 }
831
832 void xor_(Register rd, Register rs, Register rt) {
833 EmitRType(SPECIAL, rs, rt, rd, 0, XOR);
834 }
835
836 // Macros in alphabetical order.
837
838 // Addition of rs and rt with the result placed in rd.
839 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise.
840 // rd and ro must not be TMP.
841 // ro must be different from all the other registers.
842 // If rd, rs, and rt are the same register, then a scratch register different
843 // from the other registers is needed.
844 void AdduDetectOverflow(Register rd,
845 Register rs,
846 Register rt,
847 Register ro,
848 Register scratch = kNoRegister);
849
850 // ro must be different from rd and rs.
851 // rd and ro must not be TMP.
852 // If rd and rs are the same, a scratch register different from the other
853 // registers is needed.
854 void AddImmediateDetectOverflow(Register rd,
855 Register rs,
856 int32_t imm,
857 Register ro,
858 Register scratch = kNoRegister) {
859 ASSERT(!in_delay_slot_);
860 LoadImmediate(rd, imm);
861 AdduDetectOverflow(rd, rs, rd, ro, scratch);
862 }
863
864 // Subtraction of rt from rs (rs - rt) with the result placed in rd.
865 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise.
866 // None of rd, rs, rt, or ro may be TMP.
867 // ro must be different from the other registers.
868 void SubuDetectOverflow(Register rd, Register rs, Register rt, Register ro);
869
870 // ro must be different from rd and rs.
871 // None of rd, rs, rt, or ro may be TMP.
872 void SubImmediateDetectOverflow(Register rd,
873 Register rs,
874 int32_t imm,
875 Register ro) {
876 ASSERT(!in_delay_slot_);
877 LoadImmediate(rd, imm);
878 SubuDetectOverflow(rd, rs, rd, ro);
879 }
880
881 void Branch(const StubEntry& stub_entry, Register pp = PP);
882
883 void BranchLink(const StubEntry& stub_entry,
884 Patchability patchable = kNotPatchable);
885
886 void BranchLinkPatchable(const StubEntry& stub_entry);
887 void BranchLinkToRuntime();
888
889 // Emit a call that shares its object pool entries with other calls
890 // that have the same equivalence marker.
891 void BranchLinkWithEquivalence(const StubEntry& stub_entry,
892 const Object& equivalence);
893
894 void Drop(intptr_t stack_elements) {
895 ASSERT(stack_elements >= 0);
896 if (stack_elements > 0) {
897 addiu(SP, SP, Immediate(stack_elements * kWordSize));
898 }
899 }
900
901 void LoadPoolPointer(Register reg = PP) {
902 ASSERT(!in_delay_slot_);
903 CheckCodePointer();
904 lw(reg, FieldAddress(CODE_REG, Code::object_pool_offset()));
905 set_constant_pool_allowed(reg == PP);
906 }
907
908 void CheckCodePointer();
909
910 void RestoreCodePointer();
911
912 void LoadImmediate(Register rd, int32_t value) {
913 ASSERT(!in_delay_slot_);
914 if (Utils::IsInt(kImmBits, value)) {
915 addiu(rd, ZR, Immediate(value));
916 } else {
917 const uint16_t low = Utils::Low16Bits(value);
918 const uint16_t high = Utils::High16Bits(value);
919 lui(rd, Immediate(high));
920 if (low != 0) {
921 ori(rd, rd, Immediate(low));
922 }
923 }
924 }
925
926 void LoadImmediate(DRegister rd, double value) {
927 ASSERT(!in_delay_slot_);
928 FRegister frd = static_cast<FRegister>(rd * 2);
929 const int64_t ival = bit_cast<uint64_t, double>(value);
930 const int32_t low = Utils::Low32Bits(ival);
931 const int32_t high = Utils::High32Bits(ival);
932 if (low != 0) {
933 LoadImmediate(TMP, low);
934 mtc1(TMP, frd);
935 } else {
936 mtc1(ZR, frd);
937 }
938
939 if (high != 0) {
940 LoadImmediate(TMP, high);
941 mtc1(TMP, static_cast<FRegister>(frd + 1));
942 } else {
943 mtc1(ZR, static_cast<FRegister>(frd + 1));
944 }
945 }
946
947 void LoadImmediate(FRegister rd, float value) {
948 ASSERT(!in_delay_slot_);
949 const int32_t ival = bit_cast<int32_t, float>(value);
950 if (ival == 0) {
951 mtc1(ZR, rd);
952 } else {
953 LoadImmediate(TMP, ival);
954 mtc1(TMP, rd);
955 }
956 }
957
958 void AddImmediate(Register rd, Register rs, int32_t value) {
959 ASSERT(!in_delay_slot_);
960 if ((value == 0) && (rd == rs)) return;
961 // If value is 0, we still want to move rs to rd if they aren't the same.
962 if (Utils::IsInt(kImmBits, value)) {
963 addiu(rd, rs, Immediate(value));
964 } else {
965 LoadImmediate(TMP, value);
966 addu(rd, rs, TMP);
967 }
968 }
969
970 void AddImmediate(Register rd, int32_t value) {
971 ASSERT(!in_delay_slot_);
972 AddImmediate(rd, rd, value);
973 }
974
975 void AndImmediate(Register rd, Register rs, int32_t imm) {
976 ASSERT(!in_delay_slot_);
977 if (imm == 0) {
978 mov(rd, ZR);
979 return;
980 }
981
982 if (Utils::IsUint(kImmBits, imm)) {
983 andi(rd, rs, Immediate(imm));
984 } else {
985 LoadImmediate(TMP, imm);
986 and_(rd, rs, TMP);
987 }
988 }
989
990 void OrImmediate(Register rd, Register rs, int32_t imm) {
991 ASSERT(!in_delay_slot_);
992 if (imm == 0) {
993 mov(rd, rs);
994 return;
995 }
996
997 if (Utils::IsUint(kImmBits, imm)) {
998 ori(rd, rs, Immediate(imm));
999 } else {
1000 LoadImmediate(TMP, imm);
1001 or_(rd, rs, TMP);
1002 }
1003 }
1004
1005 void XorImmediate(Register rd, Register rs, int32_t imm) {
1006 ASSERT(!in_delay_slot_);
1007 if (imm == 0) {
1008 mov(rd, rs);
1009 return;
1010 }
1011
1012 if (Utils::IsUint(kImmBits, imm)) {
1013 xori(rd, rs, Immediate(imm));
1014 } else {
1015 LoadImmediate(TMP, imm);
1016 xor_(rd, rs, TMP);
1017 }
1018 }
1019
1020 Register LoadConditionOperand(Register rd,
1021 const Object& operand,
1022 int16_t* imm) {
1023 if (operand.IsSmi()) {
1024 const int32_t val = reinterpret_cast<int32_t>(operand.raw());
1025 if (val == 0) {
1026 return ZR;
1027 } else if (Condition::IsValidImm(val)) {
1028 ASSERT(*imm == 0);
1029 *imm = val;
1030 return IMM;
1031 }
1032 }
1033 LoadObject(rd, operand);
1034 return rd;
1035 }
1036
1037 // Branch to label if condition is true.
1038 void BranchOnCondition(Condition cond, Label* l) {
1039 ASSERT(!in_delay_slot_);
1040 Register left = cond.left();
1041 Register right = cond.right();
1042 RelationOperator rel_op = cond.rel_op();
1043 switch (rel_op) {
1044 case NV:
1045 return;
1046 case AL:
1047 b(l);
1048 return;
1049 case EQ: // fall through.
1050 case NE: {
1051 if (left == IMM) {
1052 addiu(AT, ZR, Immediate(cond.imm()));
1053 left = AT;
1054 } else if (right == IMM) {
1055 addiu(AT, ZR, Immediate(cond.imm()));
1056 right = AT;
1057 }
1058 if (rel_op == EQ) {
1059 beq(left, right, l);
1060 } else {
1061 bne(left, right, l);
1062 }
1063 break;
1064 }
1065 case GT: {
1066 if (left == ZR) {
1067 bltz(right, l);
1068 } else if (right == ZR) {
1069 bgtz(left, l);
1070 } else if (left == IMM) {
1071 slti(AT, right, Immediate(cond.imm()));
1072 bne(AT, ZR, l);
1073 } else if (right == IMM) {
1074 slti(AT, left, Immediate(cond.imm() + 1));
1075 beq(AT, ZR, l);
1076 } else {
1077 slt(AT, right, left);
1078 bne(AT, ZR, l);
1079 }
1080 break;
1081 }
1082 case GE: {
1083 if (left == ZR) {
1084 blez(right, l);
1085 } else if (right == ZR) {
1086 bgez(left, l);
1087 } else if (left == IMM) {
1088 slti(AT, right, Immediate(cond.imm() + 1));
1089 bne(AT, ZR, l);
1090 } else if (right == IMM) {
1091 slti(AT, left, Immediate(cond.imm()));
1092 beq(AT, ZR, l);
1093 } else {
1094 slt(AT, left, right);
1095 beq(AT, ZR, l);
1096 }
1097 break;
1098 }
1099 case LT: {
1100 if (left == ZR) {
1101 bgtz(right, l);
1102 } else if (right == ZR) {
1103 bltz(left, l);
1104 } else if (left == IMM) {
1105 slti(AT, right, Immediate(cond.imm() + 1));
1106 beq(AT, ZR, l);
1107 } else if (right == IMM) {
1108 slti(AT, left, Immediate(cond.imm()));
1109 bne(AT, ZR, l);
1110 } else {
1111 slt(AT, left, right);
1112 bne(AT, ZR, l);
1113 }
1114 break;
1115 }
1116 case LE: {
1117 if (left == ZR) {
1118 bgez(right, l);
1119 } else if (right == ZR) {
1120 blez(left, l);
1121 } else if (left == IMM) {
1122 slti(AT, right, Immediate(cond.imm()));
1123 beq(AT, ZR, l);
1124 } else if (right == IMM) {
1125 slti(AT, left, Immediate(cond.imm() + 1));
1126 bne(AT, ZR, l);
1127 } else {
1128 slt(AT, right, left);
1129 beq(AT, ZR, l);
1130 }
1131 break;
1132 }
1133 case UGT: {
1134 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used.
1135 if (left == ZR) {
1136 // NV: Never branch. Fall through.
1137 } else if (right == ZR) {
1138 bne(left, ZR, l);
1139 } else {
1140 sltu(AT, right, left);
1141 bne(AT, ZR, l);
1142 }
1143 break;
1144 }
1145 case UGE: {
1146 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used.
1147 if (left == ZR) {
1148 beq(right, ZR, l);
1149 } else if (right == ZR) {
1150 // AL: Always branch to l.
1151 beq(ZR, ZR, l);
1152 } else {
1153 sltu(AT, left, right);
1154 beq(AT, ZR, l);
1155 }
1156 break;
1157 }
1158 case ULT: {
1159 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used.
1160 if (left == ZR) {
1161 bne(right, ZR, l);
1162 } else if (right == ZR) {
1163 // NV: Never branch. Fall through.
1164 } else {
1165 sltu(AT, left, right);
1166 bne(AT, ZR, l);
1167 }
1168 break;
1169 }
1170 case ULE: {
1171 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used.
1172 if (left == ZR) {
1173 // AL: Always branch to l.
1174 beq(ZR, ZR, l);
1175 } else if (right == ZR) {
1176 beq(left, ZR, l);
1177 } else {
1178 sltu(AT, right, left);
1179 beq(AT, ZR, l);
1180 }
1181 break;
1182 }
1183 default:
1184 UNREACHABLE();
1185 }
1186 }
1187
1188 void BranchEqual(Register rd, Register rn, Label* l) { beq(rd, rn, l); }
1189
1190 void BranchEqual(Register rd, const Immediate& imm, Label* l) {
1191 ASSERT(!in_delay_slot_);
1192 if (imm.value() == 0) {
1193 beq(rd, ZR, l);
1194 } else {
1195 ASSERT(rd != CMPRES2);
1196 LoadImmediate(CMPRES2, imm.value());
1197 beq(rd, CMPRES2, l);
1198 }
1199 }
1200
1201 void BranchEqual(Register rd, const Object& object, Label* l) {
1202 ASSERT(!in_delay_slot_);
1203 ASSERT(rd != CMPRES2);
1204 LoadObject(CMPRES2, object);
1205 beq(rd, CMPRES2, l);
1206 }
1207
1208 void BranchNotEqual(Register rd, Register rn, Label* l) { bne(rd, rn, l); }
1209
1210 void BranchNotEqual(Register rd, const Immediate& imm, Label* l) {
1211 ASSERT(!in_delay_slot_);
1212 if (imm.value() == 0) {
1213 bne(rd, ZR, l);
1214 } else {
1215 ASSERT(rd != CMPRES2);
1216 LoadImmediate(CMPRES2, imm.value());
1217 bne(rd, CMPRES2, l);
1218 }
1219 }
1220
1221 void BranchNotEqual(Register rd, const Object& object, Label* l) {
1222 ASSERT(!in_delay_slot_);
1223 ASSERT(rd != CMPRES2);
1224 LoadObject(CMPRES2, object);
1225 bne(rd, CMPRES2, l);
1226 }
1227
1228 void BranchSignedGreater(Register rd, Register rs, Label* l) {
1229 ASSERT(!in_delay_slot_);
1230 slt(CMPRES2, rs, rd); // CMPRES2 = rd > rs ? 1 : 0.
1231 bne(CMPRES2, ZR, l);
1232 }
1233
1234 void BranchSignedGreater(Register rd, const Immediate& imm, Label* l) {
1235 ASSERT(!in_delay_slot_);
1236 if (imm.value() == 0) {
1237 bgtz(rd, l);
1238 } else {
1239 if (Utils::IsInt(kImmBits, imm.value() + 1)) {
1240 slti(CMPRES2, rd, Immediate(imm.value() + 1));
1241 beq(CMPRES2, ZR, l);
1242 } else {
1243 ASSERT(rd != CMPRES2);
1244 LoadImmediate(CMPRES2, imm.value());
1245 BranchSignedGreater(rd, CMPRES2, l);
1246 }
1247 }
1248 }
1249
1250 void BranchUnsignedGreater(Register rd, Register rs, Label* l) {
1251 ASSERT(!in_delay_slot_);
1252 sltu(CMPRES2, rs, rd);
1253 bne(CMPRES2, ZR, l);
1254 }
1255
1256 void BranchUnsignedGreater(Register rd, const Immediate& imm, Label* l) {
1257 ASSERT(!in_delay_slot_);
1258 if (imm.value() == 0) {
1259 BranchNotEqual(rd, Immediate(0), l);
1260 } else {
1261 if ((imm.value() != -1) && Utils::IsInt(kImmBits, imm.value() + 1)) {
1262 sltiu(CMPRES2, rd, Immediate(imm.value() + 1));
1263 beq(CMPRES2, ZR, l);
1264 } else {
1265 ASSERT(rd != CMPRES2);
1266 LoadImmediate(CMPRES2, imm.value());
1267 BranchUnsignedGreater(rd, CMPRES2, l);
1268 }
1269 }
1270 }
1271
1272 void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) {
1273 ASSERT(!in_delay_slot_);
1274 slt(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0.
1275 beq(CMPRES2, ZR, l); // If CMPRES2 = 0, then rd >= rs.
1276 }
1277
1278 void BranchSignedGreaterEqual(Register rd, const Immediate& imm, Label* l) {
1279 ASSERT(!in_delay_slot_);
1280 if (imm.value() == 0) {
1281 bgez(rd, l);
1282 } else {
1283 if (Utils::IsInt(kImmBits, imm.value())) {
1284 slti(CMPRES2, rd, imm);
1285 beq(CMPRES2, ZR, l);
1286 } else {
1287 ASSERT(rd != CMPRES2);
1288 LoadImmediate(CMPRES2, imm.value());
1289 BranchSignedGreaterEqual(rd, CMPRES2, l);
1290 }
1291 }
1292 }
1293
1294 void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) {
1295 ASSERT(!in_delay_slot_);
1296 sltu(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0.
1297 beq(CMPRES2, ZR, l);
1298 }
1299
1300 void BranchUnsignedGreaterEqual(Register rd, const Immediate& imm, Label* l) {
1301 ASSERT(!in_delay_slot_);
1302 if (imm.value() == 0) {
1303 b(l);
1304 } else {
1305 if (Utils::IsInt(kImmBits, imm.value())) {
1306 sltiu(CMPRES2, rd, imm);
1307 beq(CMPRES2, ZR, l);
1308 } else {
1309 ASSERT(rd != CMPRES2);
1310 LoadImmediate(CMPRES2, imm.value());
1311 BranchUnsignedGreaterEqual(rd, CMPRES2, l);
1312 }
1313 }
1314 }
1315
1316 void BranchSignedLess(Register rd, Register rs, Label* l) {
1317 ASSERT(!in_delay_slot_);
1318 BranchSignedGreater(rs, rd, l);
1319 }
1320
1321 void BranchSignedLess(Register rd, const Immediate& imm, Label* l) {
1322 ASSERT(!in_delay_slot_);
1323 if (imm.value() == 0) {
1324 bltz(rd, l);
1325 } else {
1326 if (Utils::IsInt(kImmBits, imm.value())) {
1327 slti(CMPRES2, rd, imm);
1328 bne(CMPRES2, ZR, l);
1329 } else {
1330 ASSERT(rd != CMPRES2);
1331 LoadImmediate(CMPRES2, imm.value());
1332 BranchSignedGreater(CMPRES2, rd, l);
1333 }
1334 }
1335 }
1336
1337 void BranchUnsignedLess(Register rd, Register rs, Label* l) {
1338 ASSERT(!in_delay_slot_);
1339 BranchUnsignedGreater(rs, rd, l);
1340 }
1341
1342 void BranchUnsignedLess(Register rd, const Immediate& imm, Label* l) {
1343 ASSERT(!in_delay_slot_);
1344 if (imm.value() == 0) {
1345 // Never branch. Fall through.
1346 } else {
1347 if (Utils::IsInt(kImmBits, imm.value())) {
1348 sltiu(CMPRES2, rd, imm);
1349 bne(CMPRES2, ZR, l);
1350 } else {
1351 ASSERT(rd != CMPRES2);
1352 LoadImmediate(CMPRES2, imm.value());
1353 BranchUnsignedGreater(CMPRES2, rd, l);
1354 }
1355 }
1356 }
1357
1358 void BranchSignedLessEqual(Register rd, Register rs, Label* l) {
1359 ASSERT(!in_delay_slot_);
1360 BranchSignedGreaterEqual(rs, rd, l);
1361 }
1362
1363 void BranchSignedLessEqual(Register rd, const Immediate& imm, Label* l) {
1364 ASSERT(!in_delay_slot_);
1365 if (imm.value() == 0) {
1366 blez(rd, l);
1367 } else {
1368 if (Utils::IsInt(kImmBits, imm.value() + 1)) {
1369 slti(CMPRES2, rd, Immediate(imm.value() + 1));
1370 bne(CMPRES2, ZR, l);
1371 } else {
1372 ASSERT(rd != CMPRES2);
1373 LoadImmediate(CMPRES2, imm.value());
1374 BranchSignedGreaterEqual(CMPRES2, rd, l);
1375 }
1376 }
1377 }
1378
1379 void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) {
1380 ASSERT(!in_delay_slot_);
1381 BranchUnsignedGreaterEqual(rs, rd, l);
1382 }
1383
1384 void BranchUnsignedLessEqual(Register rd, const Immediate& imm, Label* l) {
1385 ASSERT(!in_delay_slot_);
1386 if (imm.value() == 0) {
1387 beq(rd, ZR, l);
1388 } else {
1389 if ((imm.value() != -1) && Utils::IsInt(kImmBits, imm.value() + 1)) {
1390 sltiu(CMPRES2, rd, Immediate(imm.value() + 1));
1391 bne(CMPRES2, ZR, l);
1392 } else {
1393 ASSERT(rd != CMPRES2);
1394 LoadImmediate(CMPRES2, imm.value());
1395 BranchUnsignedGreaterEqual(CMPRES2, rd, l);
1396 }
1397 }
1398 }
1399
1400 void Push(Register rt) {
1401 ASSERT(!in_delay_slot_);
1402 addiu(SP, SP, Immediate(-kWordSize));
1403 sw(rt, Address(SP));
1404 }
1405
1406 void Pop(Register rt) {
1407 ASSERT(!in_delay_slot_);
1408 lw(rt, Address(SP));
1409 addiu(SP, SP, Immediate(kWordSize));
1410 }
1411
1412 void Ret() { jr(RA); }
1413
1414 void SmiTag(Register reg) { sll(reg, reg, kSmiTagSize); }
1415
1416 void SmiTag(Register dst, Register src) { sll(dst, src, kSmiTagSize); }
1417
1418 void SmiUntag(Register reg) { sra(reg, reg, kSmiTagSize); }
1419
1420 void SmiUntag(Register dst, Register src) { sra(dst, src, kSmiTagSize); }
1421
1422 void BranchIfNotSmi(Register reg, Label* label) {
1423 andi(CMPRES1, reg, Immediate(kSmiTagMask));
1424 bne(CMPRES1, ZR, label);
1425 }
1426
1427 void BranchIfSmi(Register reg, Label* label) {
1428 andi(CMPRES1, reg, Immediate(kSmiTagMask));
1429 beq(CMPRES1, ZR, label);
1430 }
1431
1432 void LoadFromOffset(Register reg, Register base, int32_t offset) {
1433 ASSERT(!in_delay_slot_);
1434 if (Utils::IsInt(kImmBits, offset)) {
1435 lw(reg, Address(base, offset));
1436 } else {
1437 LoadImmediate(TMP, offset);
1438 addu(TMP, base, TMP);
1439 lw(reg, Address(TMP, 0));
1440 }
1441 }
1442
1443 void LoadFieldFromOffset(Register reg, Register base, int32_t offset) {
1444 LoadFromOffset(reg, base, offset - kHeapObjectTag);
1445 }
1446
1447 void StoreToOffset(Register reg, Register base, int32_t offset) {
1448 ASSERT(!in_delay_slot_);
1449 if (Utils::IsInt(kImmBits, offset)) {
1450 sw(reg, Address(base, offset));
1451 } else {
1452 LoadImmediate(TMP, offset);
1453 addu(TMP, base, TMP);
1454 sw(reg, Address(TMP, 0));
1455 }
1456 }
1457
1458 void StoreFieldToOffset(Register reg, Register base, int32_t offset) {
1459 StoreToOffset(reg, base, offset - kHeapObjectTag);
1460 }
1461
1462
1463 void StoreDToOffset(DRegister reg, Register base, int32_t offset) {
1464 ASSERT(!in_delay_slot_);
1465 FRegister lo = static_cast<FRegister>(reg * 2);
1466 FRegister hi = static_cast<FRegister>(reg * 2 + 1);
1467 swc1(lo, Address(base, offset));
1468 swc1(hi, Address(base, offset + kWordSize));
1469 }
1470
1471 void LoadDFromOffset(DRegister reg, Register base, int32_t offset) {
1472 ASSERT(!in_delay_slot_);
1473 FRegister lo = static_cast<FRegister>(reg * 2);
1474 FRegister hi = static_cast<FRegister>(reg * 2 + 1);
1475 lwc1(lo, Address(base, offset));
1476 lwc1(hi, Address(base, offset + kWordSize));
1477 }
1478
1479 // dest gets the address of the following instruction. If temp is given,
1480 // RA is preserved using it as a temporary.
1481 void GetNextPC(Register dest, Register temp = kNoRegister);
1482
1483 void ReserveAlignedFrameSpace(intptr_t frame_space);
1484
1485 // Create a frame for calling into runtime that preserves all volatile
1486 // registers. Frame's SP is guaranteed to be correctly aligned and
1487 // frame_space bytes are reserved under it.
1488 void EnterCallRuntimeFrame(intptr_t frame_space);
1489 void LeaveCallRuntimeFrame();
1490
1491 void LoadObject(Register rd, const Object& object);
1492 void LoadUniqueObject(Register rd, const Object& object);
1493 void LoadFunctionFromCalleePool(Register dst,
1494 const Function& function,
1495 Register new_pp);
1496 void LoadNativeEntry(Register rd,
1497 const ExternalLabel* label,
1498 Patchability patchable);
1499 void PushObject(const Object& object);
1500
1501 void LoadIsolate(Register result);
1502
1503 void LoadClassId(Register result, Register object);
1504 void LoadClassById(Register result, Register class_id);
1505 void LoadClass(Register result, Register object);
1506 void LoadClassIdMayBeSmi(Register result, Register object);
1507 void LoadTaggedClassIdMayBeSmi(Register result, Register object);
1508
1509 void StoreIntoObject(Register object, // Object we are storing into.
1510 const Address& dest, // Where we are storing into.
1511 Register value, // Value we are storing.
1512 bool can_value_be_smi = true);
1513 void StoreIntoObjectOffset(Register object,
1514 int32_t offset,
1515 Register value,
1516 bool can_value_be_smi = true);
1517
1518 void StoreIntoObjectNoBarrier(Register object,
1519 const Address& dest,
1520 Register value);
1521 void StoreIntoObjectNoBarrierOffset(Register object,
1522 int32_t offset,
1523 Register value);
1524 void StoreIntoObjectNoBarrier(Register object,
1525 const Address& dest,
1526 const Object& value);
1527 void StoreIntoObjectNoBarrierOffset(Register object,
1528 int32_t offset,
1529 const Object& value);
1530
1531 void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count);
1532
1533 // Set up a Dart frame on entry with a frame pointer and PC information to
1534 // enable easy access to the RawInstruction object of code corresponding
1535 // to this frame.
1536 void EnterDartFrame(intptr_t frame_size);
1537 void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP);
1538 void LeaveDartFrameAndReturn(Register ra = RA);
1539
1540 // Set up a Dart frame for a function compiled for on-stack replacement.
1541 // The frame layout is a normal Dart frame, but the frame is partially set
1542 // up on entry (it is the frame of the unoptimized code).
1543 void EnterOsrFrame(intptr_t extra_size);
1544
1545 Address ElementAddressForIntIndex(bool is_external,
1546 intptr_t cid,
1547 intptr_t index_scale,
1548 Register array,
1549 intptr_t index) const;
1550 void LoadElementAddressForIntIndex(Register address,
1551 bool is_external,
1552 intptr_t cid,
1553 intptr_t index_scale,
1554 Register array,
1555 intptr_t index);
1556 Address ElementAddressForRegIndex(bool is_load,
1557 bool is_external,
1558 intptr_t cid,
1559 intptr_t index_scale,
1560 Register array,
1561 Register index);
1562 void LoadElementAddressForRegIndex(Register address,
1563 bool is_load,
1564 bool is_external,
1565 intptr_t cid,
1566 intptr_t index_scale,
1567 Register array,
1568 Register index);
1569
1570 void LoadHalfWordUnaligned(Register dst, Register addr, Register tmp);
1571 void LoadHalfWordUnsignedUnaligned(Register dst, Register addr, Register tmp);
1572 void StoreHalfWordUnaligned(Register src, Register addr, Register tmp);
1573 void LoadWordUnaligned(Register dst, Register addr, Register tmp);
1574 void StoreWordUnaligned(Register src, Register addr, Register tmp);
1575
1576 static Address VMTagAddress() {
1577 return Address(THR, Thread::vm_tag_offset());
1578 }
1579
1580 // On some other platforms, we draw a distinction between safe and unsafe
1581 // smis.
1582 static bool IsSafe(const Object& object) { return true; }
1583 static bool IsSafeSmi(const Object& object) { return object.IsSmi(); }
1584
1585 bool constant_pool_allowed() const { return constant_pool_allowed_; }
1586 void set_constant_pool_allowed(bool b) { constant_pool_allowed_ = b; }
1587
1588 private:
1589 AssemblerBuffer buffer_;
1590 ObjectPoolWrapper object_pool_wrapper_;
1591
1592 intptr_t prologue_offset_;
1593 bool has_single_entry_point_;
1594 bool use_far_branches_;
1595 bool delay_slot_available_;
1596 bool in_delay_slot_;
1597
1598 class CodeComment : public ZoneAllocated {
1599 public:
1600 CodeComment(intptr_t pc_offset, const String& comment)
1601 : pc_offset_(pc_offset), comment_(comment) {}
1602
1603 intptr_t pc_offset() const { return pc_offset_; }
1604 const String& comment() const { return comment_; }
1605
1606 private:
1607 intptr_t pc_offset_;
1608 const String& comment_;
1609
1610 DISALLOW_COPY_AND_ASSIGN(CodeComment);
1611 };
1612
1613 GrowableArray<CodeComment*> comments_;
1614
1615 bool constant_pool_allowed_;
1616
1617 void BranchLink(const ExternalLabel* label);
1618 void BranchLink(const Code& code, Patchability patchable);
1619
1620 bool CanLoadFromObjectPool(const Object& object) const;
1621
1622 void LoadWordFromPoolOffset(Register rd, int32_t offset, Register pp = PP);
1623 void LoadObjectHelper(Register rd, const Object& object, bool is_unique);
1624
1625 void Emit(int32_t value) {
1626 // Emitting an instruction clears the delay slot state.
1627 in_delay_slot_ = false;
1628 delay_slot_available_ = false;
1629 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1630 buffer_.Emit<int32_t>(value);
1631 }
1632
1633 // Encode CPU instructions according to the types specified in
1634 // Figures 4-1, 4-2 and 4-3 in VolI-A.
1635 void EmitIType(Opcode opcode, Register rs, Register rt, uint16_t imm) {
1636 Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift | imm);
1637 }
1638
1639 void EmitLoadStore(Opcode opcode, Register rt, const Address& addr) {
1640 Emit(opcode << kOpcodeShift | rt << kRtShift | addr.encoding());
1641 }
1642
1643 void EmitFpuLoadStore(Opcode opcode, FRegister ft, const Address& addr) {
1644 Emit(opcode << kOpcodeShift | ft << kFtShift | addr.encoding());
1645 }
1646
1647 void EmitRegImmType(Opcode opcode, Register rs, RtRegImm code, uint16_t imm) {
1648 Emit(opcode << kOpcodeShift | rs << kRsShift | code << kRtShift | imm);
1649 }
1650
1651 void EmitJType(Opcode opcode, uint32_t destination) { UNIMPLEMENTED(); }
1652
1653 void EmitRType(Opcode opcode,
1654 Register rs,
1655 Register rt,
1656 Register rd,
1657 int sa,
1658 SpecialFunction func) {
1659 ASSERT(Utils::IsUint(5, sa));
1660 Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift |
1661 rd << kRdShift | sa << kSaShift | func << kFunctionShift);
1662 }
1663
1664 void EmitFpuRType(Opcode opcode,
1665 Format fmt,
1666 FRegister ft,
1667 FRegister fs,
1668 FRegister fd,
1669 Cop1Function func) {
1670 Emit(opcode << kOpcodeShift | fmt << kFmtShift | ft << kFtShift |
1671 fs << kFsShift | fd << kFdShift | func << kCop1FnShift);
1672 }
1673
1674 int32_t EncodeBranchOffset(int32_t offset, int32_t instr);
1675
1676 void EmitFarJump(int32_t offset, bool link);
1677 void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset);
1678 void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset);
1679 void EmitFarFpuBranch(bool kind, int32_t offset);
1680 void EmitBranch(Opcode b, Register rs, Register rt, Label* label);
1681 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label);
1682 void EmitFpuBranch(bool kind, Label* label);
1683
1684 void EmitBranchDelayNop() {
1685 Emit(Instr::kNopInstruction); // Branch delay NOP.
1686 delay_slot_available_ = true;
1687 }
1688
1689 void StoreIntoObjectFilter(Register object, Register value, Label* no_update);
1690
1691 // Shorter filtering sequence that assumes that value is not a smi.
1692 void StoreIntoObjectFilterNoSmi(Register object,
1693 Register value,
1694 Label* no_update);
1695
1696 DISALLOW_ALLOCATION();
1697 DISALLOW_COPY_AND_ASSIGN(Assembler);
1698 };
1699
1700 } // namespace dart
1701
1702 #endif // RUNTIME_VM_ASSEMBLER_MIPS_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698