1 /*
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
19 #include "base/casts.h"
20 #include "entrypoints/quick/quick_entrypoints.h"
21 #include "memory_region.h"
22 #include "thread.h"
23
24 namespace art {
25 namespace mips {
26 #if 0
27 class 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
operator <<(std::ostream & os,const DRegister & rhs)39 std::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
Emit(int32_t value)48 void MipsAssembler::Emit(int32_t value) {
49 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
50 buffer_.Emit<int32_t>(value);
51 }
52
EmitR(int opcode,Register rs,Register rt,Register rd,int shamt,int funct)53 void 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
EmitI(int opcode,Register rs,Register rt,uint16_t imm)66 void 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
EmitJ(int opcode,int address)76 void MipsAssembler::EmitJ(int opcode, int address) {
77 int32_t encoding = opcode << kOpcodeShift |
78 address;
79 Emit(encoding);
80 }
81
EmitFR(int opcode,int fmt,FRegister ft,FRegister fs,FRegister fd,int funct)82 void 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
EmitFI(int opcode,int fmt,FRegister rt,uint16_t imm)95 void 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
EmitBranch(Register rt,Register rs,Label * label,bool equal)104 void 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
EmitJump(Label * label,bool link)120 void 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
EncodeBranchOffset(int offset,int32_t inst,bool is_jump)136 int32_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
DecodeBranchOffset(int32_t inst,bool is_jump)151 int 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
Bind(Label * label,bool is_jump)160 void 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
Add(Register rd,Register rs,Register rt)174 void MipsAssembler::Add(Register rd, Register rs, Register rt) {
175 EmitR(0, rs, rt, rd, 0, 0x20);
176 }
177
Addu(Register rd,Register rs,Register rt)178 void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
179 EmitR(0, rs, rt, rd, 0, 0x21);
180 }
181
Addi(Register rt,Register rs,uint16_t imm16)182 void MipsAssembler::Addi(Register rt, Register rs, uint16_t imm16) {
183 EmitI(0x8, rs, rt, imm16);
184 }
185
Addiu(Register rt,Register rs,uint16_t imm16)186 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
187 EmitI(0x9, rs, rt, imm16);
188 }
189
Sub(Register rd,Register rs,Register rt)190 void MipsAssembler::Sub(Register rd, Register rs, Register rt) {
191 EmitR(0, rs, rt, rd, 0, 0x22);
192 }
193
Subu(Register rd,Register rs,Register rt)194 void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
195 EmitR(0, rs, rt, rd, 0, 0x23);
196 }
197
Mult(Register rs,Register rt)198 void MipsAssembler::Mult(Register rs, Register rt) {
199 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
200 }
201
Multu(Register rs,Register rt)202 void MipsAssembler::Multu(Register rs, Register rt) {
203 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
204 }
205
Div(Register rs,Register rt)206 void MipsAssembler::Div(Register rs, Register rt) {
207 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
208 }
209
Divu(Register rs,Register rt)210 void MipsAssembler::Divu(Register rs, Register rt) {
211 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
212 }
213
And(Register rd,Register rs,Register rt)214 void MipsAssembler::And(Register rd, Register rs, Register rt) {
215 EmitR(0, rs, rt, rd, 0, 0x24);
216 }
217
Andi(Register rt,Register rs,uint16_t imm16)218 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
219 EmitI(0xc, rs, rt, imm16);
220 }
221
Or(Register rd,Register rs,Register rt)222 void MipsAssembler::Or(Register rd, Register rs, Register rt) {
223 EmitR(0, rs, rt, rd, 0, 0x25);
224 }
225
Ori(Register rt,Register rs,uint16_t imm16)226 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
227 EmitI(0xd, rs, rt, imm16);
228 }
229
Xor(Register rd,Register rs,Register rt)230 void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
231 EmitR(0, rs, rt, rd, 0, 0x26);
232 }
233
Xori(Register rt,Register rs,uint16_t imm16)234 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
235 EmitI(0xe, rs, rt, imm16);
236 }
237
Nor(Register rd,Register rs,Register rt)238 void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
239 EmitR(0, rs, rt, rd, 0, 0x27);
240 }
241
Sll(Register rd,Register rs,int shamt)242 void MipsAssembler::Sll(Register rd, Register rs, int shamt) {
243 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x00);
244 }
245
Srl(Register rd,Register rs,int shamt)246 void MipsAssembler::Srl(Register rd, Register rs, int shamt) {
247 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x02);
248 }
249
Sra(Register rd,Register rs,int shamt)250 void MipsAssembler::Sra(Register rd, Register rs, int shamt) {
251 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x03);
252 }
253
Sllv(Register rd,Register rs,Register rt)254 void MipsAssembler::Sllv(Register rd, Register rs, Register rt) {
255 EmitR(0, rs, rt, rd, 0, 0x04);
256 }
257
Srlv(Register rd,Register rs,Register rt)258 void MipsAssembler::Srlv(Register rd, Register rs, Register rt) {
259 EmitR(0, rs, rt, rd, 0, 0x06);
260 }
261
Srav(Register rd,Register rs,Register rt)262 void MipsAssembler::Srav(Register rd, Register rs, Register rt) {
263 EmitR(0, rs, rt, rd, 0, 0x07);
264 }
265
Lb(Register rt,Register rs,uint16_t imm16)266 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
267 EmitI(0x20, rs, rt, imm16);
268 }
269
Lh(Register rt,Register rs,uint16_t imm16)270 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
271 EmitI(0x21, rs, rt, imm16);
272 }
273
Lw(Register rt,Register rs,uint16_t imm16)274 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
275 EmitI(0x23, rs, rt, imm16);
276 }
277
Lbu(Register rt,Register rs,uint16_t imm16)278 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
279 EmitI(0x24, rs, rt, imm16);
280 }
281
Lhu(Register rt,Register rs,uint16_t imm16)282 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
283 EmitI(0x25, rs, rt, imm16);
284 }
285
Lui(Register rt,uint16_t imm16)286 void MipsAssembler::Lui(Register rt, uint16_t imm16) {
287 EmitI(0xf, static_cast<Register>(0), rt, imm16);
288 }
289
Mfhi(Register rd)290 void MipsAssembler::Mfhi(Register rd) {
291 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
292 }
293
Mflo(Register rd)294 void MipsAssembler::Mflo(Register rd) {
295 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
296 }
297
Sb(Register rt,Register rs,uint16_t imm16)298 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
299 EmitI(0x28, rs, rt, imm16);
300 }
301
Sh(Register rt,Register rs,uint16_t imm16)302 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
303 EmitI(0x29, rs, rt, imm16);
304 }
305
Sw(Register rt,Register rs,uint16_t imm16)306 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
307 EmitI(0x2b, rs, rt, imm16);
308 }
309
Slt(Register rd,Register rs,Register rt)310 void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
311 EmitR(0, rs, rt, rd, 0, 0x2a);
312 }
313
Sltu(Register rd,Register rs,Register rt)314 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
315 EmitR(0, rs, rt, rd, 0, 0x2b);
316 }
317
Slti(Register rt,Register rs,uint16_t imm16)318 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
319 EmitI(0xa, rs, rt, imm16);
320 }
321
Sltiu(Register rt,Register rs,uint16_t imm16)322 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
323 EmitI(0xb, rs, rt, imm16);
324 }
325
Beq(Register rt,Register rs,uint16_t imm16)326 void MipsAssembler::Beq(Register rt, Register rs, uint16_t imm16) {
327 EmitI(0x4, rs, rt, imm16);
328 Nop();
329 }
330
Bne(Register rt,Register rs,uint16_t imm16)331 void MipsAssembler::Bne(Register rt, Register rs, uint16_t imm16) {
332 EmitI(0x5, rs, rt, imm16);
333 Nop();
334 }
335
J(uint32_t address)336 void MipsAssembler::J(uint32_t address) {
337 EmitJ(0x2, address);
338 Nop();
339 }
340
Jal(uint32_t address)341 void MipsAssembler::Jal(uint32_t address) {
342 EmitJ(0x2, address);
343 Nop();
344 }
345
Jr(Register rs)346 void MipsAssembler::Jr(Register rs) {
347 EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x08);
348 Nop();
349 }
350
Jalr(Register rs)351 void MipsAssembler::Jalr(Register rs) {
352 EmitR(0, rs, static_cast<Register>(0), RA, 0, 0x09);
353 Nop();
354 }
355
AddS(FRegister fd,FRegister fs,FRegister ft)356 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
357 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
358 }
359
SubS(FRegister fd,FRegister fs,FRegister ft)360 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
361 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
362 }
363
MulS(FRegister fd,FRegister fs,FRegister ft)364 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
365 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
366 }
367
DivS(FRegister fd,FRegister fs,FRegister ft)368 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
369 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
370 }
371
AddD(DRegister fd,DRegister fs,DRegister ft)372 void 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
SubD(DRegister fd,DRegister fs,DRegister ft)377 void 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
MulD(DRegister fd,DRegister fs,DRegister ft)382 void 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
DivD(DRegister fd,DRegister fs,DRegister ft)387 void 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
MovS(FRegister fd,FRegister fs)392 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
393 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
394 }
395
MovD(DRegister fd,DRegister fs)396 void 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
Mfc1(Register rt,FRegister fs)401 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
402 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
403 }
404
Mtc1(FRegister ft,Register rs)405 void MipsAssembler::Mtc1(FRegister ft, Register rs) {
406 EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0);
407 }
408
Lwc1(FRegister ft,Register rs,uint16_t imm16)409 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
410 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
411 }
412
Ldc1(DRegister ft,Register rs,uint16_t imm16)413 void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) {
414 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
415 }
416
Swc1(FRegister ft,Register rs,uint16_t imm16)417 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
418 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
419 }
420
Sdc1(DRegister ft,Register rs,uint16_t imm16)421 void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) {
422 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
423 }
424
Break()425 void MipsAssembler::Break() {
426 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
427 static_cast<Register>(0), 0, 0xD);
428 }
429
Nop()430 void MipsAssembler::Nop() {
431 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
432 }
433
Move(Register rt,Register rs)434 void MipsAssembler::Move(Register rt, Register rs) {
435 EmitI(0x8, rs, rt, 0);
436 }
437
Clear(Register rt)438 void MipsAssembler::Clear(Register rt) {
439 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rt, 0, 0x20);
440 }
441
Not(Register rt,Register rs)442 void MipsAssembler::Not(Register rt, Register rs) {
443 EmitR(0, static_cast<Register>(0), rs, rt, 0, 0x27);
444 }
445
Mul(Register rd,Register rs,Register rt)446 void MipsAssembler::Mul(Register rd, Register rs, Register rt) {
447 Mult(rs, rt);
448 Mflo(rd);
449 }
450
Div(Register rd,Register rs,Register rt)451 void MipsAssembler::Div(Register rd, Register rs, Register rt) {
452 Div(rs, rt);
453 Mflo(rd);
454 }
455
Rem(Register rd,Register rs,Register rt)456 void MipsAssembler::Rem(Register rd, Register rs, Register rt) {
457 Div(rs, rt);
458 Mfhi(rd);
459 }
460
AddConstant(Register rt,Register rs,int32_t value)461 void MipsAssembler::AddConstant(Register rt, Register rs, int32_t value) {
462 Addi(rt, rs, value);
463 }
464
LoadImmediate(Register rt,int32_t value)465 void MipsAssembler::LoadImmediate(Register rt, int32_t value) {
466 Addi(rt, ZERO, value);
467 }
468
EmitLoad(ManagedRegister m_dst,Register src_register,int32_t src_offset,size_t size)469 void 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
LoadFromOffset(LoadOperandType type,Register reg,Register base,int32_t offset)489 void 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
LoadSFromOffset(FRegister reg,Register base,int32_t offset)515 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
516 Lwc1(reg, base, offset);
517 }
518
LoadDFromOffset(DRegister reg,Register base,int32_t offset)519 void MipsAssembler::LoadDFromOffset(DRegister reg, Register base, int32_t offset) {
520 Ldc1(reg, base, offset);
521 }
522
StoreToOffset(StoreOperandType type,Register reg,Register base,int32_t offset)523 void 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
StoreFToOffset(FRegister reg,Register base,int32_t offset)543 void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) {
544 Swc1(reg, base, offset);
545 }
546
StoreDToOffset(DRegister reg,Register base,int32_t offset)547 void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) {
548 Sdc1(reg, base, offset);
549 }
550
BuildFrame(size_t frame_size,ManagedRegister method_reg,const std::vector<ManagedRegister> & callee_save_regs,const std::vector<ManagedRegister> & entry_spills)551 void 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
RemoveFrame(size_t frame_size,const std::vector<ManagedRegister> & callee_save_regs)578 void 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);
593
594 // Then jump to the return address.
595 Jr(RA);
596 }
597
IncreaseFrameSize(size_t adjust)598 void MipsAssembler::IncreaseFrameSize(size_t adjust) {
599 CHECK_ALIGNED(adjust, kStackAlignment);
600 AddConstant(SP, SP, -adjust);
601 }
602
DecreaseFrameSize(size_t adjust)603 void MipsAssembler::DecreaseFrameSize(size_t adjust) {
604 CHECK_ALIGNED(adjust, kStackAlignment);
605 AddConstant(SP, SP, adjust);
606 }
607
Store(FrameOffset dest,ManagedRegister msrc,size_t size)608 void 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
StoreRef(FrameOffset dest,ManagedRegister msrc)628 void 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
StoreRawPtr(FrameOffset dest,ManagedRegister msrc)634 void 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
StoreImmediateToFrame(FrameOffset dest,uint32_t imm,ManagedRegister mscratch)640 void 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
StoreImmediateToThread(ThreadOffset dest,uint32_t imm,ManagedRegister mscratch)648 void 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
StoreStackOffsetToThread(ThreadOffset thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)656 void 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
StoreStackPointerToThread(ThreadOffset thr_offs)666 void MipsAssembler::StoreStackPointerToThread(ThreadOffset thr_offs) {
667 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
668 }
669
StoreSpanning(FrameOffset dest,ManagedRegister msrc,FrameOffset in_off,ManagedRegister mscratch)670 void 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
Load(ManagedRegister mdest,FrameOffset src,size_t size)679 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
680 return EmitLoad(mdest, SP, src.Int32Value(), size);
681 }
682
Load(ManagedRegister mdest,ThreadOffset src,size_t size)683 void MipsAssembler::Load(ManagedRegister mdest, ThreadOffset src, size_t size) {
684 return EmitLoad(mdest, S1, src.Int32Value(), size);
685 }
686
LoadRef(ManagedRegister mdest,FrameOffset src)687 void 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
LoadRef(ManagedRegister mdest,ManagedRegister base,MemberOffset offs)693 void 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
LoadRawPtr(ManagedRegister mdest,ManagedRegister base,Offset offs)701 void 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
LoadRawPtrFromThread(ManagedRegister mdest,ThreadOffset offs)709 void 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
SignExtend(ManagedRegister,size_t)716 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
717 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
718 }
719
ZeroExtend(ManagedRegister,size_t)720 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
721 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
722 }
723
Move(ManagedRegister mdest,ManagedRegister msrc,size_t)724 void 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
CopyRef(FrameOffset dest,FrameOffset src,ManagedRegister mscratch)752 void 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
CopyRawPtrFromThread(FrameOffset fr_offs,ThreadOffset thr_offs,ManagedRegister mscratch)760 void 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
CopyRawPtrToThread(ThreadOffset thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)771 void 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
Copy(FrameOffset dest,FrameOffset src,ManagedRegister mscratch,size_t size)782 void 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
Copy(FrameOffset dest,ManagedRegister src_base,Offset src_offset,ManagedRegister mscratch,size_t size)798 void 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
Copy(ManagedRegister dest_base,Offset dest_offset,FrameOffset src,ManagedRegister mscratch,size_t size)806 void 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
Copy(FrameOffset,FrameOffset,Offset,ManagedRegister,size_t)814 void MipsAssembler::Copy(FrameOffset /*dest*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
815 ManagedRegister /*mscratch*/, size_t /*size*/) {
816 UNIMPLEMENTED(FATAL) << "no mips implementation";
817 }
818
Copy(ManagedRegister dest,Offset dest_offset,ManagedRegister src,Offset src_offset,ManagedRegister mscratch,size_t size)819 void 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
Copy(FrameOffset,Offset,FrameOffset,Offset,ManagedRegister,size_t)828 void MipsAssembler::Copy(FrameOffset /*dest*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/,
829 ManagedRegister /*mscratch*/, size_t /*size*/) {
830 UNIMPLEMENTED(FATAL) << "no mips implementation";
831 }
832
MemoryBarrier(ManagedRegister)833 void MipsAssembler::MemoryBarrier(ManagedRegister) {
834 UNIMPLEMENTED(FATAL) << "no mips implementation";
835 }
836
CreateSirtEntry(ManagedRegister mout_reg,FrameOffset sirt_offset,ManagedRegister min_reg,bool null_allowed)837 void 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
CreateSirtEntry(FrameOffset out_off,FrameOffset sirt_offset,ManagedRegister mscratch,bool null_allowed)865 void 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.
LoadReferenceFromSirt(ManagedRegister mout_reg,ManagedRegister min_reg)888 void 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
VerifyObject(ManagedRegister,bool)904 void MipsAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
905 // TODO: not validating references
906 }
907
VerifyObject(FrameOffset,bool)908 void MipsAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
909 // TODO: not validating references
910 }
911
Call(ManagedRegister mbase,Offset offset,ManagedRegister mscratch)912 void 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
Call(FrameOffset base,Offset offset,ManagedRegister mscratch)923 void 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
Call(ThreadOffset,ManagedRegister)935 void MipsAssembler::Call(ThreadOffset /*offset*/, ManagedRegister /*mscratch*/) {
936 UNIMPLEMENTED(FATAL) << "no mips implementation";
937 }
938
GetCurrentThread(ManagedRegister tr)939 void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
940 Move(tr.AsMips().AsCoreRegister(), S1);
941 }
942
GetCurrentThread(FrameOffset offset,ManagedRegister)943 void MipsAssembler::GetCurrentThread(FrameOffset offset,
944 ManagedRegister /*mscratch*/) {
945 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
946 }
947
ExceptionPoll(ManagedRegister mscratch,size_t stack_adjust)948 void 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
Emit(Assembler * sasm)957 void 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
968 __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(pDeliverException).Int32Value());
969 __ Jr(T9);
970 // Call never returns
971 __ Break();
972 #undef __
973 }
974
975 } // namespace mips
976 } // namespace art
977