blob: 2be3d56cfa04ac91607e8240d562bcc5d95d38e6 [file] [log] [blame]
jeffhao7fbee072012-08-24 17:56:54 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips.h"
18
Elliott Hughes1aa246d2012-12-13 09:29:36 -080019#include "base/casts.h"
Ian Rogers166db042013-07-26 12:05:57 -070020#include "entrypoints/quick/quick_entrypoints.h"
jeffhao7fbee072012-08-24 17:56:54 -070021#include "memory_region.h"
jeffhao7fbee072012-08-24 17:56:54 -070022#include "thread.h"
23
24namespace art {
25namespace mips {
26#if 0
27class DirectCallRelocation : public AssemblerFixup {
28 public:
29 void Process(const MemoryRegion& region, int position) {
30 // Direct calls are relative to the following instruction on mips.
31 int32_t pointer = region.Load<int32_t>(position);
32 int32_t start = reinterpret_cast<int32_t>(region.start());
33 int32_t delta = start + position + sizeof(int32_t);
34 region.Store<int32_t>(position, pointer - delta);
35 }
36};
37#endif
38
jeffhao7fbee072012-08-24 17:56:54 -070039std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
40 if (rhs >= D0 && rhs < kNumberOfDRegisters) {
41 os << "d" << static_cast<int>(rhs);
42 } else {
43 os << "DRegister[" << static_cast<int>(rhs) << "]";
44 }
45 return os;
46}
47
48void MipsAssembler::Emit(int32_t value) {
49 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
50 buffer_.Emit<int32_t>(value);
51}
52
53void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
54 CHECK_NE(rs, kNoRegister);
55 CHECK_NE(rt, kNoRegister);
56 CHECK_NE(rd, kNoRegister);
57 int32_t encoding = opcode << kOpcodeShift |
58 static_cast<int32_t>(rs) << kRsShift |
59 static_cast<int32_t>(rt) << kRtShift |
60 static_cast<int32_t>(rd) << kRdShift |
61 shamt << kShamtShift |
62 funct;
63 Emit(encoding);
64}
65
66void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
67 CHECK_NE(rs, kNoRegister);
68 CHECK_NE(rt, kNoRegister);
69 int32_t encoding = opcode << kOpcodeShift |
70 static_cast<int32_t>(rs) << kRsShift |
71 static_cast<int32_t>(rt) << kRtShift |
72 imm;
73 Emit(encoding);
74}
75
76void MipsAssembler::EmitJ(int opcode, int address) {
77 int32_t encoding = opcode << kOpcodeShift |
78 address;
79 Emit(encoding);
80}
81
82void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct) {
83 CHECK_NE(ft, kNoFRegister);
84 CHECK_NE(fs, kNoFRegister);
85 CHECK_NE(fd, kNoFRegister);
86 int32_t encoding = opcode << kOpcodeShift |
87 fmt << kFmtShift |
88 static_cast<int32_t>(ft) << kFtShift |
89 static_cast<int32_t>(fs) << kFsShift |
90 static_cast<int32_t>(fd) << kFdShift |
91 funct;
92 Emit(encoding);
93}
94
95void MipsAssembler::EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm) {
96 CHECK_NE(rt, kNoFRegister);
97 int32_t encoding = opcode << kOpcodeShift |
98 fmt << kFmtShift |
99 static_cast<int32_t>(rt) << kRtShift |
100 imm;
101 Emit(encoding);
102}
103
104void MipsAssembler::EmitBranch(Register rt, Register rs, Label* label, bool equal) {
105 int offset;
106 if (label->IsBound()) {
107 offset = label->Position() - buffer_.Size();
108 } else {
109 // Use the offset field of the branch instruction for linking the sites.
110 offset = label->position_;
111 label->LinkTo(buffer_.Size());
112 }
113 if (equal) {
114 Beq(rt, rs, (offset >> 2) & kBranchOffsetMask);
115 } else {
116 Bne(rt, rs, (offset >> 2) & kBranchOffsetMask);
117 }
118}
119
120void MipsAssembler::EmitJump(Label* label, bool link) {
121 int offset;
122 if (label->IsBound()) {
123 offset = label->Position() - buffer_.Size();
124 } else {
125 // Use the offset field of the jump instruction for linking the sites.
126 offset = label->position_;
127 label->LinkTo(buffer_.Size());
128 }
129 if (link) {
130 Jal((offset >> 2) & kJumpOffsetMask);
131 } else {
132 J((offset >> 2) & kJumpOffsetMask);
133 }
134}
135
136int32_t MipsAssembler::EncodeBranchOffset(int offset, int32_t inst, bool is_jump) {
137 CHECK_ALIGNED(offset, 4);
138 CHECK(IsInt(CountOneBits(kBranchOffsetMask), offset)) << offset;
139
140 // Properly preserve only the bits supported in the instruction.
141 offset >>= 2;
142 if (is_jump) {
143 offset &= kJumpOffsetMask;
144 return (inst & ~kJumpOffsetMask) | offset;
145 } else {
146 offset &= kBranchOffsetMask;
147 return (inst & ~kBranchOffsetMask) | offset;
148 }
149}
150
151int MipsAssembler::DecodeBranchOffset(int32_t inst, bool is_jump) {
152 // Sign-extend, then left-shift by 2.
153 if (is_jump) {
154 return (((inst & kJumpOffsetMask) << 6) >> 4);
155 } else {
156 return (((inst & kBranchOffsetMask) << 16) >> 14);
157 }
158}
159
160void MipsAssembler::Bind(Label* label, bool is_jump) {
161 CHECK(!label->IsBound());
162 int bound_pc = buffer_.Size();
163 while (label->IsLinked()) {
164 int32_t position = label->Position();
165 int32_t next = buffer_.Load<int32_t>(position);
166 int32_t offset = is_jump ? bound_pc - position : bound_pc - position - 4;
167 int32_t encoded = MipsAssembler::EncodeBranchOffset(offset, next, is_jump);
168 buffer_.Store<int32_t>(position, encoded);
169 label->position_ = MipsAssembler::DecodeBranchOffset(next, is_jump);
170 }
171 label->BindTo(bound_pc);
172}
173
174void MipsAssembler::Add(Register rd, Register rs, Register rt) {
175 EmitR(0, rs, rt, rd, 0, 0x20);
176}
177
178void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
179 EmitR(0, rs, rt, rd, 0, 0x21);
180}
181
182void MipsAssembler::Addi(Register rt, Register rs, uint16_t imm16) {
183 EmitI(0x8, rs, rt, imm16);
184}
185
186void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
187 EmitI(0x9, rs, rt, imm16);
188}
189
190void MipsAssembler::Sub(Register rd, Register rs, Register rt) {
191 EmitR(0, rs, rt, rd, 0, 0x22);
192}
193
194void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
195 EmitR(0, rs, rt, rd, 0, 0x23);
196}
197
198void MipsAssembler::Mult(Register rs, Register rt) {
199 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
200}
201
202void MipsAssembler::Multu(Register rs, Register rt) {
203 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
204}
205
206void MipsAssembler::Div(Register rs, Register rt) {
207 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
208}
209
210void MipsAssembler::Divu(Register rs, Register rt) {
211 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
212}
213
214void MipsAssembler::And(Register rd, Register rs, Register rt) {
215 EmitR(0, rs, rt, rd, 0, 0x24);
216}
217
218void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
219 EmitI(0xc, rs, rt, imm16);
220}
221
222void MipsAssembler::Or(Register rd, Register rs, Register rt) {
223 EmitR(0, rs, rt, rd, 0, 0x25);
224}
225
226void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
227 EmitI(0xd, rs, rt, imm16);
228}
229
230void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
231 EmitR(0, rs, rt, rd, 0, 0x26);
232}
233
234void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
235 EmitI(0xe, rs, rt, imm16);
236}
237
238void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
239 EmitR(0, rs, rt, rd, 0, 0x27);
240}
241
242void MipsAssembler::Sll(Register rd, Register rs, int shamt) {
243 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x00);
244}
245
246void MipsAssembler::Srl(Register rd, Register rs, int shamt) {
247 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x02);
248}
249
250void MipsAssembler::Sra(Register rd, Register rs, int shamt) {
251 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x03);
252}
253
254void MipsAssembler::Sllv(Register rd, Register rs, Register rt) {
255 EmitR(0, rs, rt, rd, 0, 0x04);
256}
257
258void MipsAssembler::Srlv(Register rd, Register rs, Register rt) {
259 EmitR(0, rs, rt, rd, 0, 0x06);
260}
261
262void MipsAssembler::Srav(Register rd, Register rs, Register rt) {
263 EmitR(0, rs, rt, rd, 0, 0x07);
264}
265
266void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
267 EmitI(0x20, rs, rt, imm16);
268}
269
270void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
271 EmitI(0x21, rs, rt, imm16);
272}
273
274void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
275 EmitI(0x23, rs, rt, imm16);
276}
277
278void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
279 EmitI(0x24, rs, rt, imm16);
280}
281
282void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
283 EmitI(0x25, rs, rt, imm16);
284}
285
286void MipsAssembler::Lui(Register rt, uint16_t imm16) {
287 EmitI(0xf, static_cast<Register>(0), rt, imm16);
288}
289
290void MipsAssembler::Mfhi(Register rd) {
291 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
292}
293
294void MipsAssembler::Mflo(Register rd) {
295 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
296}
297
298void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
299 EmitI(0x28, rs, rt, imm16);
300}
301
302void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
303 EmitI(0x29, rs, rt, imm16);
304}
305
306void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
307 EmitI(0x2b, rs, rt, imm16);
308}
309
310void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
311 EmitR(0, rs, rt, rd, 0, 0x2a);
312}
313
314void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
315 EmitR(0, rs, rt, rd, 0, 0x2b);
316}
317
318void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
319 EmitI(0xa, rs, rt, imm16);
320}
321
322void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
323 EmitI(0xb, rs, rt, imm16);
324}
325
326void MipsAssembler::Beq(Register rt, Register rs, uint16_t imm16) {
327 EmitI(0x4, rs, rt, imm16);
jeffhao07030602012-09-26 14:33:14 -0700328 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700329}
330
331void MipsAssembler::Bne(Register rt, Register rs, uint16_t imm16) {
332 EmitI(0x5, rs, rt, imm16);
jeffhao07030602012-09-26 14:33:14 -0700333 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700334}
335
336void MipsAssembler::J(uint32_t address) {
337 EmitJ(0x2, address);
jeffhao07030602012-09-26 14:33:14 -0700338 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700339}
340
341void MipsAssembler::Jal(uint32_t address) {
342 EmitJ(0x2, address);
jeffhao07030602012-09-26 14:33:14 -0700343 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700344}
345
346void MipsAssembler::Jr(Register rs) {
347 EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x08);
jeffhao07030602012-09-26 14:33:14 -0700348 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700349}
350
351void MipsAssembler::Jalr(Register rs) {
jeffhao07030602012-09-26 14:33:14 -0700352 EmitR(0, rs, static_cast<Register>(0), RA, 0, 0x09);
353 Nop();
jeffhao7fbee072012-08-24 17:56:54 -0700354}
355
356void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
357 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
358}
359
360void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
361 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
362}
363
364void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
365 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
366}
367
368void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
369 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
370}
371
372void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) {
373 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
374 static_cast<FRegister>(fd), 0x0);
375}
376
377void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) {
378 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
379 static_cast<FRegister>(fd), 0x1);
380}
381
382void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) {
383 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
384 static_cast<FRegister>(fd), 0x2);
385}
386
387void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) {
388 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
389 static_cast<FRegister>(fd), 0x3);
390}
391
392void MipsAssembler::MovS(FRegister fd, FRegister fs) {
393 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
394}
395
396void MipsAssembler::MovD(DRegister fd, DRegister fs) {
397 EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs),
398 static_cast<FRegister>(fd), 0x6);
399}
400
401void MipsAssembler::Mfc1(Register rt, FRegister fs) {
402 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
403}
404
405void MipsAssembler::Mtc1(FRegister ft, Register rs) {
406 EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0);
407}
408
409void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
410 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
411}
412
413void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) {
414 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
415}
416
417void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
418 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
419}
420
421void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) {
422 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
423}
424
425void MipsAssembler::Break() {
426 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
427 static_cast<Register>(0), 0, 0xD);
428}
429
jeffhao07030602012-09-26 14:33:14 -0700430void MipsAssembler::Nop() {
431 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
432}
433
jeffhao7fbee072012-08-24 17:56:54 -0700434void MipsAssembler::Move(Register rt, Register rs) {
435 EmitI(0x8, rs, rt, 0);
436}
437
438void MipsAssembler::Clear(Register rt) {
439 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rt, 0, 0x20);
440}
441
442void MipsAssembler::Not(Register rt, Register rs) {
443 EmitR(0, static_cast<Register>(0), rs, rt, 0, 0x27);
444}
445
446void MipsAssembler::Mul(Register rd, Register rs, Register rt) {
447 Mult(rs, rt);
448 Mflo(rd);
449}
450
451void MipsAssembler::Div(Register rd, Register rs, Register rt) {
452 Div(rs, rt);
453 Mflo(rd);
454}
455
456void MipsAssembler::Rem(Register rd, Register rs, Register rt) {
457 Div(rs, rt);
458 Mfhi(rd);
459}
460
461void MipsAssembler::AddConstant(Register rt, Register rs, int32_t value) {
462 Addi(rt, rs, value);
463}
464
465void MipsAssembler::LoadImmediate(Register rt, int32_t value) {
466 Addi(rt, ZERO, value);
467}
468
469void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
470 size_t size) {
471 MipsManagedRegister dst = m_dst.AsMips();
472 if (dst.IsNoRegister()) {
473 CHECK_EQ(0u, size) << dst;
474 } else if (dst.IsCoreRegister()) {
475 CHECK_EQ(4u, size) << dst;
476 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
477 } else if (dst.IsRegisterPair()) {
478 CHECK_EQ(8u, size) << dst;
479 LoadFromOffset(kLoadWord, dst.AsRegisterPairLow(), src_register, src_offset);
480 LoadFromOffset(kLoadWord, dst.AsRegisterPairHigh(), src_register, src_offset + 4);
481 } else if (dst.IsFRegister()) {
482 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
483 } else {
484 CHECK(dst.IsDRegister()) << dst;
485 LoadDFromOffset(dst.AsDRegister(), src_register, src_offset);
486 }
487}
488
489void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
490 int32_t offset) {
491 switch (type) {
492 case kLoadSignedByte:
493 Lb(reg, base, offset);
494 break;
495 case kLoadUnsignedByte:
496 Lbu(reg, base, offset);
497 break;
498 case kLoadSignedHalfword:
499 Lh(reg, base, offset);
500 break;
501 case kLoadUnsignedHalfword:
502 Lhu(reg, base, offset);
503 break;
504 case kLoadWord:
505 Lw(reg, base, offset);
506 break;
507 case kLoadWordPair:
508 LOG(FATAL) << "UNREACHABLE";
509 break;
510 default:
511 LOG(FATAL) << "UNREACHABLE";
512 }
513}
514
515void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
516 Lwc1(reg, base, offset);
517}
518
519void MipsAssembler::LoadDFromOffset(DRegister reg, Register base, int32_t offset) {
520 Ldc1(reg, base, offset);
521}
522
523void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
524 int32_t offset) {
525 switch (type) {
526 case kStoreByte:
527 Sb(reg, base, offset);
528 break;
529 case kStoreHalfword:
530 Sh(reg, base, offset);
531 break;
532 case kStoreWord:
533 Sw(reg, base, offset);
534 break;
535 case kStoreWordPair:
536 LOG(FATAL) << "UNREACHABLE";
537 break;
538 default:
539 LOG(FATAL) << "UNREACHABLE";
540 }
541}
542
543void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) {
544 Swc1(reg, base, offset);
545}
546
547void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) {
548 Sdc1(reg, base, offset);
549}
550
551void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
552 const std::vector<ManagedRegister>& callee_save_regs,
553 const std::vector<ManagedRegister>& entry_spills) {
554 CHECK_ALIGNED(frame_size, kStackAlignment);
555
556 // Increase frame to required size.
557 IncreaseFrameSize(frame_size);
558
559 // Push callee saves and return address
560 int stack_offset = frame_size - kPointerSize;
561 StoreToOffset(kStoreWord, RA, SP, stack_offset);
562 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
563 stack_offset -= kPointerSize;
564 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
565 StoreToOffset(kStoreWord, reg, SP, stack_offset);
566 }
567
568 // Write out Method*.
569 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
570
571 // Write out entry spills.
572 for (size_t i = 0; i < entry_spills.size(); ++i) {
573 Register reg = entry_spills.at(i).AsMips().AsCoreRegister();
574 StoreToOffset(kStoreWord, reg, SP, frame_size + kPointerSize + (i * kPointerSize));
575 }
576}
577
578void MipsAssembler::RemoveFrame(size_t frame_size,
579 const std::vector<ManagedRegister>& callee_save_regs) {
580 CHECK_ALIGNED(frame_size, kStackAlignment);
581
582 // Pop callee saves and return address
583 int stack_offset = frame_size - (callee_save_regs.size() * kPointerSize) - kPointerSize;
584 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
585 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
586 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
587 stack_offset += kPointerSize;
588 }
589 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
590
591 // Decrease frame to required size.
592 DecreaseFrameSize(frame_size);
jeffhao07030602012-09-26 14:33:14 -0700593
594 // Then jump to the return address.
595 Jr(RA);
jeffhao7fbee072012-08-24 17:56:54 -0700596}
597
598void MipsAssembler::IncreaseFrameSize(size_t adjust) {
599 CHECK_ALIGNED(adjust, kStackAlignment);
600 AddConstant(SP, SP, -adjust);
601}
602
603void MipsAssembler::DecreaseFrameSize(size_t adjust) {
604 CHECK_ALIGNED(adjust, kStackAlignment);
605 AddConstant(SP, SP, adjust);
606}
607
608void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
609 MipsManagedRegister src = msrc.AsMips();
610 if (src.IsNoRegister()) {
611 CHECK_EQ(0u, size);
612 } else if (src.IsCoreRegister()) {
613 CHECK_EQ(4u, size);
614 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
615 } else if (src.IsRegisterPair()) {
616 CHECK_EQ(8u, size);
617 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
618 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
619 SP, dest.Int32Value() + 4);
620 } else if (src.IsFRegister()) {
621 StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value());
622 } else {
623 CHECK(src.IsDRegister());
624 StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value());
625 }
626}
627
628void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
629 MipsManagedRegister src = msrc.AsMips();
630 CHECK(src.IsCoreRegister());
631 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
632}
633
634void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
635 MipsManagedRegister src = msrc.AsMips();
636 CHECK(src.IsCoreRegister());
637 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
638}
639
640void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
641 ManagedRegister mscratch) {
642 MipsManagedRegister scratch = mscratch.AsMips();
643 CHECK(scratch.IsCoreRegister()) << scratch;
644 LoadImmediate(scratch.AsCoreRegister(), imm);
645 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
646}
647
648void MipsAssembler::StoreImmediateToThread(ThreadOffset dest, uint32_t imm,
649 ManagedRegister mscratch) {
650 MipsManagedRegister scratch = mscratch.AsMips();
651 CHECK(scratch.IsCoreRegister()) << scratch;
652 LoadImmediate(scratch.AsCoreRegister(), imm);
653 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
654}
655
656void MipsAssembler::StoreStackOffsetToThread(ThreadOffset thr_offs,
657 FrameOffset fr_offs,
658 ManagedRegister mscratch) {
659 MipsManagedRegister scratch = mscratch.AsMips();
660 CHECK(scratch.IsCoreRegister()) << scratch;
661 AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
662 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
663 S1, thr_offs.Int32Value());
664}
665
666void MipsAssembler::StoreStackPointerToThread(ThreadOffset thr_offs) {
667 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
668}
669
670void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
671 FrameOffset in_off, ManagedRegister mscratch) {
672 MipsManagedRegister src = msrc.AsMips();
673 MipsManagedRegister scratch = mscratch.AsMips();
674 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
675 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
676 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
677}
678
679void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
680 return EmitLoad(mdest, SP, src.Int32Value(), size);
681}
682
683void MipsAssembler::Load(ManagedRegister mdest, ThreadOffset src, size_t size) {
684 return EmitLoad(mdest, S1, src.Int32Value(), size);
685}
686
687void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
688 MipsManagedRegister dest = mdest.AsMips();
689 CHECK(dest.IsCoreRegister());
690 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
691}
692
693void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base,
694 MemberOffset offs) {
695 MipsManagedRegister dest = mdest.AsMips();
696 CHECK(dest.IsCoreRegister() && dest.IsCoreRegister());
697 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
698 base.AsMips().AsCoreRegister(), offs.Int32Value());
699}
700
701void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
702 Offset offs) {
703 MipsManagedRegister dest = mdest.AsMips();
704 CHECK(dest.IsCoreRegister() && dest.IsCoreRegister()) << dest;
705 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
706 base.AsMips().AsCoreRegister(), offs.Int32Value());
707}
708
709void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest,
710 ThreadOffset offs) {
711 MipsManagedRegister dest = mdest.AsMips();
712 CHECK(dest.IsCoreRegister());
713 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
714}
715
716void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
717 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
718}
719
720void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
721 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
722}
723
724void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t /*size*/) {
725 MipsManagedRegister dest = mdest.AsMips();
726 MipsManagedRegister src = msrc.AsMips();
727 if (!dest.Equals(src)) {
728 if (dest.IsCoreRegister()) {
729 CHECK(src.IsCoreRegister()) << src;
730 Move(dest.AsCoreRegister(), src.AsCoreRegister());
731 } else if (dest.IsFRegister()) {
732 CHECK(src.IsFRegister()) << src;
733 MovS(dest.AsFRegister(), src.AsFRegister());
734 } else if (dest.IsDRegister()) {
735 CHECK(src.IsDRegister()) << src;
736 MovD(dest.AsDRegister(), src.AsDRegister());
737 } else {
738 CHECK(dest.IsRegisterPair()) << dest;
739 CHECK(src.IsRegisterPair()) << src;
740 // Ensure that the first move doesn't clobber the input of the second
741 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
742 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
743 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
744 } else {
745 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
746 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
747 }
748 }
749 }
750}
751
752void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src,
753 ManagedRegister mscratch) {
754 MipsManagedRegister scratch = mscratch.AsMips();
755 CHECK(scratch.IsCoreRegister()) << scratch;
756 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
757 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
758}
759
760void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
761 ThreadOffset thr_offs,
762 ManagedRegister mscratch) {
763 MipsManagedRegister scratch = mscratch.AsMips();
764 CHECK(scratch.IsCoreRegister()) << scratch;
765 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
766 S1, thr_offs.Int32Value());
767 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
768 SP, fr_offs.Int32Value());
769}
770
771void MipsAssembler::CopyRawPtrToThread(ThreadOffset thr_offs,
772 FrameOffset fr_offs,
773 ManagedRegister mscratch) {
774 MipsManagedRegister scratch = mscratch.AsMips();
775 CHECK(scratch.IsCoreRegister()) << scratch;
776 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
777 SP, fr_offs.Int32Value());
778 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
779 S1, thr_offs.Int32Value());
780}
781
782void MipsAssembler::Copy(FrameOffset dest, FrameOffset src,
783 ManagedRegister mscratch, size_t size) {
784 MipsManagedRegister scratch = mscratch.AsMips();
785 CHECK(scratch.IsCoreRegister()) << scratch;
786 CHECK(size == 4 || size == 8) << size;
787 if (size == 4) {
788 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
789 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
790 } else if (size == 8) {
791 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
792 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
793 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + 4);
794 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
795 }
796}
797
798void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
799 ManagedRegister mscratch, size_t size) {
800 Register scratch = mscratch.AsMips().AsCoreRegister();
801 CHECK_EQ(size, 4u);
802 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
803 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
804}
805
806void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
807 ManagedRegister mscratch, size_t size) {
808 Register scratch = mscratch.AsMips().AsCoreRegister();
809 CHECK_EQ(size, 4u);
810 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
811 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
812}
813
814void MipsAssembler::Copy(FrameOffset /*dest*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
815 ManagedRegister /*mscratch*/, size_t /*size*/) {
Ian Rogers468532e2013-08-05 10:56:33 -0700816 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -0700817}
818
819void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
820 ManagedRegister src, Offset src_offset,
821 ManagedRegister mscratch, size_t size) {
822 CHECK_EQ(size, 4u);
823 Register scratch = mscratch.AsMips().AsCoreRegister();
824 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
825 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
826}
827
828void MipsAssembler::Copy(FrameOffset /*dest*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/,
829 ManagedRegister /*mscratch*/, size_t /*size*/) {
Ian Rogers468532e2013-08-05 10:56:33 -0700830 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -0700831}
832
833void MipsAssembler::MemoryBarrier(ManagedRegister) {
Ian Rogers468532e2013-08-05 10:56:33 -0700834 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -0700835}
836
837void MipsAssembler::CreateSirtEntry(ManagedRegister mout_reg,
838 FrameOffset sirt_offset,
839 ManagedRegister min_reg, bool null_allowed) {
840 MipsManagedRegister out_reg = mout_reg.AsMips();
841 MipsManagedRegister in_reg = min_reg.AsMips();
842 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
843 CHECK(out_reg.IsCoreRegister()) << out_reg;
844 if (null_allowed) {
845 Label null_arg;
846 // Null values get a SIRT entry value of 0. Otherwise, the SIRT entry is
847 // the address in the SIRT holding the reference.
848 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
849 if (in_reg.IsNoRegister()) {
850 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
851 SP, sirt_offset.Int32Value());
852 in_reg = out_reg;
853 }
854 if (!out_reg.Equals(in_reg)) {
855 LoadImmediate(out_reg.AsCoreRegister(), 0);
856 }
857 EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true);
858 AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value());
859 Bind(&null_arg, false);
860 } else {
861 AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value());
862 }
863}
864
865void MipsAssembler::CreateSirtEntry(FrameOffset out_off,
866 FrameOffset sirt_offset,
867 ManagedRegister mscratch,
868 bool null_allowed) {
869 MipsManagedRegister scratch = mscratch.AsMips();
870 CHECK(scratch.IsCoreRegister()) << scratch;
871 if (null_allowed) {
872 Label null_arg;
873 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
874 sirt_offset.Int32Value());
875 // Null values get a SIRT entry value of 0. Otherwise, the sirt entry is
876 // the address in the SIRT holding the reference.
877 // e.g. scratch = (scratch == 0) ? 0 : (SP+sirt_offset)
878 EmitBranch(scratch.AsCoreRegister(), ZERO, &null_arg, true);
879 AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value());
880 Bind(&null_arg, false);
881 } else {
882 AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value());
883 }
884 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
885}
886
887// Given a SIRT entry, load the associated reference.
888void MipsAssembler::LoadReferenceFromSirt(ManagedRegister mout_reg,
889 ManagedRegister min_reg) {
890 MipsManagedRegister out_reg = mout_reg.AsMips();
891 MipsManagedRegister in_reg = min_reg.AsMips();
892 CHECK(out_reg.IsCoreRegister()) << out_reg;
893 CHECK(in_reg.IsCoreRegister()) << in_reg;
894 Label null_arg;
895 if (!out_reg.Equals(in_reg)) {
896 LoadImmediate(out_reg.AsCoreRegister(), 0);
897 }
898 EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true);
899 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
900 in_reg.AsCoreRegister(), 0);
901 Bind(&null_arg, false);
902}
903
904void MipsAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
905 // TODO: not validating references
906}
907
908void MipsAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
909 // TODO: not validating references
910}
911
912void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
913 MipsManagedRegister base = mbase.AsMips();
914 MipsManagedRegister scratch = mscratch.AsMips();
915 CHECK(base.IsCoreRegister()) << base;
916 CHECK(scratch.IsCoreRegister()) << scratch;
917 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
918 base.AsCoreRegister(), offset.Int32Value());
919 Jalr(scratch.AsCoreRegister());
920 // TODO: place reference map on call
921}
922
923void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
924 MipsManagedRegister scratch = mscratch.AsMips();
925 CHECK(scratch.IsCoreRegister()) << scratch;
926 // Call *(*(SP + base) + offset)
927 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
928 SP, base.Int32Value());
929 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
930 scratch.AsCoreRegister(), offset.Int32Value());
931 Jalr(scratch.AsCoreRegister());
932 // TODO: place reference map on call
933}
934
935void MipsAssembler::Call(ThreadOffset /*offset*/, ManagedRegister /*mscratch*/) {
Ian Rogers468532e2013-08-05 10:56:33 -0700936 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -0700937}
938
939void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
940 Move(tr.AsMips().AsCoreRegister(), S1);
941}
942
943void MipsAssembler::GetCurrentThread(FrameOffset offset,
944 ManagedRegister /*mscratch*/) {
945 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
946}
947
jeffhao7fbee072012-08-24 17:56:54 -0700948void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
949 MipsManagedRegister scratch = mscratch.AsMips();
950 MipsExceptionSlowPath* slow = new MipsExceptionSlowPath(scratch, stack_adjust);
951 buffer_.EnqueueSlowPath(slow);
952 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
953 S1, Thread::ExceptionOffset().Int32Value());
954 EmitBranch(scratch.AsCoreRegister(), ZERO, slow->Entry(), false);
955}
956
957void MipsExceptionSlowPath::Emit(Assembler* sasm) {
958 MipsAssembler* sp_asm = down_cast<MipsAssembler*>(sasm);
959#define __ sp_asm->
960 __ Bind(&entry_, false);
961 if (stack_adjust_ != 0) { // Fix up the frame.
962 __ DecreaseFrameSize(stack_adjust_);
963 }
964 // Pass exception object as argument
965 // Don't care about preserving A0 as this call won't return
966 __ Move(A0, scratch_.AsCoreRegister());
967 // Set up call to Thread::Current()->pDeliverException
Ian Rogers468532e2013-08-05 10:56:33 -0700968 __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(pDeliverException).Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -0700969 __ Jr(T9);
970 // Call never returns
971 __ Break();
972#undef __
973}
974
975} // namespace mips
976} // namespace art