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 VM_ASSEMBLER_MIPS_H_ | 5 #ifndef VM_ASSEMBLER_MIPS_H_ |
6 #define VM_ASSEMBLER_MIPS_H_ | 6 #define VM_ASSEMBLER_MIPS_H_ |
7 | 7 |
8 #ifndef VM_ASSEMBLER_H_ | 8 #ifndef 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 offset_ = other.offset_; | 51 offset_ = other.offset_; |
52 return *this; | 52 return *this; |
53 } | 53 } |
54 | 54 |
55 uint32_t encoding() const { | 55 uint32_t encoding() const { |
56 ASSERT(Utils::IsInt(16, offset_)); | 56 ASSERT(Utils::IsInt(16, offset_)); |
57 uint16_t imm_value = static_cast<uint16_t>(offset_); | 57 uint16_t imm_value = static_cast<uint16_t>(offset_); |
58 return (base_ << kRsShift) | imm_value; | 58 return (base_ << kRsShift) | imm_value; |
59 } | 59 } |
60 | 60 |
61 static bool CanHoldOffset(int32_t offset) { | |
62 return Utils::IsInt(16, offset); | |
63 } | |
64 | |
61 private: | 65 private: |
62 Register base_; | 66 Register base_; |
63 int32_t offset_; | 67 int32_t offset_; |
64 }; | 68 }; |
65 | 69 |
66 | 70 |
67 class FieldAddress : public Address { | 71 class FieldAddress : public Address { |
68 public: | 72 public: |
69 FieldAddress(Register base, int32_t disp) | 73 FieldAddress(Register base, int32_t disp) |
70 : Address(base, disp - kHeapObjectTag) { } | 74 : Address(base, disp - kHeapObjectTag) { } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 public: | 140 public: |
137 Assembler() | 141 Assembler() |
138 : buffer_(), | 142 : buffer_(), |
139 object_pool_(GrowableObjectArray::Handle()), | 143 object_pool_(GrowableObjectArray::Handle()), |
140 prologue_offset_(-1), | 144 prologue_offset_(-1), |
141 delay_slot_available_(false), | 145 delay_slot_available_(false), |
142 in_delay_slot_(false), | 146 in_delay_slot_(false), |
143 comments_() { } | 147 comments_() { } |
144 ~Assembler() { } | 148 ~Assembler() { } |
145 | 149 |
146 void PopRegister(Register r) { | 150 void PopRegister(Register r) { Pop(r); } |
147 UNIMPLEMENTED(); | |
148 } | |
149 | 151 |
150 void Bind(Label* label); | 152 void Bind(Label* label); |
151 | 153 |
152 // Misc. functionality | 154 // Misc. functionality |
153 int CodeSize() const { return buffer_.Size(); } | 155 int CodeSize() const { return buffer_.Size(); } |
154 int prologue_offset() const { return -1; } | 156 int prologue_offset() const { return -1; } |
155 const ZoneGrowableArray<int>& GetPointerOffsets() const { | 157 const ZoneGrowableArray<int>& GetPointerOffsets() const { |
156 return buffer_.pointer_offsets(); | 158 return buffer_.pointer_offsets(); |
157 } | 159 } |
158 const GrowableObjectArray& object_pool() const { return object_pool_; } | 160 const GrowableObjectArray& object_pool() const { return object_pool_; } |
(...skipping 24 matching lines...) Expand all Loading... | |
183 // Allocated instance is returned in 'instance_reg'. | 185 // Allocated instance is returned in 'instance_reg'. |
184 // Only the tags field of the object is initialized. | 186 // Only the tags field of the object is initialized. |
185 void TryAllocate(const Class& cls, | 187 void TryAllocate(const Class& cls, |
186 Label* failure, | 188 Label* failure, |
187 bool near_jump, | 189 bool near_jump, |
188 Register instance_reg) { | 190 Register instance_reg) { |
189 UNIMPLEMENTED(); | 191 UNIMPLEMENTED(); |
190 } | 192 } |
191 | 193 |
192 // Debugging and bringup support. | 194 // Debugging and bringup support. |
193 void Stop(const char* message) { UNIMPLEMENTED(); } | 195 void Stop(const char* message); |
194 void Unimplemented(const char* message); | 196 void Unimplemented(const char* message); |
195 void Untested(const char* message); | 197 void Untested(const char* message); |
196 void Unreachable(const char* message); | 198 void Unreachable(const char* message); |
197 | 199 |
198 static void InitializeMemoryWithBreakpoints(uword data, int length); | 200 static void InitializeMemoryWithBreakpoints(uword data, int length); |
199 | 201 |
200 void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); | 202 void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
201 | 203 |
202 const Code::Comments& GetCodeComments() const; | 204 const Code::Comments& GetCodeComments() const; |
203 | 205 |
(...skipping 14 matching lines...) Expand all Loading... | |
218 Instr::kNopInstruction); | 220 Instr::kNopInstruction); |
219 buffer_.Remit<int32_t>(); | 221 buffer_.Remit<int32_t>(); |
220 delay_slot_available_ = false; | 222 delay_slot_available_ = false; |
221 in_delay_slot_ = true; | 223 in_delay_slot_ = true; |
222 return this; | 224 return this; |
223 } | 225 } |
224 | 226 |
225 // CPU instructions in alphabetical order. | 227 // CPU instructions in alphabetical order. |
226 void addiu(Register rt, Register rs, const Immediate& imm) { | 228 void addiu(Register rt, Register rs, const Immediate& imm) { |
227 ASSERT(Utils::IsInt(16, imm.value())); | 229 ASSERT(Utils::IsInt(16, imm.value())); |
228 uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 230 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
229 EmitIType(ADDIU, rs, rt, imm_value); | 231 EmitIType(ADDIU, rs, rt, imm_value); |
230 } | 232 } |
231 | 233 |
232 void addu(Register rd, Register rs, Register rt) { | 234 void addu(Register rd, Register rs, Register rt) { |
233 EmitRType(SPECIAL, rs, rt, rd, 0, ADDU); | 235 EmitRType(SPECIAL, rs, rt, rd, 0, ADDU); |
234 } | 236 } |
235 | 237 |
236 void and_(Register rd, Register rs, Register rt) { | 238 void and_(Register rd, Register rs, Register rt) { |
237 EmitRType(SPECIAL, rs, rt, rd, 0, AND); | 239 EmitRType(SPECIAL, rs, rt, rd, 0, AND); |
238 } | 240 } |
239 | 241 |
240 void andi(Register rt, Register rs, const Immediate& imm) { | 242 void andi(Register rt, Register rs, const Immediate& imm) { |
241 ASSERT(Utils::IsUint(16, imm.value())); | 243 ASSERT(Utils::IsUint(16, imm.value())); |
242 uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 244 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
243 EmitIType(ANDI, rs, rt, imm_value); | 245 EmitIType(ANDI, rs, rt, imm_value); |
244 } | 246 } |
245 | 247 |
246 // Unconditional branch. | 248 // Unconditional branch. |
247 void b(Label* l) { | 249 void b(Label* l) { |
248 beq(R0, R0, l); | 250 beq(R0, R0, l); |
249 } | 251 } |
250 | 252 |
251 // Branch if equal. | 253 // Branch if equal. |
252 void beq(Register rs, Register rt, Label* l) { | 254 void beq(Register rs, Register rt, Label* l) { |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
496 | 498 |
497 void sw(Register rt, const Address& addr) { | 499 void sw(Register rt, const Address& addr) { |
498 EmitLoadStore(SW, rt, addr); | 500 EmitLoadStore(SW, rt, addr); |
499 } | 501 } |
500 | 502 |
501 void xor_(Register rd, Register rs, Register rt) { | 503 void xor_(Register rd, Register rs, Register rt) { |
502 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); | 504 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); |
503 } | 505 } |
504 | 506 |
505 // Macros in alphabetical order. | 507 // Macros in alphabetical order. |
508 | |
509 void Branch(const ExternalLabel* label) { | |
510 // Doesn't need to be patchable, so use the delay slot. | |
511 if (Utils::IsInt(16, label->address())) { | |
512 jr(TMP); | |
513 delay_slot()->addiu(TMP, ZR, Immediate(label->address())); | |
514 } else { | |
515 const uint16_t low = Utils::Low16Bits(label->address()); | |
516 const uint16_t high = Utils::High16Bits(label->address()); | |
517 lui(TMP, Immediate(high)); | |
518 jr(TMP); | |
519 delay_slot()->ori(TMP, TMP, Immediate(low)); | |
520 } | |
521 } | |
522 | |
523 void BranchLink(const ExternalLabel* label) { | |
524 // Doesn't need to be patchable, so use the delay slot. | |
525 if (Utils::IsInt(16, label->address())) { | |
526 jalr(TMP); | |
527 delay_slot()->addiu(TMP, ZR, Immediate(label->address())); | |
528 } else { | |
529 const uint16_t low = Utils::Low16Bits(label->address()); | |
530 const uint16_t high = Utils::High16Bits(label->address()); | |
531 lui(TMP, Immediate(high)); | |
532 jalr(TMP); | |
533 delay_slot()->ori(TMP, TMP, Immediate(low)); | |
534 } | |
535 } | |
536 | |
537 void BranchLinkPatchable(const ExternalLabel* label) { | |
538 const int32_t offset = | |
539 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; | |
540 LoadWordFromPoolOffset(TMP, offset); | |
541 jalr(TMP); | |
542 } | |
543 | |
544 void BranchPatchable(const ExternalLabel* label) { | |
545 LoadImmediate(TMP, label->address()); | |
546 jr(TMP); | |
547 } | |
548 | |
549 void Drop(intptr_t stack_elements) { | |
550 ASSERT(stack_elements >= 0); | |
551 if (stack_elements > 0) { | |
552 addiu(SP, SP, Immediate(stack_elements * kWordSize)); | |
553 } | |
554 } | |
555 | |
506 void LoadImmediate(Register rd, int32_t value) { | 556 void LoadImmediate(Register rd, int32_t value) { |
507 if (Utils::IsInt(16, value)) { | 557 if (Utils::IsInt(16, value)) { |
508 addiu(rd, ZR, Immediate(value)); | 558 addiu(rd, ZR, Immediate(value)); |
509 } else { | 559 } else { |
510 lui(rd, Immediate((value >> 16) & 0xffff)); | 560 const uint16_t low = Utils::Low16Bits(value); |
511 ori(rd, rd, Immediate(value & 0xffff)); | 561 const uint16_t high = Utils::High16Bits(value); |
562 lui(rd, Immediate(high)); | |
563 ori(rd, rd, Immediate(low)); | |
512 } | 564 } |
513 } | 565 } |
514 | 566 |
567 void Push(Register rt) { | |
568 addiu(SP, SP, Immediate(-kWordSize)); | |
569 sw(rt, Address(SP)); | |
570 } | |
571 | |
572 void Pop(Register rt) { | |
573 lw(rt, Address(SP)); | |
574 addiu(SP, SP, Immediate(kWordSize)); | |
575 } | |
576 | |
577 void Ret() { | |
578 jr(RA); | |
579 } | |
580 | |
581 void LoadWordFromPoolOffset(Register rd, int32_t offset); | |
582 void LoadObject(Register rd, const Object& object); | |
583 void PushObject(const Object& object); | |
584 | |
585 // Sets register rd to zero if the object is equal to register rn, | |
586 // set to non-zero otherwise. | |
587 void CompareObject(Register rd, Register rn, const Object& object); | |
588 | |
515 private: | 589 private: |
516 AssemblerBuffer buffer_; | 590 AssemblerBuffer buffer_; |
517 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. | 591 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. |
518 int prologue_offset_; | 592 int prologue_offset_; |
519 | 593 |
520 bool delay_slot_available_; | 594 bool delay_slot_available_; |
521 bool in_delay_slot_; | 595 bool in_delay_slot_; |
522 | 596 |
597 int32_t AddObject(const Object& obj); | |
598 int32_t AddExternalLabel(const ExternalLabel* label); | |
599 | |
523 class CodeComment : public ZoneAllocated { | 600 class CodeComment : public ZoneAllocated { |
524 public: | 601 public: |
525 CodeComment(intptr_t pc_offset, const String& comment) | 602 CodeComment(intptr_t pc_offset, const String& comment) |
526 : pc_offset_(pc_offset), comment_(comment) { } | 603 : pc_offset_(pc_offset), comment_(comment) { } |
527 | 604 |
528 intptr_t pc_offset() const { return pc_offset_; } | 605 intptr_t pc_offset() const { return pc_offset_; } |
529 const String& comment() const { return comment_; } | 606 const String& comment() const { return comment_; } |
530 | 607 |
531 private: | 608 private: |
532 intptr_t pc_offset_; | 609 intptr_t pc_offset_; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 Emit(opcode << kOpcodeShift | | 665 Emit(opcode << kOpcodeShift | |
589 rs << kRsShift | | 666 rs << kRsShift | |
590 rt << kRtShift | | 667 rt << kRtShift | |
591 rd << kRdShift | | 668 rd << kRdShift | |
592 sa << kSaShift | | 669 sa << kSaShift | |
593 func << kFunctionShift); | 670 func << kFunctionShift); |
594 } | 671 } |
595 | 672 |
596 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | 673 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
597 if (label->IsBound()) { | 674 if (label->IsBound()) { |
598 // Reletive destination from an instruction after the branch. | 675 // Reletive destination from an instruction after the branch. |
regis
2013/03/26 17:52:35
ditto
regis
2013/03/26 17:52:35
ditto
| |
599 int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); | 676 const int32_t dest = |
600 uint16_t dest_off = EncodeBranchOffset(dest, 0); | 677 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
678 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
601 EmitIType(b, rs, rt, dest_off); | 679 EmitIType(b, rs, rt, dest_off); |
602 } else { | 680 } else { |
603 int position = buffer_.Size(); | 681 const int position = buffer_.Size(); |
604 EmitIType(b, rs, rt, label->position_); | 682 EmitIType(b, rs, rt, label->position_); |
605 label->LinkTo(position); | 683 label->LinkTo(position); |
606 } | 684 } |
607 } | 685 } |
608 | 686 |
609 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 687 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
610 if (label->IsBound()) { | 688 if (label->IsBound()) { |
611 // Reletive destination from an instruction after the branch. | 689 // Reletive destination from an instruction after the branch. |
regis
2013/03/26 17:52:35
ditto
| |
612 int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); | 690 const int32_t dest = |
613 uint16_t dest_off = EncodeBranchOffset(dest, 0); | 691 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
692 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
614 EmitRegImmType(REGIMM, rs, b, dest_off); | 693 EmitRegImmType(REGIMM, rs, b, dest_off); |
615 } else { | 694 } else { |
616 int position = buffer_.Size(); | 695 const int position = buffer_.Size(); |
617 EmitRegImmType(REGIMM, rs, b, label->position_); | 696 EmitRegImmType(REGIMM, rs, b, label->position_); |
618 label->LinkTo(position); | 697 label->LinkTo(position); |
619 } | 698 } |
620 } | 699 } |
621 | 700 |
622 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); | 701 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
623 static int DecodeBranchOffset(int32_t instr); | 702 static int DecodeBranchOffset(int32_t instr); |
624 | 703 |
625 void EmitBranchDelayNop() { | 704 void EmitBranchDelayNop() { |
626 Emit(Instr::kNopInstruction); // Branch delay NOP. | 705 Emit(Instr::kNopInstruction); // Branch delay NOP. |
627 delay_slot_available_ = true; | 706 delay_slot_available_ = true; |
628 } | 707 } |
629 | 708 |
630 DISALLOW_ALLOCATION(); | 709 DISALLOW_ALLOCATION(); |
631 DISALLOW_COPY_AND_ASSIGN(Assembler); | 710 DISALLOW_COPY_AND_ASSIGN(Assembler); |
632 }; | 711 }; |
633 | 712 |
634 } // namespace dart | 713 } // namespace dart |
635 | 714 |
636 #endif // VM_ASSEMBLER_MIPS_H_ | 715 #endif // VM_ASSEMBLER_MIPS_H_ |
OLD | NEW |