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