OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #ifndef RUNTIME_VM_ASSEMBLER_MIPS_H_ | 5 #ifndef RUNTIME_VM_ASSEMBLER_MIPS_H_ |
6 #define RUNTIME_VM_ASSEMBLER_MIPS_H_ | 6 #define RUNTIME_VM_ASSEMBLER_MIPS_H_ |
7 | 7 |
8 #ifndef RUNTIME_VM_ASSEMBLER_H_ | 8 #ifndef RUNTIME_VM_ASSEMBLER_H_ |
9 #error Do not include assembler_mips.h directly; use assembler.h instead. | 9 #error Do not include assembler_mips.h directly; use assembler.h instead. |
10 #endif | 10 #endif |
(...skipping 12 matching lines...) Expand all Loading... |
23 // "MIPS® Architecture For Programmers Volume II-A: | 23 // "MIPS® Architecture For Programmers Volume II-A: |
24 // The MIPS32® Instruction Set" in short "VolII-A" | 24 // The MIPS32® Instruction Set" in short "VolII-A" |
25 namespace dart { | 25 namespace dart { |
26 | 26 |
27 // Forward declarations. | 27 // Forward declarations. |
28 class RuntimeEntry; | 28 class RuntimeEntry; |
29 class StubEntry; | 29 class StubEntry; |
30 | 30 |
31 class Immediate : public ValueObject { | 31 class Immediate : public ValueObject { |
32 public: | 32 public: |
33 explicit Immediate(int32_t value) : value_(value) { } | 33 explicit Immediate(int32_t value) : value_(value) {} |
34 | 34 |
35 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) { } | 35 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) {} |
36 Immediate& operator=(const Immediate& other) { | 36 Immediate& operator=(const Immediate& other) { |
37 value_ = other.value_; | 37 value_ = other.value_; |
38 return *this; | 38 return *this; |
39 } | 39 } |
40 | 40 |
41 private: | 41 private: |
42 int32_t value_; | 42 int32_t value_; |
43 | 43 |
44 int32_t value() const { return value_; } | 44 int32_t value() const { return value_; } |
45 | 45 |
46 friend class Assembler; | 46 friend class Assembler; |
47 }; | 47 }; |
48 | 48 |
49 | 49 |
50 class Address : public ValueObject { | 50 class Address : public ValueObject { |
51 public: | 51 public: |
52 explicit Address(Register base, int32_t offset = 0) | 52 explicit Address(Register base, int32_t offset = 0) |
53 : ValueObject(), base_(base), offset_(offset) { } | 53 : ValueObject(), base_(base), offset_(offset) {} |
54 | 54 |
55 // This addressing mode does not exist. | 55 // This addressing mode does not exist. |
56 Address(Register base, Register offset); | 56 Address(Register base, Register offset); |
57 | 57 |
58 Address(const Address& other) | 58 Address(const Address& other) |
59 : ValueObject(), base_(other.base_), offset_(other.offset_) { } | 59 : ValueObject(), base_(other.base_), offset_(other.offset_) {} |
60 Address& operator=(const Address& other) { | 60 Address& operator=(const Address& other) { |
61 base_ = other.base_; | 61 base_ = other.base_; |
62 offset_ = other.offset_; | 62 offset_ = other.offset_; |
63 return *this; | 63 return *this; |
64 } | 64 } |
65 | 65 |
66 uint32_t encoding() const { | 66 uint32_t encoding() const { |
67 ASSERT(Utils::IsInt(kImmBits, offset_)); | 67 ASSERT(Utils::IsInt(kImmBits, offset_)); |
68 uint16_t imm_value = static_cast<uint16_t>(offset_); | 68 uint16_t imm_value = static_cast<uint16_t>(offset_); |
69 return (base_ << kRsShift) | imm_value; | 69 return (base_ << kRsShift) | imm_value; |
70 } | 70 } |
71 | 71 |
72 static bool CanHoldOffset(int32_t offset) { | 72 static bool CanHoldOffset(int32_t offset) { |
73 return Utils::IsInt(kImmBits, offset); | 73 return Utils::IsInt(kImmBits, offset); |
74 } | 74 } |
75 | 75 |
76 Register base() const { return base_; } | 76 Register base() const { return base_; } |
77 int32_t offset() const { return offset_; } | 77 int32_t offset() const { return offset_; } |
78 | 78 |
79 private: | 79 private: |
80 Register base_; | 80 Register base_; |
81 int32_t offset_; | 81 int32_t offset_; |
82 }; | 82 }; |
83 | 83 |
84 | 84 |
85 class FieldAddress : public Address { | 85 class FieldAddress : public Address { |
86 public: | 86 public: |
87 FieldAddress(Register base, int32_t disp) | 87 FieldAddress(Register base, int32_t disp) |
88 : Address(base, disp - kHeapObjectTag) { } | 88 : Address(base, disp - kHeapObjectTag) {} |
89 | 89 |
90 FieldAddress(const FieldAddress& other) : Address(other) { } | 90 FieldAddress(const FieldAddress& other) : Address(other) {} |
91 | 91 |
92 FieldAddress& operator=(const FieldAddress& other) { | 92 FieldAddress& operator=(const FieldAddress& other) { |
93 Address::operator=(other); | 93 Address::operator=(other); |
94 return *this; | 94 return *this; |
95 } | 95 } |
96 }; | 96 }; |
97 | 97 |
98 | 98 |
99 class Label : public ValueObject { | 99 class Label : public ValueObject { |
100 public: | 100 public: |
101 Label() : position_(0) { } | 101 Label() : position_(0) {} |
102 | 102 |
103 ~Label() { | 103 ~Label() { |
104 // Assert if label is being destroyed with unresolved branches pending. | 104 // Assert if label is being destroyed with unresolved branches pending. |
105 ASSERT(!IsLinked()); | 105 ASSERT(!IsLinked()); |
106 } | 106 } |
107 | 107 |
108 // Returns the position for bound and linked labels. Cannot be used | 108 // Returns the position for bound and linked labels. Cannot be used |
109 // for unused labels. | 109 // for unused labels. |
110 intptr_t Position() const { | 110 intptr_t Position() const { |
111 ASSERT(!IsUnused()); | 111 ASSERT(!IsUnused()); |
112 return IsBound() ? -position_ - kWordSize : position_ - kWordSize; | 112 return IsBound() ? -position_ - kWordSize : position_ - kWordSize; |
113 } | 113 } |
114 | 114 |
115 bool IsBound() const { return position_ < 0; } | 115 bool IsBound() const { return position_ < 0; } |
116 bool IsUnused() const { return position_ == 0; } | 116 bool IsUnused() const { return position_ == 0; } |
117 bool IsLinked() const { return position_ > 0; } | 117 bool IsLinked() const { return position_ > 0; } |
118 | 118 |
119 private: | 119 private: |
120 intptr_t position_; | 120 intptr_t position_; |
121 | 121 |
122 void Reinitialize() { | 122 void Reinitialize() { position_ = 0; } |
123 position_ = 0; | |
124 } | |
125 | 123 |
126 void BindTo(intptr_t position) { | 124 void BindTo(intptr_t position) { |
127 ASSERT(!IsBound()); | 125 ASSERT(!IsBound()); |
128 position_ = -position - kWordSize; | 126 position_ = -position - kWordSize; |
129 ASSERT(IsBound()); | 127 ASSERT(IsBound()); |
130 } | 128 } |
131 | 129 |
132 void LinkTo(intptr_t position) { | 130 void LinkTo(intptr_t position) { |
133 ASSERT(!IsBound()); | 131 ASSERT(!IsBound()); |
134 position_ = position + kWordSize; | 132 position_ = position + kWordSize; |
(...skipping 18 matching lines...) Expand all Loading... |
153 kRightPos = kLeftPos + kLeftSize, | 151 kRightPos = kLeftPos + kLeftSize, |
154 kRightSize = 6, | 152 kRightSize = 6, |
155 kRelOpPos = kRightPos + kRightSize, | 153 kRelOpPos = kRightPos + kRightSize, |
156 kRelOpSize = 4, | 154 kRelOpSize = 4, |
157 kImmPos = kRelOpPos + kRelOpSize, | 155 kImmPos = kRelOpPos + kRelOpSize, |
158 kImmSize = 16, | 156 kImmSize = 16, |
159 }; | 157 }; |
160 | 158 |
161 class LeftBits : public BitField<uword, Register, kLeftPos, kLeftSize> {}; | 159 class LeftBits : public BitField<uword, Register, kLeftPos, kLeftSize> {}; |
162 class RightBits : public BitField<uword, Register, kRightPos, kRightSize> {}; | 160 class RightBits : public BitField<uword, Register, kRightPos, kRightSize> {}; |
163 class RelOpBits : | 161 class RelOpBits |
164 public BitField<uword, RelationOperator, kRelOpPos, kRelOpSize> {}; | 162 : public BitField<uword, RelationOperator, kRelOpPos, kRelOpSize> {}; |
165 class ImmBits : public BitField<uword, uint16_t, kImmPos, kImmSize> {}; | 163 class ImmBits : public BitField<uword, uint16_t, kImmPos, kImmSize> {}; |
166 | 164 |
167 Register left() const { return LeftBits::decode(bits_); } | 165 Register left() const { return LeftBits::decode(bits_); } |
168 Register right() const { return RightBits::decode(bits_); } | 166 Register right() const { return RightBits::decode(bits_); } |
169 RelationOperator rel_op() const { return RelOpBits::decode(bits_); } | 167 RelationOperator rel_op() const { return RelOpBits::decode(bits_); } |
170 int16_t imm() const { return static_cast<int16_t>(ImmBits::decode(bits_)); } | 168 int16_t imm() const { return static_cast<int16_t>(ImmBits::decode(bits_)); } |
171 | 169 |
172 static bool IsValidImm(int32_t value) { | 170 static bool IsValidImm(int32_t value) { |
173 // We want both value and value + 1 to fit in an int16_t. | 171 // We want both value and value + 1 to fit in an int16_t. |
174 return (-0x08000 <= value) && (value < 0x7fff); | 172 return (-0x08000 <= value) && (value < 0x7fff); |
175 } | 173 } |
176 | 174 |
177 void set_rel_op(RelationOperator value) { | 175 void set_rel_op(RelationOperator value) { |
178 ASSERT(IsValidRelOp(value)); | 176 ASSERT(IsValidRelOp(value)); |
179 bits_ = RelOpBits::update(value, bits_); | 177 bits_ = RelOpBits::update(value, bits_); |
180 } | 178 } |
181 | 179 |
182 // Uninitialized condition. | 180 // Uninitialized condition. |
183 Condition() : ValueObject(), bits_(0) { } | 181 Condition() : ValueObject(), bits_(0) {} |
184 | 182 |
185 // Copy constructor. | 183 // Copy constructor. |
186 Condition(const Condition& other) : ValueObject(), bits_(other.bits_) { } | 184 Condition(const Condition& other) : ValueObject(), bits_(other.bits_) {} |
187 | 185 |
188 // Copy assignment operator. | 186 // Copy assignment operator. |
189 Condition& operator=(const Condition& other) { | 187 Condition& operator=(const Condition& other) { |
190 bits_ = other.bits_; | 188 bits_ = other.bits_; |
191 return *this; | 189 return *this; |
192 } | 190 } |
193 | 191 |
194 Condition(Register left, | 192 Condition(Register left, |
195 Register right, | 193 Register right, |
196 RelationOperator rel_op, | 194 RelationOperator rel_op, |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 class Assembler : public ValueObject { | 235 class Assembler : public ValueObject { |
238 public: | 236 public: |
239 explicit Assembler(bool use_far_branches = false) | 237 explicit Assembler(bool use_far_branches = false) |
240 : buffer_(), | 238 : buffer_(), |
241 prologue_offset_(-1), | 239 prologue_offset_(-1), |
242 has_single_entry_point_(true), | 240 has_single_entry_point_(true), |
243 use_far_branches_(use_far_branches), | 241 use_far_branches_(use_far_branches), |
244 delay_slot_available_(false), | 242 delay_slot_available_(false), |
245 in_delay_slot_(false), | 243 in_delay_slot_(false), |
246 comments_(), | 244 comments_(), |
247 constant_pool_allowed_(true) { | 245 constant_pool_allowed_(true) {} |
248 } | 246 ~Assembler() {} |
249 ~Assembler() { } | |
250 | 247 |
251 void PopRegister(Register r) { Pop(r); } | 248 void PopRegister(Register r) { Pop(r); } |
252 | 249 |
253 void Bind(Label* label); | 250 void Bind(Label* label); |
254 void Jump(Label* label) { b(label); } | 251 void Jump(Label* label) { b(label); } |
255 | 252 |
256 // Misc. functionality | 253 // Misc. functionality |
257 intptr_t CodeSize() const { return buffer_.Size(); } | 254 intptr_t CodeSize() const { return buffer_.Size(); } |
258 intptr_t prologue_offset() const { return prologue_offset_; } | 255 intptr_t prologue_offset() const { return prologue_offset_; } |
259 bool has_single_entry_point() const { return has_single_entry_point_; } | 256 bool has_single_entry_point() const { return has_single_entry_point_; } |
260 | 257 |
261 // Count the fixups that produce a pointer offset, without processing | 258 // Count the fixups that produce a pointer offset, without processing |
262 // the fixups. | 259 // the fixups. |
263 intptr_t CountPointerOffsets() const { | 260 intptr_t CountPointerOffsets() const { return buffer_.CountPointerOffsets(); } |
264 return buffer_.CountPointerOffsets(); | |
265 } | |
266 | 261 |
267 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { | 262 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
268 return buffer_.pointer_offsets(); | 263 return buffer_.pointer_offsets(); |
269 } | 264 } |
270 | 265 |
271 ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } | 266 ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } |
272 | 267 |
273 RawObjectPool* MakeObjectPool() { | 268 RawObjectPool* MakeObjectPool() { |
274 return object_pool_wrapper_.MakeObjectPool(); | 269 return object_pool_wrapper_.MakeObjectPool(); |
275 } | 270 } |
276 | 271 |
277 void FinalizeInstructions(const MemoryRegion& region) { | 272 void FinalizeInstructions(const MemoryRegion& region) { |
278 buffer_.FinalizeInstructions(region); | 273 buffer_.FinalizeInstructions(region); |
279 } | 274 } |
280 | 275 |
281 bool use_far_branches() const { | 276 bool use_far_branches() const { |
282 return FLAG_use_far_branches || use_far_branches_; | 277 return FLAG_use_far_branches || use_far_branches_; |
283 } | 278 } |
284 | 279 |
285 void set_use_far_branches(bool b) { | 280 void set_use_far_branches(bool b) { use_far_branches_ = b; } |
286 use_far_branches_ = b; | |
287 } | |
288 | 281 |
289 void EnterFrame(); | 282 void EnterFrame(); |
290 void LeaveFrameAndReturn(); | 283 void LeaveFrameAndReturn(); |
291 | 284 |
292 // Set up a stub frame so that the stack traversal code can easily identify | 285 // Set up a stub frame so that the stack traversal code can easily identify |
293 // a stub frame. | 286 // a stub frame. |
294 void EnterStubFrame(intptr_t frame_size = 0); | 287 void EnterStubFrame(intptr_t frame_size = 0); |
295 void LeaveStubFrame(); | 288 void LeaveStubFrame(); |
296 // A separate macro for when a Ret immediately follows, so that we can use | 289 // A separate macro for when a Ret immediately follows, so that we can use |
297 // the branch delay slot. | 290 // the branch delay slot. |
298 void LeaveStubFrameAndReturn(Register ra = RA); | 291 void LeaveStubFrameAndReturn(Register ra = RA); |
299 | 292 |
300 void MonomorphicCheckedEntry(); | 293 void MonomorphicCheckedEntry(); |
301 | 294 |
302 void UpdateAllocationStats(intptr_t cid, | 295 void UpdateAllocationStats(intptr_t cid, |
303 Register temp_reg, | 296 Register temp_reg, |
304 Heap::Space space); | 297 Heap::Space space); |
305 | 298 |
306 void UpdateAllocationStatsWithSize(intptr_t cid, | 299 void UpdateAllocationStatsWithSize(intptr_t cid, |
307 Register size_reg, | 300 Register size_reg, |
308 Register temp_reg, | 301 Register temp_reg, |
309 Heap::Space space); | 302 Heap::Space space); |
310 | 303 |
311 | 304 |
312 void MaybeTraceAllocation(intptr_t cid, | 305 void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace); |
313 Register temp_reg, | |
314 Label* trace); | |
315 | 306 |
316 // Inlined allocation of an instance of class 'cls', code has no runtime | 307 // Inlined allocation of an instance of class 'cls', code has no runtime |
317 // calls. Jump to 'failure' if the instance cannot be allocated here. | 308 // calls. Jump to 'failure' if the instance cannot be allocated here. |
318 // Allocated instance is returned in 'instance_reg'. | 309 // Allocated instance is returned in 'instance_reg'. |
319 // Only the tags field of the object is initialized. | 310 // Only the tags field of the object is initialized. |
320 void TryAllocate(const Class& cls, | 311 void TryAllocate(const Class& cls, |
321 Label* failure, | 312 Label* failure, |
322 Register instance_reg, | 313 Register instance_reg, |
323 Register temp_reg); | 314 Register temp_reg); |
324 | 315 |
(...skipping 25 matching lines...) Expand all Loading... |
350 void SetPrologueOffset() { | 341 void SetPrologueOffset() { |
351 if (prologue_offset_ == -1) { | 342 if (prologue_offset_ == -1) { |
352 prologue_offset_ = CodeSize(); | 343 prologue_offset_ = CodeSize(); |
353 } | 344 } |
354 } | 345 } |
355 | 346 |
356 // A utility to be able to assemble an instruction into the delay slot. | 347 // A utility to be able to assemble an instruction into the delay slot. |
357 Assembler* delay_slot() { | 348 Assembler* delay_slot() { |
358 ASSERT(delay_slot_available_); | 349 ASSERT(delay_slot_available_); |
359 ASSERT(buffer_.Load<int32_t>(buffer_.GetPosition() - sizeof(int32_t)) == | 350 ASSERT(buffer_.Load<int32_t>(buffer_.GetPosition() - sizeof(int32_t)) == |
360 Instr::kNopInstruction); | 351 Instr::kNopInstruction); |
361 buffer_.Remit<int32_t>(); | 352 buffer_.Remit<int32_t>(); |
362 delay_slot_available_ = false; | 353 delay_slot_available_ = false; |
363 in_delay_slot_ = true; | 354 in_delay_slot_ = true; |
364 return this; | 355 return this; |
365 } | 356 } |
366 | 357 |
367 // CPU instructions in alphabetical order. | 358 // CPU instructions in alphabetical order. |
368 void addd(DRegister dd, DRegister ds, DRegister dt) { | 359 void addd(DRegister dd, DRegister ds, DRegister dt) { |
369 // DRegisters start at the even FRegisters. | 360 // DRegisters start at the even FRegisters. |
370 FRegister fd = static_cast<FRegister>(dd * 2); | 361 FRegister fd = static_cast<FRegister>(dd * 2); |
(...skipping 16 matching lines...) Expand all Loading... |
387 EmitRType(SPECIAL, rs, rt, rd, 0, AND); | 378 EmitRType(SPECIAL, rs, rt, rd, 0, AND); |
388 } | 379 } |
389 | 380 |
390 void andi(Register rt, Register rs, const Immediate& imm) { | 381 void andi(Register rt, Register rs, const Immediate& imm) { |
391 ASSERT(Utils::IsUint(kImmBits, imm.value())); | 382 ASSERT(Utils::IsUint(kImmBits, imm.value())); |
392 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 383 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
393 EmitIType(ANDI, rs, rt, imm_value); | 384 EmitIType(ANDI, rs, rt, imm_value); |
394 } | 385 } |
395 | 386 |
396 // Unconditional branch. | 387 // Unconditional branch. |
397 void b(Label* l) { | 388 void b(Label* l) { beq(R0, R0, l); } |
398 beq(R0, R0, l); | |
399 } | |
400 | 389 |
401 void bal(Label *l) { | 390 void bal(Label* l) { |
402 ASSERT(!in_delay_slot_); | 391 ASSERT(!in_delay_slot_); |
403 EmitRegImmBranch(BGEZAL, R0, l); | 392 EmitRegImmBranch(BGEZAL, R0, l); |
404 EmitBranchDelayNop(); | 393 EmitBranchDelayNop(); |
405 } | 394 } |
406 | 395 |
407 // Branch on floating point false. | 396 // Branch on floating point false. |
408 void bc1f(Label* l) { | 397 void bc1f(Label* l) { |
409 EmitFpuBranch(false, l); | 398 EmitFpuBranch(false, l); |
410 EmitBranchDelayNop(); | 399 EmitBranchDelayNop(); |
411 } | 400 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 // Branch if not equal, likely taken. | 490 // Branch if not equal, likely taken. |
502 // Delay slot executed only when branch taken. | 491 // Delay slot executed only when branch taken. |
503 void bnel(Register rs, Register rt, Label* l) { | 492 void bnel(Register rs, Register rt, Label* l) { |
504 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. | 493 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
505 EmitBranch(BNEL, rs, rt, l); | 494 EmitBranch(BNEL, rs, rt, l); |
506 EmitBranchDelayNop(); | 495 EmitBranchDelayNop(); |
507 } | 496 } |
508 | 497 |
509 static int32_t BreakEncoding(int32_t code) { | 498 static int32_t BreakEncoding(int32_t code) { |
510 ASSERT(Utils::IsUint(20, code)); | 499 ASSERT(Utils::IsUint(20, code)); |
511 return SPECIAL << kOpcodeShift | | 500 return SPECIAL << kOpcodeShift | code << kBreakCodeShift | |
512 code << kBreakCodeShift | | |
513 BREAK << kFunctionShift; | 501 BREAK << kFunctionShift; |
514 } | 502 } |
515 | 503 |
516 | 504 |
517 void break_(int32_t code) { | 505 void break_(int32_t code) { Emit(BreakEncoding(code)); } |
518 Emit(BreakEncoding(code)); | |
519 } | |
520 | 506 |
521 static uword GetBreakInstructionFiller() { | 507 static uword GetBreakInstructionFiller() { return BreakEncoding(0); } |
522 return BreakEncoding(0); | |
523 } | |
524 | 508 |
525 // FPU compare, always false. | 509 // FPU compare, always false. |
526 void cfd(DRegister ds, DRegister dt) { | 510 void cfd(DRegister ds, DRegister dt) { |
527 FRegister fs = static_cast<FRegister>(ds * 2); | 511 FRegister fs = static_cast<FRegister>(ds * 2); |
528 FRegister ft = static_cast<FRegister>(dt * 2); | 512 FRegister ft = static_cast<FRegister>(dt * 2); |
529 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_F); | 513 EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_F); |
530 } | 514 } |
531 | 515 |
532 // FPU compare, true if unordered, i.e. one is NaN. | 516 // FPU compare, true if unordered, i.e. one is NaN. |
533 void cund(DRegister ds, DRegister dt) { | 517 void cund(DRegister ds, DRegister dt) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 FRegister fd = static_cast<FRegister>(dd * 2); | 587 FRegister fd = static_cast<FRegister>(dd * 2); |
604 EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D); | 588 EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D); |
605 } | 589 } |
606 | 590 |
607 // Convert a 64-bit double in ds to a 32-bit float in fd. | 591 // Convert a 64-bit double in ds to a 32-bit float in fd. |
608 void cvtsd(FRegister fd, DRegister ds) { | 592 void cvtsd(FRegister fd, DRegister ds) { |
609 FRegister fs = static_cast<FRegister>(ds * 2); | 593 FRegister fs = static_cast<FRegister>(ds * 2); |
610 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S); | 594 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S); |
611 } | 595 } |
612 | 596 |
613 void div(Register rs, Register rt) { | 597 void div(Register rs, Register rt) { EmitRType(SPECIAL, rs, rt, R0, 0, DIV); } |
614 EmitRType(SPECIAL, rs, rt, R0, 0, DIV); | |
615 } | |
616 | 598 |
617 void divd(DRegister dd, DRegister ds, DRegister dt) { | 599 void divd(DRegister dd, DRegister ds, DRegister dt) { |
618 FRegister fd = static_cast<FRegister>(dd * 2); | 600 FRegister fd = static_cast<FRegister>(dd * 2); |
619 FRegister fs = static_cast<FRegister>(ds * 2); | 601 FRegister fs = static_cast<FRegister>(ds * 2); |
620 FRegister ft = static_cast<FRegister>(dt * 2); | 602 FRegister ft = static_cast<FRegister>(dt * 2); |
621 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_DIV); | 603 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_DIV); |
622 } | 604 } |
623 | 605 |
624 void divu(Register rs, Register rt) { | 606 void divu(Register rs, Register rt) { |
625 EmitRType(SPECIAL, rs, rt, R0, 0, DIVU); | 607 EmitRType(SPECIAL, rs, rt, R0, 0, DIVU); |
626 } | 608 } |
627 | 609 |
628 void jalr(Register rs, Register rd = RA) { | 610 void jalr(Register rs, Register rd = RA) { |
629 ASSERT(rs != rd); | 611 ASSERT(rs != rd); |
630 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. | 612 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
631 EmitRType(SPECIAL, rs, R0, rd, 0, JALR); | 613 EmitRType(SPECIAL, rs, R0, rd, 0, JALR); |
632 EmitBranchDelayNop(); | 614 EmitBranchDelayNop(); |
633 } | 615 } |
634 | 616 |
635 void jr(Register rs) { | 617 void jr(Register rs) { |
636 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. | 618 ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
637 EmitRType(SPECIAL, rs, R0, R0, 0, JR); | 619 EmitRType(SPECIAL, rs, R0, R0, 0, JR); |
638 EmitBranchDelayNop(); | 620 EmitBranchDelayNop(); |
639 } | 621 } |
640 | 622 |
641 void lb(Register rt, const Address& addr) { | 623 void lb(Register rt, const Address& addr) { EmitLoadStore(LB, rt, addr); } |
642 EmitLoadStore(LB, rt, addr); | |
643 } | |
644 | 624 |
645 void lbu(Register rt, const Address& addr) { | 625 void lbu(Register rt, const Address& addr) { EmitLoadStore(LBU, rt, addr); } |
646 EmitLoadStore(LBU, rt, addr); | |
647 } | |
648 | 626 |
649 void ldc1(DRegister dt, const Address& addr) { | 627 void ldc1(DRegister dt, const Address& addr) { |
650 FRegister ft = static_cast<FRegister>(dt * 2); | 628 FRegister ft = static_cast<FRegister>(dt * 2); |
651 EmitFpuLoadStore(LDC1, ft, addr); | 629 EmitFpuLoadStore(LDC1, ft, addr); |
652 } | 630 } |
653 | 631 |
654 void lh(Register rt, const Address& addr) { | 632 void lh(Register rt, const Address& addr) { EmitLoadStore(LH, rt, addr); } |
655 EmitLoadStore(LH, rt, addr); | |
656 } | |
657 | 633 |
658 void lhu(Register rt, const Address& addr) { | 634 void lhu(Register rt, const Address& addr) { EmitLoadStore(LHU, rt, addr); } |
659 EmitLoadStore(LHU, rt, addr); | |
660 } | |
661 | 635 |
662 void ll(Register rt, const Address& addr) { | 636 void ll(Register rt, const Address& addr) { EmitLoadStore(LL, rt, addr); } |
663 EmitLoadStore(LL, rt, addr); | |
664 } | |
665 | 637 |
666 void lui(Register rt, const Immediate& imm) { | 638 void lui(Register rt, const Immediate& imm) { |
667 ASSERT(Utils::IsUint(kImmBits, imm.value())); | 639 ASSERT(Utils::IsUint(kImmBits, imm.value())); |
668 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 640 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
669 EmitIType(LUI, R0, rt, imm_value); | 641 EmitIType(LUI, R0, rt, imm_value); |
670 } | 642 } |
671 | 643 |
672 void lw(Register rt, const Address& addr) { | 644 void lw(Register rt, const Address& addr) { EmitLoadStore(LW, rt, addr); } |
673 EmitLoadStore(LW, rt, addr); | |
674 } | |
675 | 645 |
676 void lwc1(FRegister ft, const Address& addr) { | 646 void lwc1(FRegister ft, const Address& addr) { |
677 EmitFpuLoadStore(LWC1, ft, addr); | 647 EmitFpuLoadStore(LWC1, ft, addr); |
678 } | 648 } |
679 | 649 |
680 void madd(Register rs, Register rt) { | 650 void madd(Register rs, Register rt) { |
681 EmitRType(SPECIAL2, rs, rt, R0, 0, MADD); | 651 EmitRType(SPECIAL2, rs, rt, R0, 0, MADD); |
682 } | 652 } |
683 | 653 |
684 void maddu(Register rs, Register rt) { | 654 void maddu(Register rs, Register rt) { |
685 EmitRType(SPECIAL2, rs, rt, R0, 0, MADDU); | 655 EmitRType(SPECIAL2, rs, rt, R0, 0, MADDU); |
686 } | 656 } |
687 | 657 |
688 void mfc1(Register rt, FRegister fs) { | 658 void mfc1(Register rt, FRegister fs) { |
689 Emit(COP1 << kOpcodeShift | | 659 Emit(COP1 << kOpcodeShift | COP1_MF << kCop1SubShift | rt << kRtShift | |
690 COP1_MF << kCop1SubShift | | |
691 rt << kRtShift | | |
692 fs << kFsShift); | 660 fs << kFsShift); |
693 } | 661 } |
694 | 662 |
695 void mfhi(Register rd) { | 663 void mfhi(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFHI); } |
696 EmitRType(SPECIAL, R0, R0, rd, 0, MFHI); | |
697 } | |
698 | 664 |
699 void mflo(Register rd) { | 665 void mflo(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFLO); } |
700 EmitRType(SPECIAL, R0, R0, rd, 0, MFLO); | |
701 } | |
702 | 666 |
703 void mov(Register rd, Register rs) { | 667 void mov(Register rd, Register rs) { or_(rd, rs, ZR); } |
704 or_(rd, rs, ZR); | |
705 } | |
706 | 668 |
707 void movd(DRegister dd, DRegister ds) { | 669 void movd(DRegister dd, DRegister ds) { |
708 FRegister fd = static_cast<FRegister>(dd * 2); | 670 FRegister fd = static_cast<FRegister>(dd * 2); |
709 FRegister fs = static_cast<FRegister>(ds * 2); | 671 FRegister fs = static_cast<FRegister>(ds * 2); |
710 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV); | 672 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV); |
711 } | 673 } |
712 | 674 |
713 // Move if floating point false. | 675 // Move if floating point false. |
714 void movf(Register rd, Register rs) { | 676 void movf(Register rd, Register rs) { |
715 EmitRType(SPECIAL, rs, R0, rd, 0, MOVCI); | 677 EmitRType(SPECIAL, rs, R0, rd, 0, MOVCI); |
(...skipping 11 matching lines...) Expand all Loading... |
727 // rd <- (rt == 0) ? rs : rd; | 689 // rd <- (rt == 0) ? rs : rd; |
728 void movz(Register rd, Register rs, Register rt) { | 690 void movz(Register rd, Register rs, Register rt) { |
729 EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ); | 691 EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ); |
730 } | 692 } |
731 | 693 |
732 void movs(FRegister fd, FRegister fs) { | 694 void movs(FRegister fd, FRegister fs) { |
733 EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_MOV); | 695 EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_MOV); |
734 } | 696 } |
735 | 697 |
736 void mtc1(Register rt, FRegister fs) { | 698 void mtc1(Register rt, FRegister fs) { |
737 Emit(COP1 << kOpcodeShift | | 699 Emit(COP1 << kOpcodeShift | COP1_MT << kCop1SubShift | rt << kRtShift | |
738 COP1_MT << kCop1SubShift | | |
739 rt << kRtShift | | |
740 fs << kFsShift); | 700 fs << kFsShift); |
741 } | 701 } |
742 | 702 |
743 void mthi(Register rs) { | 703 void mthi(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTHI); } |
744 EmitRType(SPECIAL, rs, R0, R0, 0, MTHI); | |
745 } | |
746 | 704 |
747 void mtlo(Register rs) { | 705 void mtlo(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTLO); } |
748 EmitRType(SPECIAL, rs, R0, R0, 0, MTLO); | |
749 } | |
750 | 706 |
751 void muld(DRegister dd, DRegister ds, DRegister dt) { | 707 void muld(DRegister dd, DRegister ds, DRegister dt) { |
752 FRegister fd = static_cast<FRegister>(dd * 2); | 708 FRegister fd = static_cast<FRegister>(dd * 2); |
753 FRegister fs = static_cast<FRegister>(ds * 2); | 709 FRegister fs = static_cast<FRegister>(ds * 2); |
754 FRegister ft = static_cast<FRegister>(dt * 2); | 710 FRegister ft = static_cast<FRegister>(dt * 2); |
755 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_MUL); | 711 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_MUL); |
756 } | 712 } |
757 | 713 |
758 void mult(Register rs, Register rt) { | 714 void mult(Register rs, Register rt) { |
759 EmitRType(SPECIAL, rs, rt, R0, 0, MULT); | 715 EmitRType(SPECIAL, rs, rt, R0, 0, MULT); |
760 } | 716 } |
761 | 717 |
762 void multu(Register rs, Register rt) { | 718 void multu(Register rs, Register rt) { |
763 EmitRType(SPECIAL, rs, rt, R0, 0, MULTU); | 719 EmitRType(SPECIAL, rs, rt, R0, 0, MULTU); |
764 } | 720 } |
765 | 721 |
766 void negd(DRegister dd, DRegister ds) { | 722 void negd(DRegister dd, DRegister ds) { |
767 FRegister fd = static_cast<FRegister>(dd * 2); | 723 FRegister fd = static_cast<FRegister>(dd * 2); |
768 FRegister fs = static_cast<FRegister>(ds * 2); | 724 FRegister fs = static_cast<FRegister>(ds * 2); |
769 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_NEG); | 725 EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_NEG); |
770 } | 726 } |
771 | 727 |
772 void nop() { | 728 void nop() { Emit(Instr::kNopInstruction); } |
773 Emit(Instr::kNopInstruction); | |
774 } | |
775 | 729 |
776 void nor(Register rd, Register rs, Register rt) { | 730 void nor(Register rd, Register rs, Register rt) { |
777 EmitRType(SPECIAL, rs, rt, rd, 0, NOR); | 731 EmitRType(SPECIAL, rs, rt, rd, 0, NOR); |
778 } | 732 } |
779 | 733 |
780 void or_(Register rd, Register rs, Register rt) { | 734 void or_(Register rd, Register rs, Register rt) { |
781 EmitRType(SPECIAL, rs, rt, rd, 0, OR); | 735 EmitRType(SPECIAL, rs, rt, rd, 0, OR); |
782 } | 736 } |
783 | 737 |
784 void ori(Register rt, Register rs, const Immediate& imm) { | 738 void ori(Register rt, Register rs, const Immediate& imm) { |
785 ASSERT(Utils::IsUint(kImmBits, imm.value())); | 739 ASSERT(Utils::IsUint(kImmBits, imm.value())); |
786 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 740 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
787 EmitIType(ORI, rs, rt, imm_value); | 741 EmitIType(ORI, rs, rt, imm_value); |
788 } | 742 } |
789 | 743 |
790 void sb(Register rt, const Address& addr) { | 744 void sb(Register rt, const Address& addr) { EmitLoadStore(SB, rt, addr); } |
791 EmitLoadStore(SB, rt, addr); | |
792 } | |
793 | 745 |
794 // rt = 1 on success, 0 on failure. | 746 // rt = 1 on success, 0 on failure. |
795 void sc(Register rt, const Address& addr) { | 747 void sc(Register rt, const Address& addr) { EmitLoadStore(SC, rt, addr); } |
796 EmitLoadStore(SC, rt, addr); | |
797 } | |
798 | 748 |
799 void sdc1(DRegister dt, const Address& addr) { | 749 void sdc1(DRegister dt, const Address& addr) { |
800 FRegister ft = static_cast<FRegister>(dt * 2); | 750 FRegister ft = static_cast<FRegister>(dt * 2); |
801 EmitFpuLoadStore(SDC1, ft, addr); | 751 EmitFpuLoadStore(SDC1, ft, addr); |
802 } | 752 } |
803 | 753 |
804 void sh(Register rt, const Address& addr) { | 754 void sh(Register rt, const Address& addr) { EmitLoadStore(SH, rt, addr); } |
805 EmitLoadStore(SH, rt, addr); | |
806 } | |
807 | 755 |
808 void sll(Register rd, Register rt, int sa) { | 756 void sll(Register rd, Register rt, int sa) { |
809 EmitRType(SPECIAL, R0, rt, rd, sa, SLL); | 757 EmitRType(SPECIAL, R0, rt, rd, sa, SLL); |
810 } | 758 } |
811 | 759 |
812 void sllv(Register rd, Register rt, Register rs) { | 760 void sllv(Register rd, Register rt, Register rs) { |
813 EmitRType(SPECIAL, rs, rt, rd, 0, SLLV); | 761 EmitRType(SPECIAL, rs, rt, rd, 0, SLLV); |
814 } | 762 } |
815 | 763 |
816 void slt(Register rd, Register rs, Register rt) { | 764 void slt(Register rd, Register rs, Register rt) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 FRegister fd = static_cast<FRegister>(dd * 2); | 810 FRegister fd = static_cast<FRegister>(dd * 2); |
863 FRegister fs = static_cast<FRegister>(ds * 2); | 811 FRegister fs = static_cast<FRegister>(ds * 2); |
864 FRegister ft = static_cast<FRegister>(dt * 2); | 812 FRegister ft = static_cast<FRegister>(dt * 2); |
865 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_SUB); | 813 EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_SUB); |
866 } | 814 } |
867 | 815 |
868 void subu(Register rd, Register rs, Register rt) { | 816 void subu(Register rd, Register rs, Register rt) { |
869 EmitRType(SPECIAL, rs, rt, rd, 0, SUBU); | 817 EmitRType(SPECIAL, rs, rt, rd, 0, SUBU); |
870 } | 818 } |
871 | 819 |
872 void sw(Register rt, const Address& addr) { | 820 void sw(Register rt, const Address& addr) { EmitLoadStore(SW, rt, addr); } |
873 EmitLoadStore(SW, rt, addr); | |
874 } | |
875 | 821 |
876 void swc1(FRegister ft, const Address& addr) { | 822 void swc1(FRegister ft, const Address& addr) { |
877 EmitFpuLoadStore(SWC1, ft, addr); | 823 EmitFpuLoadStore(SWC1, ft, addr); |
878 } | 824 } |
879 | 825 |
880 void xori(Register rt, Register rs, const Immediate& imm) { | 826 void xori(Register rt, Register rs, const Immediate& imm) { |
881 ASSERT(Utils::IsUint(kImmBits, imm.value())); | 827 ASSERT(Utils::IsUint(kImmBits, imm.value())); |
882 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 828 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
883 EmitIType(XORI, rs, rt, imm_value); | 829 EmitIType(XORI, rs, rt, imm_value); |
884 } | 830 } |
885 | 831 |
886 void xor_(Register rd, Register rs, Register rt) { | 832 void xor_(Register rd, Register rs, Register rt) { |
887 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); | 833 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); |
888 } | 834 } |
889 | 835 |
890 // Macros in alphabetical order. | 836 // Macros in alphabetical order. |
891 | 837 |
892 // Addition of rs and rt with the result placed in rd. | 838 // Addition of rs and rt with the result placed in rd. |
893 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. | 839 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. |
894 // rd and ro must not be TMP. | 840 // rd and ro must not be TMP. |
895 // ro must be different from all the other registers. | 841 // ro must be different from all the other registers. |
896 // If rd, rs, and rt are the same register, then a scratch register different | 842 // If rd, rs, and rt are the same register, then a scratch register different |
897 // from the other registers is needed. | 843 // from the other registers is needed. |
898 void AdduDetectOverflow(Register rd, Register rs, Register rt, Register ro, | 844 void AdduDetectOverflow(Register rd, |
| 845 Register rs, |
| 846 Register rt, |
| 847 Register ro, |
899 Register scratch = kNoRegister); | 848 Register scratch = kNoRegister); |
900 | 849 |
901 // ro must be different from rd and rs. | 850 // ro must be different from rd and rs. |
902 // rd and ro must not be TMP. | 851 // rd and ro must not be TMP. |
903 // If rd and rs are the same, a scratch register different from the other | 852 // If rd and rs are the same, a scratch register different from the other |
904 // registers is needed. | 853 // registers is needed. |
905 void AddImmediateDetectOverflow(Register rd, Register rs, int32_t imm, | 854 void AddImmediateDetectOverflow(Register rd, |
906 Register ro, Register scratch = kNoRegister) { | 855 Register rs, |
| 856 int32_t imm, |
| 857 Register ro, |
| 858 Register scratch = kNoRegister) { |
907 ASSERT(!in_delay_slot_); | 859 ASSERT(!in_delay_slot_); |
908 LoadImmediate(rd, imm); | 860 LoadImmediate(rd, imm); |
909 AdduDetectOverflow(rd, rs, rd, ro, scratch); | 861 AdduDetectOverflow(rd, rs, rd, ro, scratch); |
910 } | 862 } |
911 | 863 |
912 // Subtraction of rt from rs (rs - rt) with the result placed in rd. | 864 // Subtraction of rt from rs (rs - rt) with the result placed in rd. |
913 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. | 865 // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. |
914 // None of rd, rs, rt, or ro may be TMP. | 866 // None of rd, rs, rt, or ro may be TMP. |
915 // ro must be different from the other registers. | 867 // ro must be different from the other registers. |
916 void SubuDetectOverflow(Register rd, Register rs, Register rt, Register ro); | 868 void SubuDetectOverflow(Register rd, Register rs, Register rt, Register ro); |
917 | 869 |
918 // ro must be different from rd and rs. | 870 // ro must be different from rd and rs. |
919 // None of rd, rs, rt, or ro may be TMP. | 871 // None of rd, rs, rt, or ro may be TMP. |
920 void SubImmediateDetectOverflow(Register rd, Register rs, int32_t imm, | 872 void SubImmediateDetectOverflow(Register rd, |
| 873 Register rs, |
| 874 int32_t imm, |
921 Register ro) { | 875 Register ro) { |
922 ASSERT(!in_delay_slot_); | 876 ASSERT(!in_delay_slot_); |
923 LoadImmediate(rd, imm); | 877 LoadImmediate(rd, imm); |
924 SubuDetectOverflow(rd, rs, rd, ro); | 878 SubuDetectOverflow(rd, rs, rd, ro); |
925 } | 879 } |
926 | 880 |
927 void Branch(const StubEntry& stub_entry, Register pp = PP); | 881 void Branch(const StubEntry& stub_entry, Register pp = PP); |
928 | 882 |
929 void BranchLink(const StubEntry& stub_entry, | 883 void BranchLink(const StubEntry& stub_entry, |
930 Patchability patchable = kNotPatchable); | 884 Patchability patchable = kNotPatchable); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 return rd; | 1034 return rd; |
1081 } | 1035 } |
1082 | 1036 |
1083 // Branch to label if condition is true. | 1037 // Branch to label if condition is true. |
1084 void BranchOnCondition(Condition cond, Label* l) { | 1038 void BranchOnCondition(Condition cond, Label* l) { |
1085 ASSERT(!in_delay_slot_); | 1039 ASSERT(!in_delay_slot_); |
1086 Register left = cond.left(); | 1040 Register left = cond.left(); |
1087 Register right = cond.right(); | 1041 Register right = cond.right(); |
1088 RelationOperator rel_op = cond.rel_op(); | 1042 RelationOperator rel_op = cond.rel_op(); |
1089 switch (rel_op) { | 1043 switch (rel_op) { |
1090 case NV: return; | 1044 case NV: |
1091 case AL: b(l); return; | 1045 return; |
| 1046 case AL: |
| 1047 b(l); |
| 1048 return; |
1092 case EQ: // fall through. | 1049 case EQ: // fall through. |
1093 case NE: { | 1050 case NE: { |
1094 if (left == IMM) { | 1051 if (left == IMM) { |
1095 addiu(AT, ZR, Immediate(cond.imm())); | 1052 addiu(AT, ZR, Immediate(cond.imm())); |
1096 left = AT; | 1053 left = AT; |
1097 } else if (right == IMM) { | 1054 } else if (right == IMM) { |
1098 addiu(AT, ZR, Immediate(cond.imm())); | 1055 addiu(AT, ZR, Immediate(cond.imm())); |
1099 right = AT; | 1056 right = AT; |
1100 } | 1057 } |
1101 if (rel_op == EQ) { | 1058 if (rel_op == EQ) { |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 sltu(AT, right, left); | 1178 sltu(AT, right, left); |
1222 beq(AT, ZR, l); | 1179 beq(AT, ZR, l); |
1223 } | 1180 } |
1224 break; | 1181 break; |
1225 } | 1182 } |
1226 default: | 1183 default: |
1227 UNREACHABLE(); | 1184 UNREACHABLE(); |
1228 } | 1185 } |
1229 } | 1186 } |
1230 | 1187 |
1231 void BranchEqual(Register rd, Register rn, Label* l) { | 1188 void BranchEqual(Register rd, Register rn, Label* l) { beq(rd, rn, l); } |
1232 beq(rd, rn, l); | |
1233 } | |
1234 | 1189 |
1235 void BranchEqual(Register rd, const Immediate& imm, Label* l) { | 1190 void BranchEqual(Register rd, const Immediate& imm, Label* l) { |
1236 ASSERT(!in_delay_slot_); | 1191 ASSERT(!in_delay_slot_); |
1237 if (imm.value() == 0) { | 1192 if (imm.value() == 0) { |
1238 beq(rd, ZR, l); | 1193 beq(rd, ZR, l); |
1239 } else { | 1194 } else { |
1240 ASSERT(rd != CMPRES2); | 1195 ASSERT(rd != CMPRES2); |
1241 LoadImmediate(CMPRES2, imm.value()); | 1196 LoadImmediate(CMPRES2, imm.value()); |
1242 beq(rd, CMPRES2, l); | 1197 beq(rd, CMPRES2, l); |
1243 } | 1198 } |
1244 } | 1199 } |
1245 | 1200 |
1246 void BranchEqual(Register rd, const Object& object, Label* l) { | 1201 void BranchEqual(Register rd, const Object& object, Label* l) { |
1247 ASSERT(!in_delay_slot_); | 1202 ASSERT(!in_delay_slot_); |
1248 ASSERT(rd != CMPRES2); | 1203 ASSERT(rd != CMPRES2); |
1249 LoadObject(CMPRES2, object); | 1204 LoadObject(CMPRES2, object); |
1250 beq(rd, CMPRES2, l); | 1205 beq(rd, CMPRES2, l); |
1251 } | 1206 } |
1252 | 1207 |
1253 void BranchNotEqual(Register rd, Register rn, Label* l) { | 1208 void BranchNotEqual(Register rd, Register rn, Label* l) { bne(rd, rn, l); } |
1254 bne(rd, rn, l); | |
1255 } | |
1256 | 1209 |
1257 void BranchNotEqual(Register rd, const Immediate& imm, Label* l) { | 1210 void BranchNotEqual(Register rd, const Immediate& imm, Label* l) { |
1258 ASSERT(!in_delay_slot_); | 1211 ASSERT(!in_delay_slot_); |
1259 if (imm.value() == 0) { | 1212 if (imm.value() == 0) { |
1260 bne(rd, ZR, l); | 1213 bne(rd, ZR, l); |
1261 } else { | 1214 } else { |
1262 ASSERT(rd != CMPRES2); | 1215 ASSERT(rd != CMPRES2); |
1263 LoadImmediate(CMPRES2, imm.value()); | 1216 LoadImmediate(CMPRES2, imm.value()); |
1264 bne(rd, CMPRES2, l); | 1217 bne(rd, CMPRES2, l); |
1265 } | 1218 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1312 ASSERT(rd != CMPRES2); | 1265 ASSERT(rd != CMPRES2); |
1313 LoadImmediate(CMPRES2, imm.value()); | 1266 LoadImmediate(CMPRES2, imm.value()); |
1314 BranchUnsignedGreater(rd, CMPRES2, l); | 1267 BranchUnsignedGreater(rd, CMPRES2, l); |
1315 } | 1268 } |
1316 } | 1269 } |
1317 } | 1270 } |
1318 | 1271 |
1319 void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { | 1272 void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { |
1320 ASSERT(!in_delay_slot_); | 1273 ASSERT(!in_delay_slot_); |
1321 slt(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. | 1274 slt(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. |
1322 beq(CMPRES2, ZR, l); // If CMPRES2 = 0, then rd >= rs. | 1275 beq(CMPRES2, ZR, l); // If CMPRES2 = 0, then rd >= rs. |
1323 } | 1276 } |
1324 | 1277 |
1325 void BranchSignedGreaterEqual(Register rd, const Immediate& imm, Label* l) { | 1278 void BranchSignedGreaterEqual(Register rd, const Immediate& imm, Label* l) { |
1326 ASSERT(!in_delay_slot_); | 1279 ASSERT(!in_delay_slot_); |
1327 if (imm.value() == 0) { | 1280 if (imm.value() == 0) { |
1328 bgez(rd, l); | 1281 bgez(rd, l); |
1329 } else { | 1282 } else { |
1330 if (Utils::IsInt(kImmBits, imm.value())) { | 1283 if (Utils::IsInt(kImmBits, imm.value())) { |
1331 slti(CMPRES2, rd, imm); | 1284 slti(CMPRES2, rd, imm); |
1332 beq(CMPRES2, ZR, l); | 1285 beq(CMPRES2, ZR, l); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 addiu(SP, SP, Immediate(-kWordSize)); | 1402 addiu(SP, SP, Immediate(-kWordSize)); |
1450 sw(rt, Address(SP)); | 1403 sw(rt, Address(SP)); |
1451 } | 1404 } |
1452 | 1405 |
1453 void Pop(Register rt) { | 1406 void Pop(Register rt) { |
1454 ASSERT(!in_delay_slot_); | 1407 ASSERT(!in_delay_slot_); |
1455 lw(rt, Address(SP)); | 1408 lw(rt, Address(SP)); |
1456 addiu(SP, SP, Immediate(kWordSize)); | 1409 addiu(SP, SP, Immediate(kWordSize)); |
1457 } | 1410 } |
1458 | 1411 |
1459 void Ret() { | 1412 void Ret() { jr(RA); } |
1460 jr(RA); | |
1461 } | |
1462 | 1413 |
1463 void SmiTag(Register reg) { | 1414 void SmiTag(Register reg) { sll(reg, reg, kSmiTagSize); } |
1464 sll(reg, reg, kSmiTagSize); | |
1465 } | |
1466 | 1415 |
1467 void SmiTag(Register dst, Register src) { | 1416 void SmiTag(Register dst, Register src) { sll(dst, src, kSmiTagSize); } |
1468 sll(dst, src, kSmiTagSize); | |
1469 } | |
1470 | 1417 |
1471 void SmiUntag(Register reg) { | 1418 void SmiUntag(Register reg) { sra(reg, reg, kSmiTagSize); } |
1472 sra(reg, reg, kSmiTagSize); | |
1473 } | |
1474 | 1419 |
1475 void SmiUntag(Register dst, Register src) { | 1420 void SmiUntag(Register dst, Register src) { sra(dst, src, kSmiTagSize); } |
1476 sra(dst, src, kSmiTagSize); | |
1477 } | |
1478 | 1421 |
1479 void BranchIfNotSmi(Register reg, Label* label) { | 1422 void BranchIfNotSmi(Register reg, Label* label) { |
1480 andi(CMPRES1, reg, Immediate(kSmiTagMask)); | 1423 andi(CMPRES1, reg, Immediate(kSmiTagMask)); |
1481 bne(CMPRES1, ZR, label); | 1424 bne(CMPRES1, ZR, label); |
1482 } | 1425 } |
1483 | 1426 |
1484 void LoadFromOffset(Register reg, Register base, int32_t offset) { | 1427 void LoadFromOffset(Register reg, Register base, int32_t offset) { |
1485 ASSERT(!in_delay_slot_); | 1428 ASSERT(!in_delay_slot_); |
1486 if (Utils::IsInt(kImmBits, offset)) { | 1429 if (Utils::IsInt(kImmBits, offset)) { |
1487 lw(reg, Address(base, offset)); | 1430 lw(reg, Address(base, offset)); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1551 void PushObject(const Object& object); | 1494 void PushObject(const Object& object); |
1552 | 1495 |
1553 void LoadIsolate(Register result); | 1496 void LoadIsolate(Register result); |
1554 | 1497 |
1555 void LoadClassId(Register result, Register object); | 1498 void LoadClassId(Register result, Register object); |
1556 void LoadClassById(Register result, Register class_id); | 1499 void LoadClassById(Register result, Register class_id); |
1557 void LoadClass(Register result, Register object); | 1500 void LoadClass(Register result, Register object); |
1558 void LoadClassIdMayBeSmi(Register result, Register object); | 1501 void LoadClassIdMayBeSmi(Register result, Register object); |
1559 void LoadTaggedClassIdMayBeSmi(Register result, Register object); | 1502 void LoadTaggedClassIdMayBeSmi(Register result, Register object); |
1560 | 1503 |
1561 void StoreIntoObject(Register object, // Object we are storing into. | 1504 void StoreIntoObject(Register object, // Object we are storing into. |
1562 const Address& dest, // Where we are storing into. | 1505 const Address& dest, // Where we are storing into. |
1563 Register value, // Value we are storing. | 1506 Register value, // Value we are storing. |
1564 bool can_value_be_smi = true); | 1507 bool can_value_be_smi = true); |
1565 void StoreIntoObjectOffset(Register object, | 1508 void StoreIntoObjectOffset(Register object, |
1566 int32_t offset, | 1509 int32_t offset, |
1567 Register value, | 1510 Register value, |
1568 bool can_value_be_smi = true); | 1511 bool can_value_be_smi = true); |
1569 | 1512 |
1570 void StoreIntoObjectNoBarrier(Register object, | 1513 void StoreIntoObjectNoBarrier(Register object, |
1571 const Address& dest, | 1514 const Address& dest, |
1572 Register value); | 1515 Register value); |
1573 void StoreIntoObjectNoBarrierOffset(Register object, | 1516 void StoreIntoObjectNoBarrierOffset(Register object, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1627 | 1570 |
1628 static Address VMTagAddress() { | 1571 static Address VMTagAddress() { |
1629 return Address(THR, Thread::vm_tag_offset()); | 1572 return Address(THR, Thread::vm_tag_offset()); |
1630 } | 1573 } |
1631 | 1574 |
1632 // On some other platforms, we draw a distinction between safe and unsafe | 1575 // On some other platforms, we draw a distinction between safe and unsafe |
1633 // smis. | 1576 // smis. |
1634 static bool IsSafe(const Object& object) { return true; } | 1577 static bool IsSafe(const Object& object) { return true; } |
1635 static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } | 1578 static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } |
1636 | 1579 |
1637 bool constant_pool_allowed() const { | 1580 bool constant_pool_allowed() const { return constant_pool_allowed_; } |
1638 return constant_pool_allowed_; | 1581 void set_constant_pool_allowed(bool b) { constant_pool_allowed_ = b; } |
1639 } | |
1640 void set_constant_pool_allowed(bool b) { | |
1641 constant_pool_allowed_ = b; | |
1642 } | |
1643 | 1582 |
1644 private: | 1583 private: |
1645 AssemblerBuffer buffer_; | 1584 AssemblerBuffer buffer_; |
1646 ObjectPoolWrapper object_pool_wrapper_; | 1585 ObjectPoolWrapper object_pool_wrapper_; |
1647 | 1586 |
1648 intptr_t prologue_offset_; | 1587 intptr_t prologue_offset_; |
1649 bool has_single_entry_point_; | 1588 bool has_single_entry_point_; |
1650 bool use_far_branches_; | 1589 bool use_far_branches_; |
1651 bool delay_slot_available_; | 1590 bool delay_slot_available_; |
1652 bool in_delay_slot_; | 1591 bool in_delay_slot_; |
1653 | 1592 |
1654 class CodeComment : public ZoneAllocated { | 1593 class CodeComment : public ZoneAllocated { |
1655 public: | 1594 public: |
1656 CodeComment(intptr_t pc_offset, const String& comment) | 1595 CodeComment(intptr_t pc_offset, const String& comment) |
1657 : pc_offset_(pc_offset), comment_(comment) { } | 1596 : pc_offset_(pc_offset), comment_(comment) {} |
1658 | 1597 |
1659 intptr_t pc_offset() const { return pc_offset_; } | 1598 intptr_t pc_offset() const { return pc_offset_; } |
1660 const String& comment() const { return comment_; } | 1599 const String& comment() const { return comment_; } |
1661 | 1600 |
1662 private: | 1601 private: |
1663 intptr_t pc_offset_; | 1602 intptr_t pc_offset_; |
1664 const String& comment_; | 1603 const String& comment_; |
1665 | 1604 |
1666 DISALLOW_COPY_AND_ASSIGN(CodeComment); | 1605 DISALLOW_COPY_AND_ASSIGN(CodeComment); |
1667 }; | 1606 }; |
(...skipping 13 matching lines...) Expand all Loading... |
1681 void Emit(int32_t value) { | 1620 void Emit(int32_t value) { |
1682 // Emitting an instruction clears the delay slot state. | 1621 // Emitting an instruction clears the delay slot state. |
1683 in_delay_slot_ = false; | 1622 in_delay_slot_ = false; |
1684 delay_slot_available_ = false; | 1623 delay_slot_available_ = false; |
1685 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 1624 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
1686 buffer_.Emit<int32_t>(value); | 1625 buffer_.Emit<int32_t>(value); |
1687 } | 1626 } |
1688 | 1627 |
1689 // Encode CPU instructions according to the types specified in | 1628 // Encode CPU instructions according to the types specified in |
1690 // Figures 4-1, 4-2 and 4-3 in VolI-A. | 1629 // Figures 4-1, 4-2 and 4-3 in VolI-A. |
1691 void EmitIType(Opcode opcode, | 1630 void EmitIType(Opcode opcode, Register rs, Register rt, uint16_t imm) { |
1692 Register rs, | 1631 Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift | imm); |
1693 Register rt, | |
1694 uint16_t imm) { | |
1695 Emit(opcode << kOpcodeShift | | |
1696 rs << kRsShift | | |
1697 rt << kRtShift | | |
1698 imm); | |
1699 } | 1632 } |
1700 | 1633 |
1701 void EmitLoadStore(Opcode opcode, Register rt, | 1634 void EmitLoadStore(Opcode opcode, Register rt, const Address& addr) { |
1702 const Address &addr) { | 1635 Emit(opcode << kOpcodeShift | rt << kRtShift | addr.encoding()); |
1703 Emit(opcode << kOpcodeShift | | |
1704 rt << kRtShift | | |
1705 addr.encoding()); | |
1706 } | 1636 } |
1707 | 1637 |
1708 void EmitFpuLoadStore(Opcode opcode, FRegister ft, | 1638 void EmitFpuLoadStore(Opcode opcode, FRegister ft, const Address& addr) { |
1709 const Address &addr) { | 1639 Emit(opcode << kOpcodeShift | ft << kFtShift | addr.encoding()); |
1710 Emit(opcode << kOpcodeShift | | |
1711 ft << kFtShift | | |
1712 addr.encoding()); | |
1713 } | 1640 } |
1714 | 1641 |
1715 void EmitRegImmType(Opcode opcode, | 1642 void EmitRegImmType(Opcode opcode, Register rs, RtRegImm code, uint16_t imm) { |
1716 Register rs, | 1643 Emit(opcode << kOpcodeShift | rs << kRsShift | code << kRtShift | imm); |
1717 RtRegImm code, | |
1718 uint16_t imm) { | |
1719 Emit(opcode << kOpcodeShift | | |
1720 rs << kRsShift | | |
1721 code << kRtShift | | |
1722 imm); | |
1723 } | 1644 } |
1724 | 1645 |
1725 void EmitJType(Opcode opcode, uint32_t destination) { | 1646 void EmitJType(Opcode opcode, uint32_t destination) { UNIMPLEMENTED(); } |
1726 UNIMPLEMENTED(); | |
1727 } | |
1728 | 1647 |
1729 void EmitRType(Opcode opcode, | 1648 void EmitRType(Opcode opcode, |
1730 Register rs, | 1649 Register rs, |
1731 Register rt, | 1650 Register rt, |
1732 Register rd, | 1651 Register rd, |
1733 int sa, | 1652 int sa, |
1734 SpecialFunction func) { | 1653 SpecialFunction func) { |
1735 ASSERT(Utils::IsUint(5, sa)); | 1654 ASSERT(Utils::IsUint(5, sa)); |
1736 Emit(opcode << kOpcodeShift | | 1655 Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift | |
1737 rs << kRsShift | | 1656 rd << kRdShift | sa << kSaShift | func << kFunctionShift); |
1738 rt << kRtShift | | |
1739 rd << kRdShift | | |
1740 sa << kSaShift | | |
1741 func << kFunctionShift); | |
1742 } | 1657 } |
1743 | 1658 |
1744 void EmitFpuRType(Opcode opcode, | 1659 void EmitFpuRType(Opcode opcode, |
1745 Format fmt, | 1660 Format fmt, |
1746 FRegister ft, | 1661 FRegister ft, |
1747 FRegister fs, | 1662 FRegister fs, |
1748 FRegister fd, | 1663 FRegister fd, |
1749 Cop1Function func) { | 1664 Cop1Function func) { |
1750 Emit(opcode << kOpcodeShift | | 1665 Emit(opcode << kOpcodeShift | fmt << kFmtShift | ft << kFtShift | |
1751 fmt << kFmtShift | | 1666 fs << kFsShift | fd << kFdShift | func << kCop1FnShift); |
1752 ft << kFtShift | | |
1753 fs << kFsShift | | |
1754 fd << kFdShift | | |
1755 func << kCop1FnShift); | |
1756 } | 1667 } |
1757 | 1668 |
1758 int32_t EncodeBranchOffset(int32_t offset, int32_t instr); | 1669 int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
1759 | 1670 |
1760 void EmitFarJump(int32_t offset, bool link); | 1671 void EmitFarJump(int32_t offset, bool link); |
1761 void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset); | 1672 void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset); |
1762 void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset); | 1673 void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset); |
1763 void EmitFarFpuBranch(bool kind, int32_t offset); | 1674 void EmitFarFpuBranch(bool kind, int32_t offset); |
1764 void EmitBranch(Opcode b, Register rs, Register rt, Label* label); | 1675 void EmitBranch(Opcode b, Register rs, Register rt, Label* label); |
1765 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label); | 1676 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label); |
1766 void EmitFpuBranch(bool kind, Label *label); | 1677 void EmitFpuBranch(bool kind, Label* label); |
1767 | 1678 |
1768 void EmitBranchDelayNop() { | 1679 void EmitBranchDelayNop() { |
1769 Emit(Instr::kNopInstruction); // Branch delay NOP. | 1680 Emit(Instr::kNopInstruction); // Branch delay NOP. |
1770 delay_slot_available_ = true; | 1681 delay_slot_available_ = true; |
1771 } | 1682 } |
1772 | 1683 |
1773 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); | 1684 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); |
1774 | 1685 |
1775 // Shorter filtering sequence that assumes that value is not a smi. | 1686 // Shorter filtering sequence that assumes that value is not a smi. |
1776 void StoreIntoObjectFilterNoSmi(Register object, | 1687 void StoreIntoObjectFilterNoSmi(Register object, |
1777 Register value, | 1688 Register value, |
1778 Label* no_update); | 1689 Label* no_update); |
1779 | 1690 |
1780 DISALLOW_ALLOCATION(); | 1691 DISALLOW_ALLOCATION(); |
1781 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1692 DISALLOW_COPY_AND_ASSIGN(Assembler); |
1782 }; | 1693 }; |
1783 | 1694 |
1784 } // namespace dart | 1695 } // namespace dart |
1785 | 1696 |
1786 #endif // RUNTIME_VM_ASSEMBLER_MIPS_H_ | 1697 #endif // RUNTIME_VM_ASSEMBLER_MIPS_H_ |
OLD | NEW |