• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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