• 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/bit_utils.h"
20 #include "base/casts.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "entrypoints/quick/quick_entrypoints_enum.h"
23 #include "memory_region.h"
24 #include "thread.h"
25 
26 namespace art {
27 namespace mips {
28 
operator <<(std::ostream & os,const DRegister & rhs)29 std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
30   if (rhs >= D0 && rhs < kNumberOfDRegisters) {
31     os << "d" << static_cast<int>(rhs);
32   } else {
33     os << "DRegister[" << static_cast<int>(rhs) << "]";
34   }
35   return os;
36 }
37 
FinalizeCode()38 void MipsAssembler::FinalizeCode() {
39   for (auto& exception_block : exception_blocks_) {
40     EmitExceptionPoll(&exception_block);
41   }
42   PromoteBranches();
43 }
44 
FinalizeInstructions(const MemoryRegion & region)45 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
46   size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
47   EmitBranches();
48   Assembler::FinalizeInstructions(region);
49   PatchCFI(number_of_delayed_adjust_pcs);
50 }
51 
PatchCFI(size_t number_of_delayed_adjust_pcs)52 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
53   if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
54     DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
55     return;
56   }
57 
58   typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
59   const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
60   const std::vector<uint8_t>& old_stream = data.first;
61   const std::vector<DelayedAdvancePC>& advances = data.second;
62 
63   // PCs recorded before EmitBranches() need to be adjusted.
64   // PCs recorded during EmitBranches() are already adjusted.
65   // Both ranges are separately sorted but they may overlap.
66   if (kIsDebugBuild) {
67     auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
68       return lhs.pc < rhs.pc;
69     };
70     CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
71     CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
72   }
73 
74   // Append initial CFI data if any.
75   size_t size = advances.size();
76   DCHECK_NE(size, 0u);
77   cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
78   // Emit PC adjustments interleaved with the old CFI stream.
79   size_t adjust_pos = 0u;
80   size_t late_emit_pos = number_of_delayed_adjust_pcs;
81   while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
82     size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
83         ? GetAdjustedPosition(advances[adjust_pos].pc)
84         : static_cast<size_t>(-1);
85     size_t late_emit_pc = (late_emit_pos != size)
86         ? advances[late_emit_pos].pc
87         : static_cast<size_t>(-1);
88     size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
89     DCHECK_NE(advance_pc, static_cast<size_t>(-1));
90     size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
91     if (adjusted_pc <= late_emit_pc) {
92       ++adjust_pos;
93     } else {
94       ++late_emit_pos;
95     }
96     cfi().AdvancePC(advance_pc);
97     size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
98     cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
99   }
100 }
101 
EmitBranches()102 void MipsAssembler::EmitBranches() {
103   CHECK(!overwriting_);
104   // Switch from appending instructions at the end of the buffer to overwriting
105   // existing instructions (branch placeholders) in the buffer.
106   overwriting_ = true;
107   for (auto& branch : branches_) {
108     EmitBranch(&branch);
109   }
110   overwriting_ = false;
111 }
112 
Emit(uint32_t value)113 void MipsAssembler::Emit(uint32_t value) {
114   if (overwriting_) {
115     // Branches to labels are emitted into their placeholders here.
116     buffer_.Store<uint32_t>(overwrite_location_, value);
117     overwrite_location_ += sizeof(uint32_t);
118   } else {
119     // Other instructions are simply appended at the end here.
120     AssemblerBuffer::EnsureCapacity ensured(&buffer_);
121     buffer_.Emit<uint32_t>(value);
122   }
123 }
124 
EmitR(int opcode,Register rs,Register rt,Register rd,int shamt,int funct)125 void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
126   CHECK_NE(rs, kNoRegister);
127   CHECK_NE(rt, kNoRegister);
128   CHECK_NE(rd, kNoRegister);
129   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
130                       static_cast<uint32_t>(rs) << kRsShift |
131                       static_cast<uint32_t>(rt) << kRtShift |
132                       static_cast<uint32_t>(rd) << kRdShift |
133                       shamt << kShamtShift |
134                       funct;
135   Emit(encoding);
136 }
137 
EmitI(int opcode,Register rs,Register rt,uint16_t imm)138 void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
139   CHECK_NE(rs, kNoRegister);
140   CHECK_NE(rt, kNoRegister);
141   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
142                       static_cast<uint32_t>(rs) << kRsShift |
143                       static_cast<uint32_t>(rt) << kRtShift |
144                       imm;
145   Emit(encoding);
146 }
147 
EmitI21(int opcode,Register rs,uint32_t imm21)148 void MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
149   CHECK_NE(rs, kNoRegister);
150   CHECK(IsUint<21>(imm21)) << imm21;
151   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
152                       static_cast<uint32_t>(rs) << kRsShift |
153                       imm21;
154   Emit(encoding);
155 }
156 
EmitI26(int opcode,uint32_t imm26)157 void MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
158   CHECK(IsUint<26>(imm26)) << imm26;
159   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
160   Emit(encoding);
161 }
162 
EmitFR(int opcode,int fmt,FRegister ft,FRegister fs,FRegister fd,int funct)163 void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd,
164                            int funct) {
165   CHECK_NE(ft, kNoFRegister);
166   CHECK_NE(fs, kNoFRegister);
167   CHECK_NE(fd, kNoFRegister);
168   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
169                       fmt << kFmtShift |
170                       static_cast<uint32_t>(ft) << kFtShift |
171                       static_cast<uint32_t>(fs) << kFsShift |
172                       static_cast<uint32_t>(fd) << kFdShift |
173                       funct;
174   Emit(encoding);
175 }
176 
EmitFI(int opcode,int fmt,FRegister ft,uint16_t imm)177 void MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
178   CHECK_NE(ft, kNoFRegister);
179   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
180                       fmt << kFmtShift |
181                       static_cast<uint32_t>(ft) << kFtShift |
182                       imm;
183   Emit(encoding);
184 }
185 
Addu(Register rd,Register rs,Register rt)186 void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
187   EmitR(0, rs, rt, rd, 0, 0x21);
188 }
189 
Addiu(Register rt,Register rs,uint16_t imm16)190 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
191   EmitI(0x9, rs, rt, imm16);
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 
MultR2(Register rs,Register rt)198 void MipsAssembler::MultR2(Register rs, Register rt) {
199   CHECK(!IsR6());
200   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
201 }
202 
MultuR2(Register rs,Register rt)203 void MipsAssembler::MultuR2(Register rs, Register rt) {
204   CHECK(!IsR6());
205   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
206 }
207 
DivR2(Register rs,Register rt)208 void MipsAssembler::DivR2(Register rs, Register rt) {
209   CHECK(!IsR6());
210   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
211 }
212 
DivuR2(Register rs,Register rt)213 void MipsAssembler::DivuR2(Register rs, Register rt) {
214   CHECK(!IsR6());
215   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
216 }
217 
MulR2(Register rd,Register rs,Register rt)218 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
219   CHECK(!IsR6());
220   EmitR(0x1c, rs, rt, rd, 0, 2);
221 }
222 
DivR2(Register rd,Register rs,Register rt)223 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
224   CHECK(!IsR6());
225   DivR2(rs, rt);
226   Mflo(rd);
227 }
228 
ModR2(Register rd,Register rs,Register rt)229 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
230   CHECK(!IsR6());
231   DivR2(rs, rt);
232   Mfhi(rd);
233 }
234 
DivuR2(Register rd,Register rs,Register rt)235 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
236   CHECK(!IsR6());
237   DivuR2(rs, rt);
238   Mflo(rd);
239 }
240 
ModuR2(Register rd,Register rs,Register rt)241 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
242   CHECK(!IsR6());
243   DivuR2(rs, rt);
244   Mfhi(rd);
245 }
246 
MulR6(Register rd,Register rs,Register rt)247 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
248   CHECK(IsR6());
249   EmitR(0, rs, rt, rd, 2, 0x18);
250 }
251 
MuhR6(Register rd,Register rs,Register rt)252 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
253   CHECK(IsR6());
254   EmitR(0, rs, rt, rd, 3, 0x18);
255 }
256 
MuhuR6(Register rd,Register rs,Register rt)257 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
258   CHECK(IsR6());
259   EmitR(0, rs, rt, rd, 3, 0x19);
260 }
261 
DivR6(Register rd,Register rs,Register rt)262 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
263   CHECK(IsR6());
264   EmitR(0, rs, rt, rd, 2, 0x1a);
265 }
266 
ModR6(Register rd,Register rs,Register rt)267 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
268   CHECK(IsR6());
269   EmitR(0, rs, rt, rd, 3, 0x1a);
270 }
271 
DivuR6(Register rd,Register rs,Register rt)272 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
273   CHECK(IsR6());
274   EmitR(0, rs, rt, rd, 2, 0x1b);
275 }
276 
ModuR6(Register rd,Register rs,Register rt)277 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
278   CHECK(IsR6());
279   EmitR(0, rs, rt, rd, 3, 0x1b);
280 }
281 
And(Register rd,Register rs,Register rt)282 void MipsAssembler::And(Register rd, Register rs, Register rt) {
283   EmitR(0, rs, rt, rd, 0, 0x24);
284 }
285 
Andi(Register rt,Register rs,uint16_t imm16)286 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
287   EmitI(0xc, rs, rt, imm16);
288 }
289 
Or(Register rd,Register rs,Register rt)290 void MipsAssembler::Or(Register rd, Register rs, Register rt) {
291   EmitR(0, rs, rt, rd, 0, 0x25);
292 }
293 
Ori(Register rt,Register rs,uint16_t imm16)294 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
295   EmitI(0xd, rs, rt, imm16);
296 }
297 
Xor(Register rd,Register rs,Register rt)298 void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
299   EmitR(0, rs, rt, rd, 0, 0x26);
300 }
301 
Xori(Register rt,Register rs,uint16_t imm16)302 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
303   EmitI(0xe, rs, rt, imm16);
304 }
305 
Nor(Register rd,Register rs,Register rt)306 void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
307   EmitR(0, rs, rt, rd, 0, 0x27);
308 }
309 
Movz(Register rd,Register rs,Register rt)310 void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
311   CHECK(!IsR6());
312   EmitR(0, rs, rt, rd, 0, 0x0A);
313 }
314 
Movn(Register rd,Register rs,Register rt)315 void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
316   CHECK(!IsR6());
317   EmitR(0, rs, rt, rd, 0, 0x0B);
318 }
319 
Seleqz(Register rd,Register rs,Register rt)320 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
321   CHECK(IsR6());
322   EmitR(0, rs, rt, rd, 0, 0x35);
323 }
324 
Selnez(Register rd,Register rs,Register rt)325 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
326   CHECK(IsR6());
327   EmitR(0, rs, rt, rd, 0, 0x37);
328 }
329 
ClzR6(Register rd,Register rs)330 void MipsAssembler::ClzR6(Register rd, Register rs) {
331   CHECK(IsR6());
332   EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10);
333 }
334 
ClzR2(Register rd,Register rs)335 void MipsAssembler::ClzR2(Register rd, Register rs) {
336   CHECK(!IsR6());
337   EmitR(0x1C, rs, rd, rd, 0, 0x20);
338 }
339 
CloR6(Register rd,Register rs)340 void MipsAssembler::CloR6(Register rd, Register rs) {
341   CHECK(IsR6());
342   EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11);
343 }
344 
CloR2(Register rd,Register rs)345 void MipsAssembler::CloR2(Register rd, Register rs) {
346   CHECK(!IsR6());
347   EmitR(0x1C, rs, rd, rd, 0, 0x21);
348 }
349 
Seb(Register rd,Register rt)350 void MipsAssembler::Seb(Register rd, Register rt) {
351   EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
352 }
353 
Seh(Register rd,Register rt)354 void MipsAssembler::Seh(Register rd, Register rt) {
355   EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20);
356 }
357 
Wsbh(Register rd,Register rt)358 void MipsAssembler::Wsbh(Register rd, Register rt) {
359   EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20);
360 }
361 
Bitswap(Register rd,Register rt)362 void MipsAssembler::Bitswap(Register rd, Register rt) {
363   CHECK(IsR6());
364   EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20);
365 }
366 
Sll(Register rd,Register rt,int shamt)367 void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
368   CHECK(IsUint<5>(shamt)) << shamt;
369   EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00);
370 }
371 
Srl(Register rd,Register rt,int shamt)372 void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
373   CHECK(IsUint<5>(shamt)) << shamt;
374   EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02);
375 }
376 
Rotr(Register rd,Register rt,int shamt)377 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
378   CHECK(IsUint<5>(shamt)) << shamt;
379   EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02);
380 }
381 
Sra(Register rd,Register rt,int shamt)382 void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
383   CHECK(IsUint<5>(shamt)) << shamt;
384   EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03);
385 }
386 
Sllv(Register rd,Register rt,Register rs)387 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
388   EmitR(0, rs, rt, rd, 0, 0x04);
389 }
390 
Srlv(Register rd,Register rt,Register rs)391 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
392   EmitR(0, rs, rt, rd, 0, 0x06);
393 }
394 
Rotrv(Register rd,Register rt,Register rs)395 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
396   EmitR(0, rs, rt, rd, 1, 0x06);
397 }
398 
Srav(Register rd,Register rt,Register rs)399 void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
400   EmitR(0, rs, rt, rd, 0, 0x07);
401 }
402 
Ext(Register rd,Register rt,int pos,int size)403 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
404   CHECK(IsUint<5>(pos)) << pos;
405   CHECK(0 < size && size <= 32) << size;
406   CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
407   EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00);
408 }
409 
Ins(Register rd,Register rt,int pos,int size)410 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
411   CHECK(IsUint<5>(pos)) << pos;
412   CHECK(0 < size && size <= 32) << size;
413   CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
414   EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04);
415 }
416 
Lb(Register rt,Register rs,uint16_t imm16)417 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
418   EmitI(0x20, rs, rt, imm16);
419 }
420 
Lh(Register rt,Register rs,uint16_t imm16)421 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
422   EmitI(0x21, rs, rt, imm16);
423 }
424 
Lw(Register rt,Register rs,uint16_t imm16)425 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
426   EmitI(0x23, rs, rt, imm16);
427 }
428 
Lwl(Register rt,Register rs,uint16_t imm16)429 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
430   CHECK(!IsR6());
431   EmitI(0x22, rs, rt, imm16);
432 }
433 
Lwr(Register rt,Register rs,uint16_t imm16)434 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
435   CHECK(!IsR6());
436   EmitI(0x26, rs, rt, imm16);
437 }
438 
Lbu(Register rt,Register rs,uint16_t imm16)439 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
440   EmitI(0x24, rs, rt, imm16);
441 }
442 
Lhu(Register rt,Register rs,uint16_t imm16)443 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
444   EmitI(0x25, rs, rt, imm16);
445 }
446 
Lui(Register rt,uint16_t imm16)447 void MipsAssembler::Lui(Register rt, uint16_t imm16) {
448   EmitI(0xf, static_cast<Register>(0), rt, imm16);
449 }
450 
Sync(uint32_t stype)451 void MipsAssembler::Sync(uint32_t stype) {
452   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0),
453         stype & 0x1f, 0xf);
454 }
455 
Mfhi(Register rd)456 void MipsAssembler::Mfhi(Register rd) {
457   CHECK(!IsR6());
458   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
459 }
460 
Mflo(Register rd)461 void MipsAssembler::Mflo(Register rd) {
462   CHECK(!IsR6());
463   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
464 }
465 
Sb(Register rt,Register rs,uint16_t imm16)466 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
467   EmitI(0x28, rs, rt, imm16);
468 }
469 
Sh(Register rt,Register rs,uint16_t imm16)470 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
471   EmitI(0x29, rs, rt, imm16);
472 }
473 
Sw(Register rt,Register rs,uint16_t imm16)474 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
475   EmitI(0x2b, rs, rt, imm16);
476 }
477 
Swl(Register rt,Register rs,uint16_t imm16)478 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
479   CHECK(!IsR6());
480   EmitI(0x2a, rs, rt, imm16);
481 }
482 
Swr(Register rt,Register rs,uint16_t imm16)483 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
484   CHECK(!IsR6());
485   EmitI(0x2e, rs, rt, imm16);
486 }
487 
LlR2(Register rt,Register base,int16_t imm16)488 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
489   CHECK(!IsR6());
490   EmitI(0x30, base, rt, imm16);
491 }
492 
ScR2(Register rt,Register base,int16_t imm16)493 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
494   CHECK(!IsR6());
495   EmitI(0x38, base, rt, imm16);
496 }
497 
LlR6(Register rt,Register base,int16_t imm9)498 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
499   CHECK(IsR6());
500   CHECK(IsInt<9>(imm9));
501   EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36);
502 }
503 
ScR6(Register rt,Register base,int16_t imm9)504 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
505   CHECK(IsR6());
506   CHECK(IsInt<9>(imm9));
507   EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26);
508 }
509 
Slt(Register rd,Register rs,Register rt)510 void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
511   EmitR(0, rs, rt, rd, 0, 0x2a);
512 }
513 
Sltu(Register rd,Register rs,Register rt)514 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
515   EmitR(0, rs, rt, rd, 0, 0x2b);
516 }
517 
Slti(Register rt,Register rs,uint16_t imm16)518 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
519   EmitI(0xa, rs, rt, imm16);
520 }
521 
Sltiu(Register rt,Register rs,uint16_t imm16)522 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
523   EmitI(0xb, rs, rt, imm16);
524 }
525 
B(uint16_t imm16)526 void MipsAssembler::B(uint16_t imm16) {
527   EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
528 }
529 
Beq(Register rs,Register rt,uint16_t imm16)530 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
531   EmitI(0x4, rs, rt, imm16);
532 }
533 
Bne(Register rs,Register rt,uint16_t imm16)534 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
535   EmitI(0x5, rs, rt, imm16);
536 }
537 
Beqz(Register rt,uint16_t imm16)538 void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
539   Beq(ZERO, rt, imm16);
540 }
541 
Bnez(Register rt,uint16_t imm16)542 void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
543   Bne(ZERO, rt, imm16);
544 }
545 
Bltz(Register rt,uint16_t imm16)546 void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
547   EmitI(0x1, rt, static_cast<Register>(0), imm16);
548 }
549 
Bgez(Register rt,uint16_t imm16)550 void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
551   EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
552 }
553 
Blez(Register rt,uint16_t imm16)554 void MipsAssembler::Blez(Register rt, uint16_t imm16) {
555   EmitI(0x6, rt, static_cast<Register>(0), imm16);
556 }
557 
Bgtz(Register rt,uint16_t imm16)558 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
559   EmitI(0x7, rt, static_cast<Register>(0), imm16);
560 }
561 
Bc1f(uint16_t imm16)562 void MipsAssembler::Bc1f(uint16_t imm16) {
563   Bc1f(0, imm16);
564 }
565 
Bc1f(int cc,uint16_t imm16)566 void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
567   CHECK(!IsR6());
568   CHECK(IsUint<3>(cc)) << cc;
569   EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16);
570 }
571 
Bc1t(uint16_t imm16)572 void MipsAssembler::Bc1t(uint16_t imm16) {
573   Bc1t(0, imm16);
574 }
575 
Bc1t(int cc,uint16_t imm16)576 void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
577   CHECK(!IsR6());
578   CHECK(IsUint<3>(cc)) << cc;
579   EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16);
580 }
581 
J(uint32_t addr26)582 void MipsAssembler::J(uint32_t addr26) {
583   EmitI26(0x2, addr26);
584 }
585 
Jal(uint32_t addr26)586 void MipsAssembler::Jal(uint32_t addr26) {
587   EmitI26(0x3, addr26);
588 }
589 
Jalr(Register rd,Register rs)590 void MipsAssembler::Jalr(Register rd, Register rs) {
591   EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
592 }
593 
Jalr(Register rs)594 void MipsAssembler::Jalr(Register rs) {
595   Jalr(RA, rs);
596 }
597 
Jr(Register rs)598 void MipsAssembler::Jr(Register rs) {
599   Jalr(ZERO, rs);
600 }
601 
Nal()602 void MipsAssembler::Nal() {
603   EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
604 }
605 
Auipc(Register rs,uint16_t imm16)606 void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
607   CHECK(IsR6());
608   EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
609 }
610 
Addiupc(Register rs,uint32_t imm19)611 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
612   CHECK(IsR6());
613   CHECK(IsUint<19>(imm19)) << imm19;
614   EmitI21(0x3B, rs, imm19);
615 }
616 
Bc(uint32_t imm26)617 void MipsAssembler::Bc(uint32_t imm26) {
618   CHECK(IsR6());
619   EmitI26(0x32, imm26);
620 }
621 
Jic(Register rt,uint16_t imm16)622 void MipsAssembler::Jic(Register rt, uint16_t imm16) {
623   CHECK(IsR6());
624   EmitI(0x36, static_cast<Register>(0), rt, imm16);
625 }
626 
Jialc(Register rt,uint16_t imm16)627 void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
628   CHECK(IsR6());
629   EmitI(0x3E, static_cast<Register>(0), rt, imm16);
630 }
631 
Bltc(Register rs,Register rt,uint16_t imm16)632 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
633   CHECK(IsR6());
634   CHECK_NE(rs, ZERO);
635   CHECK_NE(rt, ZERO);
636   CHECK_NE(rs, rt);
637   EmitI(0x17, rs, rt, imm16);
638 }
639 
Bltzc(Register rt,uint16_t imm16)640 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
641   CHECK(IsR6());
642   CHECK_NE(rt, ZERO);
643   EmitI(0x17, rt, rt, imm16);
644 }
645 
Bgtzc(Register rt,uint16_t imm16)646 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
647   CHECK(IsR6());
648   CHECK_NE(rt, ZERO);
649   EmitI(0x17, static_cast<Register>(0), rt, imm16);
650 }
651 
Bgec(Register rs,Register rt,uint16_t imm16)652 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
653   CHECK(IsR6());
654   CHECK_NE(rs, ZERO);
655   CHECK_NE(rt, ZERO);
656   CHECK_NE(rs, rt);
657   EmitI(0x16, rs, rt, imm16);
658 }
659 
Bgezc(Register rt,uint16_t imm16)660 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
661   CHECK(IsR6());
662   CHECK_NE(rt, ZERO);
663   EmitI(0x16, rt, rt, imm16);
664 }
665 
Blezc(Register rt,uint16_t imm16)666 void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
667   CHECK(IsR6());
668   CHECK_NE(rt, ZERO);
669   EmitI(0x16, static_cast<Register>(0), rt, imm16);
670 }
671 
Bltuc(Register rs,Register rt,uint16_t imm16)672 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
673   CHECK(IsR6());
674   CHECK_NE(rs, ZERO);
675   CHECK_NE(rt, ZERO);
676   CHECK_NE(rs, rt);
677   EmitI(0x7, rs, rt, imm16);
678 }
679 
Bgeuc(Register rs,Register rt,uint16_t imm16)680 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
681   CHECK(IsR6());
682   CHECK_NE(rs, ZERO);
683   CHECK_NE(rt, ZERO);
684   CHECK_NE(rs, rt);
685   EmitI(0x6, rs, rt, imm16);
686 }
687 
Beqc(Register rs,Register rt,uint16_t imm16)688 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
689   CHECK(IsR6());
690   CHECK_NE(rs, ZERO);
691   CHECK_NE(rt, ZERO);
692   CHECK_NE(rs, rt);
693   EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
694 }
695 
Bnec(Register rs,Register rt,uint16_t imm16)696 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
697   CHECK(IsR6());
698   CHECK_NE(rs, ZERO);
699   CHECK_NE(rt, ZERO);
700   CHECK_NE(rs, rt);
701   EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
702 }
703 
Beqzc(Register rs,uint32_t imm21)704 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
705   CHECK(IsR6());
706   CHECK_NE(rs, ZERO);
707   EmitI21(0x36, rs, imm21);
708 }
709 
Bnezc(Register rs,uint32_t imm21)710 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
711   CHECK(IsR6());
712   CHECK_NE(rs, ZERO);
713   EmitI21(0x3E, rs, imm21);
714 }
715 
Bc1eqz(FRegister ft,uint16_t imm16)716 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
717   CHECK(IsR6());
718   EmitFI(0x11, 0x9, ft, imm16);
719 }
720 
Bc1nez(FRegister ft,uint16_t imm16)721 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
722   CHECK(IsR6());
723   EmitFI(0x11, 0xD, ft, imm16);
724 }
725 
EmitBcondR2(BranchCondition cond,Register rs,Register rt,uint16_t imm16)726 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
727   switch (cond) {
728     case kCondLTZ:
729       CHECK_EQ(rt, ZERO);
730       Bltz(rs, imm16);
731       break;
732     case kCondGEZ:
733       CHECK_EQ(rt, ZERO);
734       Bgez(rs, imm16);
735       break;
736     case kCondLEZ:
737       CHECK_EQ(rt, ZERO);
738       Blez(rs, imm16);
739       break;
740     case kCondGTZ:
741       CHECK_EQ(rt, ZERO);
742       Bgtz(rs, imm16);
743       break;
744     case kCondEQ:
745       Beq(rs, rt, imm16);
746       break;
747     case kCondNE:
748       Bne(rs, rt, imm16);
749       break;
750     case kCondEQZ:
751       CHECK_EQ(rt, ZERO);
752       Beqz(rs, imm16);
753       break;
754     case kCondNEZ:
755       CHECK_EQ(rt, ZERO);
756       Bnez(rs, imm16);
757       break;
758     case kCondF:
759       CHECK_EQ(rt, ZERO);
760       Bc1f(static_cast<int>(rs), imm16);
761       break;
762     case kCondT:
763       CHECK_EQ(rt, ZERO);
764       Bc1t(static_cast<int>(rs), imm16);
765       break;
766     case kCondLT:
767     case kCondGE:
768     case kCondLE:
769     case kCondGT:
770     case kCondLTU:
771     case kCondGEU:
772     case kUncond:
773       // We don't support synthetic R2 branches (preceded with slt[u]) at this level
774       // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
775       LOG(FATAL) << "Unexpected branch condition " << cond;
776       UNREACHABLE();
777   }
778 }
779 
EmitBcondR6(BranchCondition cond,Register rs,Register rt,uint32_t imm16_21)780 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
781   switch (cond) {
782     case kCondLT:
783       Bltc(rs, rt, imm16_21);
784       break;
785     case kCondGE:
786       Bgec(rs, rt, imm16_21);
787       break;
788     case kCondLE:
789       Bgec(rt, rs, imm16_21);
790       break;
791     case kCondGT:
792       Bltc(rt, rs, imm16_21);
793       break;
794     case kCondLTZ:
795       CHECK_EQ(rt, ZERO);
796       Bltzc(rs, imm16_21);
797       break;
798     case kCondGEZ:
799       CHECK_EQ(rt, ZERO);
800       Bgezc(rs, imm16_21);
801       break;
802     case kCondLEZ:
803       CHECK_EQ(rt, ZERO);
804       Blezc(rs, imm16_21);
805       break;
806     case kCondGTZ:
807       CHECK_EQ(rt, ZERO);
808       Bgtzc(rs, imm16_21);
809       break;
810     case kCondEQ:
811       Beqc(rs, rt, imm16_21);
812       break;
813     case kCondNE:
814       Bnec(rs, rt, imm16_21);
815       break;
816     case kCondEQZ:
817       CHECK_EQ(rt, ZERO);
818       Beqzc(rs, imm16_21);
819       break;
820     case kCondNEZ:
821       CHECK_EQ(rt, ZERO);
822       Bnezc(rs, imm16_21);
823       break;
824     case kCondLTU:
825       Bltuc(rs, rt, imm16_21);
826       break;
827     case kCondGEU:
828       Bgeuc(rs, rt, imm16_21);
829       break;
830     case kCondF:
831       CHECK_EQ(rt, ZERO);
832       Bc1eqz(static_cast<FRegister>(rs), imm16_21);
833       break;
834     case kCondT:
835       CHECK_EQ(rt, ZERO);
836       Bc1nez(static_cast<FRegister>(rs), imm16_21);
837       break;
838     case kUncond:
839       LOG(FATAL) << "Unexpected branch condition " << cond;
840       UNREACHABLE();
841   }
842 }
843 
AddS(FRegister fd,FRegister fs,FRegister ft)844 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
845   EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
846 }
847 
SubS(FRegister fd,FRegister fs,FRegister ft)848 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
849   EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
850 }
851 
MulS(FRegister fd,FRegister fs,FRegister ft)852 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
853   EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
854 }
855 
DivS(FRegister fd,FRegister fs,FRegister ft)856 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
857   EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
858 }
859 
AddD(FRegister fd,FRegister fs,FRegister ft)860 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
861   EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
862 }
863 
SubD(FRegister fd,FRegister fs,FRegister ft)864 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
865   EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
866 }
867 
MulD(FRegister fd,FRegister fs,FRegister ft)868 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
869   EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
870 }
871 
DivD(FRegister fd,FRegister fs,FRegister ft)872 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
873   EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
874 }
875 
SqrtS(FRegister fd,FRegister fs)876 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
877   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4);
878 }
879 
SqrtD(FRegister fd,FRegister fs)880 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
881   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4);
882 }
883 
AbsS(FRegister fd,FRegister fs)884 void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
885   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5);
886 }
887 
AbsD(FRegister fd,FRegister fs)888 void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
889   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5);
890 }
891 
MovS(FRegister fd,FRegister fs)892 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
893   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
894 }
895 
MovD(FRegister fd,FRegister fs)896 void MipsAssembler::MovD(FRegister fd, FRegister fs) {
897   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
898 }
899 
NegS(FRegister fd,FRegister fs)900 void MipsAssembler::NegS(FRegister fd, FRegister fs) {
901   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
902 }
903 
NegD(FRegister fd,FRegister fs)904 void MipsAssembler::NegD(FRegister fd, FRegister fs) {
905   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
906 }
907 
CunS(FRegister fs,FRegister ft)908 void MipsAssembler::CunS(FRegister fs, FRegister ft) {
909   CunS(0, fs, ft);
910 }
911 
CunS(int cc,FRegister fs,FRegister ft)912 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
913   CHECK(!IsR6());
914   CHECK(IsUint<3>(cc)) << cc;
915   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
916 }
917 
CeqS(FRegister fs,FRegister ft)918 void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
919   CeqS(0, fs, ft);
920 }
921 
CeqS(int cc,FRegister fs,FRegister ft)922 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
923   CHECK(!IsR6());
924   CHECK(IsUint<3>(cc)) << cc;
925   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
926 }
927 
CueqS(FRegister fs,FRegister ft)928 void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
929   CueqS(0, fs, ft);
930 }
931 
CueqS(int cc,FRegister fs,FRegister ft)932 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
933   CHECK(!IsR6());
934   CHECK(IsUint<3>(cc)) << cc;
935   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
936 }
937 
ColtS(FRegister fs,FRegister ft)938 void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
939   ColtS(0, fs, ft);
940 }
941 
ColtS(int cc,FRegister fs,FRegister ft)942 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
943   CHECK(!IsR6());
944   CHECK(IsUint<3>(cc)) << cc;
945   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
946 }
947 
CultS(FRegister fs,FRegister ft)948 void MipsAssembler::CultS(FRegister fs, FRegister ft) {
949   CultS(0, fs, ft);
950 }
951 
CultS(int cc,FRegister fs,FRegister ft)952 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
953   CHECK(!IsR6());
954   CHECK(IsUint<3>(cc)) << cc;
955   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
956 }
957 
ColeS(FRegister fs,FRegister ft)958 void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
959   ColeS(0, fs, ft);
960 }
961 
ColeS(int cc,FRegister fs,FRegister ft)962 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
963   CHECK(!IsR6());
964   CHECK(IsUint<3>(cc)) << cc;
965   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
966 }
967 
CuleS(FRegister fs,FRegister ft)968 void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
969   CuleS(0, fs, ft);
970 }
971 
CuleS(int cc,FRegister fs,FRegister ft)972 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
973   CHECK(!IsR6());
974   CHECK(IsUint<3>(cc)) << cc;
975   EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
976 }
977 
CunD(FRegister fs,FRegister ft)978 void MipsAssembler::CunD(FRegister fs, FRegister ft) {
979   CunD(0, fs, ft);
980 }
981 
CunD(int cc,FRegister fs,FRegister ft)982 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
983   CHECK(!IsR6());
984   CHECK(IsUint<3>(cc)) << cc;
985   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
986 }
987 
CeqD(FRegister fs,FRegister ft)988 void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
989   CeqD(0, fs, ft);
990 }
991 
CeqD(int cc,FRegister fs,FRegister ft)992 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
993   CHECK(!IsR6());
994   CHECK(IsUint<3>(cc)) << cc;
995   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
996 }
997 
CueqD(FRegister fs,FRegister ft)998 void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
999   CueqD(0, fs, ft);
1000 }
1001 
CueqD(int cc,FRegister fs,FRegister ft)1002 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1003   CHECK(!IsR6());
1004   CHECK(IsUint<3>(cc)) << cc;
1005   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
1006 }
1007 
ColtD(FRegister fs,FRegister ft)1008 void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1009   ColtD(0, fs, ft);
1010 }
1011 
ColtD(int cc,FRegister fs,FRegister ft)1012 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1013   CHECK(!IsR6());
1014   CHECK(IsUint<3>(cc)) << cc;
1015   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
1016 }
1017 
CultD(FRegister fs,FRegister ft)1018 void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1019   CultD(0, fs, ft);
1020 }
1021 
CultD(int cc,FRegister fs,FRegister ft)1022 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1023   CHECK(!IsR6());
1024   CHECK(IsUint<3>(cc)) << cc;
1025   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
1026 }
1027 
ColeD(FRegister fs,FRegister ft)1028 void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1029   ColeD(0, fs, ft);
1030 }
1031 
ColeD(int cc,FRegister fs,FRegister ft)1032 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1033   CHECK(!IsR6());
1034   CHECK(IsUint<3>(cc)) << cc;
1035   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
1036 }
1037 
CuleD(FRegister fs,FRegister ft)1038 void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1039   CuleD(0, fs, ft);
1040 }
1041 
CuleD(int cc,FRegister fs,FRegister ft)1042 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1043   CHECK(!IsR6());
1044   CHECK(IsUint<3>(cc)) << cc;
1045   EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
1046 }
1047 
CmpUnS(FRegister fd,FRegister fs,FRegister ft)1048 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1049   CHECK(IsR6());
1050   EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1051 }
1052 
CmpEqS(FRegister fd,FRegister fs,FRegister ft)1053 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1054   CHECK(IsR6());
1055   EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1056 }
1057 
CmpUeqS(FRegister fd,FRegister fs,FRegister ft)1058 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1059   CHECK(IsR6());
1060   EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1061 }
1062 
CmpLtS(FRegister fd,FRegister fs,FRegister ft)1063 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1064   CHECK(IsR6());
1065   EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1066 }
1067 
CmpUltS(FRegister fd,FRegister fs,FRegister ft)1068 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1069   CHECK(IsR6());
1070   EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1071 }
1072 
CmpLeS(FRegister fd,FRegister fs,FRegister ft)1073 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1074   CHECK(IsR6());
1075   EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1076 }
1077 
CmpUleS(FRegister fd,FRegister fs,FRegister ft)1078 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1079   CHECK(IsR6());
1080   EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1081 }
1082 
CmpOrS(FRegister fd,FRegister fs,FRegister ft)1083 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1084   CHECK(IsR6());
1085   EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1086 }
1087 
CmpUneS(FRegister fd,FRegister fs,FRegister ft)1088 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1089   CHECK(IsR6());
1090   EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1091 }
1092 
CmpNeS(FRegister fd,FRegister fs,FRegister ft)1093 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1094   CHECK(IsR6());
1095   EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1096 }
1097 
CmpUnD(FRegister fd,FRegister fs,FRegister ft)1098 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1099   CHECK(IsR6());
1100   EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1101 }
1102 
CmpEqD(FRegister fd,FRegister fs,FRegister ft)1103 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1104   CHECK(IsR6());
1105   EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1106 }
1107 
CmpUeqD(FRegister fd,FRegister fs,FRegister ft)1108 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1109   CHECK(IsR6());
1110   EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1111 }
1112 
CmpLtD(FRegister fd,FRegister fs,FRegister ft)1113 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1114   CHECK(IsR6());
1115   EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1116 }
1117 
CmpUltD(FRegister fd,FRegister fs,FRegister ft)1118 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1119   CHECK(IsR6());
1120   EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1121 }
1122 
CmpLeD(FRegister fd,FRegister fs,FRegister ft)1123 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1124   CHECK(IsR6());
1125   EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1126 }
1127 
CmpUleD(FRegister fd,FRegister fs,FRegister ft)1128 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1129   CHECK(IsR6());
1130   EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1131 }
1132 
CmpOrD(FRegister fd,FRegister fs,FRegister ft)1133 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1134   CHECK(IsR6());
1135   EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1136 }
1137 
CmpUneD(FRegister fd,FRegister fs,FRegister ft)1138 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1139   CHECK(IsR6());
1140   EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1141 }
1142 
CmpNeD(FRegister fd,FRegister fs,FRegister ft)1143 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1144   CHECK(IsR6());
1145   EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1146 }
1147 
Movf(Register rd,Register rs,int cc)1148 void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1149   CHECK(!IsR6());
1150   CHECK(IsUint<3>(cc)) << cc;
1151   EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01);
1152 }
1153 
Movt(Register rd,Register rs,int cc)1154 void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1155   CHECK(!IsR6());
1156   CHECK(IsUint<3>(cc)) << cc;
1157   EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01);
1158 }
1159 
MovfS(FRegister fd,FRegister fs,int cc)1160 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1161   CHECK(!IsR6());
1162   CHECK(IsUint<3>(cc)) << cc;
1163   EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1164 }
1165 
MovfD(FRegister fd,FRegister fs,int cc)1166 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1167   CHECK(!IsR6());
1168   CHECK(IsUint<3>(cc)) << cc;
1169   EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1170 }
1171 
MovtS(FRegister fd,FRegister fs,int cc)1172 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1173   CHECK(!IsR6());
1174   CHECK(IsUint<3>(cc)) << cc;
1175   EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1176 }
1177 
MovtD(FRegister fd,FRegister fs,int cc)1178 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1179   CHECK(!IsR6());
1180   CHECK(IsUint<3>(cc)) << cc;
1181   EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1182 }
1183 
SelS(FRegister fd,FRegister fs,FRegister ft)1184 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1185   CHECK(IsR6());
1186   EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
1187 }
1188 
SelD(FRegister fd,FRegister fs,FRegister ft)1189 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1190   CHECK(IsR6());
1191   EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1192 }
1193 
ClassS(FRegister fd,FRegister fs)1194 void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1195   CHECK(IsR6());
1196   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b);
1197 }
1198 
ClassD(FRegister fd,FRegister fs)1199 void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1200   CHECK(IsR6());
1201   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b);
1202 }
1203 
MinS(FRegister fd,FRegister fs,FRegister ft)1204 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1205   CHECK(IsR6());
1206   EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1207 }
1208 
MinD(FRegister fd,FRegister fs,FRegister ft)1209 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1210   CHECK(IsR6());
1211   EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1212 }
1213 
MaxS(FRegister fd,FRegister fs,FRegister ft)1214 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1215   CHECK(IsR6());
1216   EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1217 }
1218 
MaxD(FRegister fd,FRegister fs,FRegister ft)1219 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1220   CHECK(IsR6());
1221   EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1222 }
1223 
TruncLS(FRegister fd,FRegister fs)1224 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1225   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1226 }
1227 
TruncLD(FRegister fd,FRegister fs)1228 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1229   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1230 }
1231 
TruncWS(FRegister fd,FRegister fs)1232 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1233   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1234 }
1235 
TruncWD(FRegister fd,FRegister fs)1236 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1237   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1238 }
1239 
Cvtsw(FRegister fd,FRegister fs)1240 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1241   EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1242 }
1243 
Cvtdw(FRegister fd,FRegister fs)1244 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1245   EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1246 }
1247 
Cvtsd(FRegister fd,FRegister fs)1248 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1249   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1250 }
1251 
Cvtds(FRegister fd,FRegister fs)1252 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1253   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
1254 }
1255 
Cvtsl(FRegister fd,FRegister fs)1256 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1257   EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1258 }
1259 
Cvtdl(FRegister fd,FRegister fs)1260 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1261   EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1262 }
1263 
FloorWS(FRegister fd,FRegister fs)1264 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1265   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf);
1266 }
1267 
FloorWD(FRegister fd,FRegister fs)1268 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1269   EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf);
1270 }
1271 
Mfc1(Register rt,FRegister fs)1272 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
1273   EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1274 }
1275 
Mtc1(Register rt,FRegister fs)1276 void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1277   EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1278 }
1279 
Mfhc1(Register rt,FRegister fs)1280 void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1281   EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1282 }
1283 
Mthc1(Register rt,FRegister fs)1284 void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1285   EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1286 }
1287 
MoveFromFpuHigh(Register rt,FRegister fs)1288 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1289   if (Is32BitFPU()) {
1290     CHECK_EQ(fs % 2, 0) << fs;
1291     Mfc1(rt, static_cast<FRegister>(fs + 1));
1292   } else {
1293     Mfhc1(rt, fs);
1294   }
1295 }
1296 
MoveToFpuHigh(Register rt,FRegister fs)1297 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1298   if (Is32BitFPU()) {
1299     CHECK_EQ(fs % 2, 0) << fs;
1300     Mtc1(rt, static_cast<FRegister>(fs + 1));
1301   } else {
1302     Mthc1(rt, fs);
1303   }
1304 }
1305 
Lwc1(FRegister ft,Register rs,uint16_t imm16)1306 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
1307   EmitI(0x31, rs, static_cast<Register>(ft), imm16);
1308 }
1309 
Ldc1(FRegister ft,Register rs,uint16_t imm16)1310 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1311   EmitI(0x35, rs, static_cast<Register>(ft), imm16);
1312 }
1313 
Swc1(FRegister ft,Register rs,uint16_t imm16)1314 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
1315   EmitI(0x39, rs, static_cast<Register>(ft), imm16);
1316 }
1317 
Sdc1(FRegister ft,Register rs,uint16_t imm16)1318 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1319   EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
1320 }
1321 
Break()1322 void MipsAssembler::Break() {
1323   EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1324         static_cast<Register>(0), 0, 0xD);
1325 }
1326 
Nop()1327 void MipsAssembler::Nop() {
1328   EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1329 }
1330 
Move(Register rd,Register rs)1331 void MipsAssembler::Move(Register rd, Register rs) {
1332   Or(rd, rs, ZERO);
1333 }
1334 
Clear(Register rd)1335 void MipsAssembler::Clear(Register rd) {
1336   Move(rd, ZERO);
1337 }
1338 
Not(Register rd,Register rs)1339 void MipsAssembler::Not(Register rd, Register rs) {
1340   Nor(rd, rs, ZERO);
1341 }
1342 
Push(Register rs)1343 void MipsAssembler::Push(Register rs) {
1344   IncreaseFrameSize(kMipsWordSize);
1345   Sw(rs, SP, 0);
1346 }
1347 
Pop(Register rd)1348 void MipsAssembler::Pop(Register rd) {
1349   Lw(rd, SP, 0);
1350   DecreaseFrameSize(kMipsWordSize);
1351 }
1352 
PopAndReturn(Register rd,Register rt)1353 void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1354   Lw(rd, SP, 0);
1355   Jr(rt);
1356   DecreaseFrameSize(kMipsWordSize);
1357 }
1358 
LoadConst32(Register rd,int32_t value)1359 void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1360   if (IsUint<16>(value)) {
1361     // Use OR with (unsigned) immediate to encode 16b unsigned int.
1362     Ori(rd, ZERO, value);
1363   } else if (IsInt<16>(value)) {
1364     // Use ADD with (signed) immediate to encode 16b signed int.
1365     Addiu(rd, ZERO, value);
1366   } else {
1367     Lui(rd, High16Bits(value));
1368     if (value & 0xFFFF)
1369       Ori(rd, rd, Low16Bits(value));
1370   }
1371 }
1372 
LoadConst64(Register reg_hi,Register reg_lo,int64_t value)1373 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
1374   uint32_t low = Low32Bits(value);
1375   uint32_t high = High32Bits(value);
1376   LoadConst32(reg_lo, low);
1377   if (high != low) {
1378     LoadConst32(reg_hi, high);
1379   } else {
1380     Move(reg_hi, reg_lo);
1381   }
1382 }
1383 
StoreConst32ToOffset(int32_t value,Register base,int32_t offset,Register temp)1384 void MipsAssembler::StoreConst32ToOffset(int32_t value,
1385                                          Register base,
1386                                          int32_t offset,
1387                                          Register temp) {
1388   if (!IsInt<16>(offset)) {
1389     CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
1390     LoadConst32(AT, offset);
1391     Addu(AT, AT, base);
1392     base = AT;
1393     offset = 0;
1394   }
1395   if (value == 0) {
1396     temp = ZERO;
1397   } else {
1398     LoadConst32(temp, value);
1399   }
1400   Sw(temp, base, offset);
1401 }
1402 
StoreConst64ToOffset(int64_t value,Register base,int32_t offset,Register temp)1403 void MipsAssembler::StoreConst64ToOffset(int64_t value,
1404                                          Register base,
1405                                          int32_t offset,
1406                                          Register temp) {
1407   // IsInt<16> must be passed a signed value.
1408   if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
1409     CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
1410     LoadConst32(AT, offset);
1411     Addu(AT, AT, base);
1412     base = AT;
1413     offset = 0;
1414   }
1415   uint32_t low = Low32Bits(value);
1416   uint32_t high = High32Bits(value);
1417   if (low == 0) {
1418     Sw(ZERO, base, offset);
1419   } else {
1420     LoadConst32(temp, low);
1421     Sw(temp, base, offset);
1422   }
1423   if (high == 0) {
1424     Sw(ZERO, base, offset + kMipsWordSize);
1425   } else {
1426     if (high != low) {
1427       LoadConst32(temp, high);
1428     }
1429     Sw(temp, base, offset + kMipsWordSize);
1430   }
1431 }
1432 
LoadSConst32(FRegister r,int32_t value,Register temp)1433 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
1434   if (value == 0) {
1435     temp = ZERO;
1436   } else {
1437     LoadConst32(temp, value);
1438   }
1439   Mtc1(temp, r);
1440 }
1441 
LoadDConst64(FRegister rd,int64_t value,Register temp)1442 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
1443   uint32_t low = Low32Bits(value);
1444   uint32_t high = High32Bits(value);
1445   if (low == 0) {
1446     Mtc1(ZERO, rd);
1447   } else {
1448     LoadConst32(temp, low);
1449     Mtc1(temp, rd);
1450   }
1451   if (high == 0) {
1452     MoveToFpuHigh(ZERO, rd);
1453   } else {
1454     LoadConst32(temp, high);
1455     MoveToFpuHigh(temp, rd);
1456   }
1457 }
1458 
Addiu32(Register rt,Register rs,int32_t value,Register temp)1459 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1460   if (IsInt<16>(value)) {
1461     Addiu(rt, rs, value);
1462   } else {
1463     LoadConst32(temp, value);
1464     Addu(rt, rs, temp);
1465   }
1466 }
1467 
InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,MipsAssembler::Branch::Type short_type,MipsAssembler::Branch::Type long_type)1468 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1469                                             MipsAssembler::Branch::Type short_type,
1470                                             MipsAssembler::Branch::Type long_type) {
1471   type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1472 }
1473 
InitializeType(bool is_call,bool is_r6)1474 void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
1475   OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1476   if (is_r6) {
1477     // R6
1478     if (is_call) {
1479       InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1480     } else if (condition_ == kUncond) {
1481       InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1482     } else {
1483       if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1484         // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1485         type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1486       } else {
1487         InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1488       }
1489     }
1490   } else {
1491     // R2
1492     if (is_call) {
1493       InitShortOrLong(offset_size, kCall, kLongCall);
1494     } else if (condition_ == kUncond) {
1495       InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1496     } else {
1497       InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1498     }
1499   }
1500   old_type_ = type_;
1501 }
1502 
IsNop(BranchCondition condition,Register lhs,Register rhs)1503 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1504   switch (condition) {
1505     case kCondLT:
1506     case kCondGT:
1507     case kCondNE:
1508     case kCondLTU:
1509       return lhs == rhs;
1510     default:
1511       return false;
1512   }
1513 }
1514 
IsUncond(BranchCondition condition,Register lhs,Register rhs)1515 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1516   switch (condition) {
1517     case kUncond:
1518       return true;
1519     case kCondGE:
1520     case kCondLE:
1521     case kCondEQ:
1522     case kCondGEU:
1523       return lhs == rhs;
1524     default:
1525       return false;
1526   }
1527 }
1528 
Branch(bool is_r6,uint32_t location,uint32_t target)1529 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
1530     : old_location_(location),
1531       location_(location),
1532       target_(target),
1533       lhs_reg_(0),
1534       rhs_reg_(0),
1535       condition_(kUncond) {
1536   InitializeType(false, is_r6);
1537 }
1538 
Branch(bool is_r6,uint32_t location,uint32_t target,MipsAssembler::BranchCondition condition,Register lhs_reg,Register rhs_reg)1539 MipsAssembler::Branch::Branch(bool is_r6,
1540                               uint32_t location,
1541                               uint32_t target,
1542                               MipsAssembler::BranchCondition condition,
1543                               Register lhs_reg,
1544                               Register rhs_reg)
1545     : old_location_(location),
1546       location_(location),
1547       target_(target),
1548       lhs_reg_(lhs_reg),
1549       rhs_reg_(rhs_reg),
1550       condition_(condition) {
1551   CHECK_NE(condition, kUncond);
1552   switch (condition) {
1553     case kCondLT:
1554     case kCondGE:
1555     case kCondLE:
1556     case kCondGT:
1557     case kCondLTU:
1558     case kCondGEU:
1559       // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1560       // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1561       // We leave this up to the caller.
1562       CHECK(is_r6);
1563       FALLTHROUGH_INTENDED;
1564     case kCondEQ:
1565     case kCondNE:
1566       // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1567       // To compare with 0, use dedicated kCond*Z conditions.
1568       CHECK_NE(lhs_reg, ZERO);
1569       CHECK_NE(rhs_reg, ZERO);
1570       break;
1571     case kCondLTZ:
1572     case kCondGEZ:
1573     case kCondLEZ:
1574     case kCondGTZ:
1575     case kCondEQZ:
1576     case kCondNEZ:
1577       // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1578       CHECK_NE(lhs_reg, ZERO);
1579       CHECK_EQ(rhs_reg, ZERO);
1580       break;
1581     case kCondF:
1582     case kCondT:
1583       CHECK_EQ(rhs_reg, ZERO);
1584       break;
1585     case kUncond:
1586       UNREACHABLE();
1587   }
1588   CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1589   if (IsUncond(condition, lhs_reg, rhs_reg)) {
1590     // Branch condition is always true, make the branch unconditional.
1591     condition_ = kUncond;
1592   }
1593   InitializeType(false, is_r6);
1594 }
1595 
Branch(bool is_r6,uint32_t location,uint32_t target,Register indirect_reg)1596 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
1597     : old_location_(location),
1598       location_(location),
1599       target_(target),
1600       lhs_reg_(indirect_reg),
1601       rhs_reg_(0),
1602       condition_(kUncond) {
1603   CHECK_NE(indirect_reg, ZERO);
1604   CHECK_NE(indirect_reg, AT);
1605   InitializeType(true, is_r6);
1606 }
1607 
OppositeCondition(MipsAssembler::BranchCondition cond)1608 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1609     MipsAssembler::BranchCondition cond) {
1610   switch (cond) {
1611     case kCondLT:
1612       return kCondGE;
1613     case kCondGE:
1614       return kCondLT;
1615     case kCondLE:
1616       return kCondGT;
1617     case kCondGT:
1618       return kCondLE;
1619     case kCondLTZ:
1620       return kCondGEZ;
1621     case kCondGEZ:
1622       return kCondLTZ;
1623     case kCondLEZ:
1624       return kCondGTZ;
1625     case kCondGTZ:
1626       return kCondLEZ;
1627     case kCondEQ:
1628       return kCondNE;
1629     case kCondNE:
1630       return kCondEQ;
1631     case kCondEQZ:
1632       return kCondNEZ;
1633     case kCondNEZ:
1634       return kCondEQZ;
1635     case kCondLTU:
1636       return kCondGEU;
1637     case kCondGEU:
1638       return kCondLTU;
1639     case kCondF:
1640       return kCondT;
1641     case kCondT:
1642       return kCondF;
1643     case kUncond:
1644       LOG(FATAL) << "Unexpected branch condition " << cond;
1645   }
1646   UNREACHABLE();
1647 }
1648 
GetType() const1649 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1650   return type_;
1651 }
1652 
GetCondition() const1653 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1654   return condition_;
1655 }
1656 
GetLeftRegister() const1657 Register MipsAssembler::Branch::GetLeftRegister() const {
1658   return static_cast<Register>(lhs_reg_);
1659 }
1660 
GetRightRegister() const1661 Register MipsAssembler::Branch::GetRightRegister() const {
1662   return static_cast<Register>(rhs_reg_);
1663 }
1664 
GetTarget() const1665 uint32_t MipsAssembler::Branch::GetTarget() const {
1666   return target_;
1667 }
1668 
GetLocation() const1669 uint32_t MipsAssembler::Branch::GetLocation() const {
1670   return location_;
1671 }
1672 
GetOldLocation() const1673 uint32_t MipsAssembler::Branch::GetOldLocation() const {
1674   return old_location_;
1675 }
1676 
GetLength() const1677 uint32_t MipsAssembler::Branch::GetLength() const {
1678   return branch_info_[type_].length;
1679 }
1680 
GetOldLength() const1681 uint32_t MipsAssembler::Branch::GetOldLength() const {
1682   return branch_info_[old_type_].length;
1683 }
1684 
GetSize() const1685 uint32_t MipsAssembler::Branch::GetSize() const {
1686   return GetLength() * sizeof(uint32_t);
1687 }
1688 
GetOldSize() const1689 uint32_t MipsAssembler::Branch::GetOldSize() const {
1690   return GetOldLength() * sizeof(uint32_t);
1691 }
1692 
GetEndLocation() const1693 uint32_t MipsAssembler::Branch::GetEndLocation() const {
1694   return GetLocation() + GetSize();
1695 }
1696 
GetOldEndLocation() const1697 uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1698   return GetOldLocation() + GetOldSize();
1699 }
1700 
IsLong() const1701 bool MipsAssembler::Branch::IsLong() const {
1702   switch (type_) {
1703     // R2 short branches.
1704     case kUncondBranch:
1705     case kCondBranch:
1706     case kCall:
1707     // R6 short branches.
1708     case kR6UncondBranch:
1709     case kR6CondBranch:
1710     case kR6Call:
1711       return false;
1712     // R2 long branches.
1713     case kLongUncondBranch:
1714     case kLongCondBranch:
1715     case kLongCall:
1716     // R6 long branches.
1717     case kR6LongUncondBranch:
1718     case kR6LongCondBranch:
1719     case kR6LongCall:
1720       return true;
1721   }
1722   UNREACHABLE();
1723 }
1724 
IsResolved() const1725 bool MipsAssembler::Branch::IsResolved() const {
1726   return target_ != kUnresolved;
1727 }
1728 
GetOffsetSize() const1729 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1730   OffsetBits offset_size =
1731       (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1732           ? kOffset23
1733           : branch_info_[type_].offset_size;
1734   return offset_size;
1735 }
1736 
GetOffsetSizeNeeded(uint32_t location,uint32_t target)1737 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1738                                                                              uint32_t target) {
1739   // For unresolved targets assume the shortest encoding
1740   // (later it will be made longer if needed).
1741   if (target == kUnresolved)
1742     return kOffset16;
1743   int64_t distance = static_cast<int64_t>(target) - location;
1744   // To simplify calculations in composite branches consisting of multiple instructions
1745   // bump up the distance by a value larger than the max byte size of a composite branch.
1746   distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1747   if (IsInt<kOffset16>(distance))
1748     return kOffset16;
1749   else if (IsInt<kOffset18>(distance))
1750     return kOffset18;
1751   else if (IsInt<kOffset21>(distance))
1752     return kOffset21;
1753   else if (IsInt<kOffset23>(distance))
1754     return kOffset23;
1755   else if (IsInt<kOffset28>(distance))
1756     return kOffset28;
1757   return kOffset32;
1758 }
1759 
Resolve(uint32_t target)1760 void MipsAssembler::Branch::Resolve(uint32_t target) {
1761   target_ = target;
1762 }
1763 
Relocate(uint32_t expand_location,uint32_t delta)1764 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1765   if (location_ > expand_location) {
1766     location_ += delta;
1767   }
1768   if (!IsResolved()) {
1769     return;  // Don't know the target yet.
1770   }
1771   if (target_ > expand_location) {
1772     target_ += delta;
1773   }
1774 }
1775 
PromoteToLong()1776 void MipsAssembler::Branch::PromoteToLong() {
1777   switch (type_) {
1778     // R2 short branches.
1779     case kUncondBranch:
1780       type_ = kLongUncondBranch;
1781       break;
1782     case kCondBranch:
1783       type_ = kLongCondBranch;
1784       break;
1785     case kCall:
1786       type_ = kLongCall;
1787       break;
1788     // R6 short branches.
1789     case kR6UncondBranch:
1790       type_ = kR6LongUncondBranch;
1791       break;
1792     case kR6CondBranch:
1793       type_ = kR6LongCondBranch;
1794       break;
1795     case kR6Call:
1796       type_ = kR6LongCall;
1797       break;
1798     default:
1799       // Note: 'type_' is already long.
1800       break;
1801   }
1802   CHECK(IsLong());
1803 }
1804 
PromoteIfNeeded(uint32_t max_short_distance)1805 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1806   // If the branch is still unresolved or already long, nothing to do.
1807   if (IsLong() || !IsResolved()) {
1808     return 0;
1809   }
1810   // Promote the short branch to long if the offset size is too small
1811   // to hold the distance between location_ and target_.
1812   if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1813     PromoteToLong();
1814     uint32_t old_size = GetOldSize();
1815     uint32_t new_size = GetSize();
1816     CHECK_GT(new_size, old_size);
1817     return new_size - old_size;
1818   }
1819   // The following logic is for debugging/testing purposes.
1820   // Promote some short branches to long when it's not really required.
1821   if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1822     int64_t distance = static_cast<int64_t>(target_) - location_;
1823     distance = (distance >= 0) ? distance : -distance;
1824     if (distance >= max_short_distance) {
1825       PromoteToLong();
1826       uint32_t old_size = GetOldSize();
1827       uint32_t new_size = GetSize();
1828       CHECK_GT(new_size, old_size);
1829       return new_size - old_size;
1830     }
1831   }
1832   return 0;
1833 }
1834 
GetOffsetLocation() const1835 uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1836   return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1837 }
1838 
GetOffset() const1839 uint32_t MipsAssembler::Branch::GetOffset() const {
1840   CHECK(IsResolved());
1841   uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1842   // Calculate the byte distance between instructions and also account for
1843   // different PC-relative origins.
1844   uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1845   // Prepare the offset for encoding into the instruction(s).
1846   offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1847   return offset;
1848 }
1849 
GetBranch(uint32_t branch_id)1850 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1851   CHECK_LT(branch_id, branches_.size());
1852   return &branches_[branch_id];
1853 }
1854 
GetBranch(uint32_t branch_id) const1855 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1856   CHECK_LT(branch_id, branches_.size());
1857   return &branches_[branch_id];
1858 }
1859 
Bind(MipsLabel * label)1860 void MipsAssembler::Bind(MipsLabel* label) {
1861   CHECK(!label->IsBound());
1862   uint32_t bound_pc = buffer_.Size();
1863 
1864   // Walk the list of branches referring to and preceding this label.
1865   // Store the previously unknown target addresses in them.
1866   while (label->IsLinked()) {
1867     uint32_t branch_id = label->Position();
1868     Branch* branch = GetBranch(branch_id);
1869     branch->Resolve(bound_pc);
1870 
1871     uint32_t branch_location = branch->GetLocation();
1872     // Extract the location of the previous branch in the list (walking the list backwards;
1873     // the previous branch ID was stored in the space reserved for this branch).
1874     uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1875 
1876     // On to the previous branch in the list...
1877     label->position_ = prev;
1878   }
1879 
1880   // Now make the label object contain its own location (relative to the end of the preceding
1881   // branch, if any; it will be used by the branches referring to and following this label).
1882   label->prev_branch_id_plus_one_ = branches_.size();
1883   if (label->prev_branch_id_plus_one_) {
1884     uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1885     const Branch* branch = GetBranch(branch_id);
1886     bound_pc -= branch->GetEndLocation();
1887   }
1888   label->BindTo(bound_pc);
1889 }
1890 
GetLabelLocation(MipsLabel * label) const1891 uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1892   CHECK(label->IsBound());
1893   uint32_t target = label->Position();
1894   if (label->prev_branch_id_plus_one_) {
1895     // Get label location based on the branch preceding it.
1896     uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1897     const Branch* branch = GetBranch(branch_id);
1898     target += branch->GetEndLocation();
1899   }
1900   return target;
1901 }
1902 
GetAdjustedPosition(uint32_t old_position)1903 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1904   // We can reconstruct the adjustment by going through all the branches from the beginning
1905   // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1906   // with increasing old_position, we can use the data from last AdjustedPosition() to
1907   // continue where we left off and the whole loop should be O(m+n) where m is the number
1908   // of positions to adjust and n is the number of branches.
1909   if (old_position < last_old_position_) {
1910     last_position_adjustment_ = 0;
1911     last_old_position_ = 0;
1912     last_branch_id_ = 0;
1913   }
1914   while (last_branch_id_ != branches_.size()) {
1915     const Branch* branch = GetBranch(last_branch_id_);
1916     if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1917       break;
1918     }
1919     last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1920     ++last_branch_id_;
1921   }
1922   last_old_position_ = old_position;
1923   return old_position + last_position_adjustment_;
1924 }
1925 
FinalizeLabeledBranch(MipsLabel * label)1926 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1927   uint32_t length = branches_.back().GetLength();
1928   if (!label->IsBound()) {
1929     // Branch forward (to a following label), distance is unknown.
1930     // The first branch forward will contain 0, serving as the terminator of
1931     // the list of forward-reaching branches.
1932     Emit(label->position_);
1933     length--;
1934     // Now make the label object point to this branch
1935     // (this forms a linked list of branches preceding this label).
1936     uint32_t branch_id = branches_.size() - 1;
1937     label->LinkTo(branch_id);
1938   }
1939   // Reserve space for the branch.
1940   while (length--) {
1941     Nop();
1942   }
1943 }
1944 
Buncond(MipsLabel * label)1945 void MipsAssembler::Buncond(MipsLabel* label) {
1946   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1947   branches_.emplace_back(IsR6(), buffer_.Size(), target);
1948   FinalizeLabeledBranch(label);
1949 }
1950 
Bcond(MipsLabel * label,BranchCondition condition,Register lhs,Register rhs)1951 void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1952   // If lhs = rhs, this can be a NOP.
1953   if (Branch::IsNop(condition, lhs, rhs)) {
1954     return;
1955   }
1956   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1957   branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1958   FinalizeLabeledBranch(label);
1959 }
1960 
Call(MipsLabel * label,Register indirect_reg)1961 void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1962   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1963   branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1964   FinalizeLabeledBranch(label);
1965 }
1966 
PromoteBranches()1967 void MipsAssembler::PromoteBranches() {
1968   // Promote short branches to long as necessary.
1969   bool changed;
1970   do {
1971     changed = false;
1972     for (auto& branch : branches_) {
1973       CHECK(branch.IsResolved());
1974       uint32_t delta = branch.PromoteIfNeeded();
1975       // If this branch has been promoted and needs to expand in size,
1976       // relocate all branches by the expansion size.
1977       if (delta) {
1978         changed = true;
1979         uint32_t expand_location = branch.GetLocation();
1980         for (auto& branch2 : branches_) {
1981           branch2.Relocate(expand_location, delta);
1982         }
1983       }
1984     }
1985   } while (changed);
1986 
1987   // Account for branch expansion by resizing the code buffer
1988   // and moving the code in it to its final location.
1989   size_t branch_count = branches_.size();
1990   if (branch_count > 0) {
1991     // Resize.
1992     Branch& last_branch = branches_[branch_count - 1];
1993     uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1994     uint32_t old_size = buffer_.Size();
1995     buffer_.Resize(old_size + size_delta);
1996     // Move the code residing between branch placeholders.
1997     uint32_t end = old_size;
1998     for (size_t i = branch_count; i > 0; ) {
1999       Branch& branch = branches_[--i];
2000       uint32_t size = end - branch.GetOldEndLocation();
2001       buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
2002       end = branch.GetOldLocation();
2003     }
2004   }
2005 }
2006 
2007 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2008 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
2009   // R2 short branches.
2010   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kUncondBranch
2011   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCondBranch
2012   {  5, 2, 0, MipsAssembler::Branch::kOffset16, 0 },  // kCall
2013   // R2 long branches.
2014   {  9, 3, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongUncondBranch
2015   { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCondBranch
2016   {  6, 1, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCall
2017   // R6 short branches.
2018   {  1, 0, 1, MipsAssembler::Branch::kOffset28, 2 },  // kR6UncondBranch
2019   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kR6CondBranch
2020                                                       // Exception: kOffset23 for beqzc/bnezc.
2021   {  2, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Call
2022   // R6 long branches.
2023   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongUncondBranch
2024   {  3, 1, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCondBranch
2025   {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCall
2026 };
2027 
2028 // Note: make sure branch_info_[] and mitBranch() are kept synchronized.
EmitBranch(MipsAssembler::Branch * branch)2029 void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
2030   CHECK_EQ(overwriting_, true);
2031   overwrite_location_ = branch->GetLocation();
2032   uint32_t offset = branch->GetOffset();
2033   BranchCondition condition = branch->GetCondition();
2034   Register lhs = branch->GetLeftRegister();
2035   Register rhs = branch->GetRightRegister();
2036   switch (branch->GetType()) {
2037     // R2 short branches.
2038     case Branch::kUncondBranch:
2039       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2040       B(offset);
2041       Nop();  // TODO: improve by filling the delay slot.
2042       break;
2043     case Branch::kCondBranch:
2044       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2045       EmitBcondR2(condition, lhs, rhs, offset);
2046       Nop();  // TODO: improve by filling the delay slot.
2047       break;
2048     case Branch::kCall:
2049       Nal();
2050       Nop();  // TODO: is this NOP really needed here?
2051       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2052       Addiu(lhs, RA, offset);
2053       Jalr(lhs);
2054       Nop();
2055       break;
2056 
2057     // R2 long branches.
2058     case Branch::kLongUncondBranch:
2059       // To get the value of the PC register we need to use the NAL instruction.
2060       // NAL clobbers the RA register. However, RA must be preserved if the
2061       // method is compiled without the entry/exit sequences that would take care
2062       // of preserving RA (typically, leaf methods don't preserve RA explicitly).
2063       // So, we need to preserve RA in some temporary storage ourselves. The AT
2064       // register can't be used for this because we need it to load a constant
2065       // which will be added to the value that NAL stores in RA. And we can't
2066       // use T9 for this in the context of the JNI compiler, which uses it
2067       // as a scratch register (see InterproceduralScratchRegister()).
2068       // If we were to add a 32-bit constant to RA using two ADDIU instructions,
2069       // we'd also need to use the ROTR instruction, which requires no less than
2070       // MIPSR2.
2071       // Perhaps, we could use T8 or one of R2's multiplier/divider registers
2072       // (LO or HI) or even a floating-point register, but that doesn't seem
2073       // like a nice solution. We may want this to work on both R6 and pre-R6.
2074       // For now simply use the stack for RA. This should be OK since for the
2075       // vast majority of code a short PC-relative branch is sufficient.
2076       // TODO: can this be improved?
2077       Push(RA);
2078       Nal();
2079       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2080       Lui(AT, High16Bits(offset));
2081       Ori(AT, AT, Low16Bits(offset));
2082       Addu(AT, AT, RA);
2083       Lw(RA, SP, 0);
2084       Jr(AT);
2085       DecreaseFrameSize(kMipsWordSize);
2086       break;
2087     case Branch::kLongCondBranch:
2088       // The comment on case 'Branch::kLongUncondBranch' applies here as well.
2089       // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
2090       // number of instructions skipped:
2091       // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
2092       EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
2093       Push(RA);
2094       Nal();
2095       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2096       Lui(AT, High16Bits(offset));
2097       Ori(AT, AT, Low16Bits(offset));
2098       Addu(AT, AT, RA);
2099       Lw(RA, SP, 0);
2100       Jr(AT);
2101       DecreaseFrameSize(kMipsWordSize);
2102       break;
2103     case Branch::kLongCall:
2104       Nal();
2105       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2106       Lui(AT, High16Bits(offset));
2107       Ori(AT, AT, Low16Bits(offset));
2108       Addu(lhs, AT, RA);
2109       Jalr(lhs);
2110       Nop();
2111       break;
2112 
2113     // R6 short branches.
2114     case Branch::kR6UncondBranch:
2115       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2116       Bc(offset);
2117       break;
2118     case Branch::kR6CondBranch:
2119       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2120       EmitBcondR6(condition, lhs, rhs, offset);
2121       Nop();  // TODO: improve by filling the forbidden/delay slot.
2122       break;
2123     case Branch::kR6Call:
2124       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2125       Addiupc(lhs, offset);
2126       Jialc(lhs, 0);
2127       break;
2128 
2129     // R6 long branches.
2130     case Branch::kR6LongUncondBranch:
2131       offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
2132       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2133       Auipc(AT, High16Bits(offset));
2134       Jic(AT, Low16Bits(offset));
2135       break;
2136     case Branch::kR6LongCondBranch:
2137       EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
2138       offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
2139       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2140       Auipc(AT, High16Bits(offset));
2141       Jic(AT, Low16Bits(offset));
2142       break;
2143     case Branch::kR6LongCall:
2144       offset += (offset & 0x8000) << 1;  // Account for sign extension in addiu.
2145       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2146       Auipc(lhs, High16Bits(offset));
2147       Addiu(lhs, lhs, Low16Bits(offset));
2148       Jialc(lhs, 0);
2149       break;
2150   }
2151   CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2152   CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
2153 }
2154 
B(MipsLabel * label)2155 void MipsAssembler::B(MipsLabel* label) {
2156   Buncond(label);
2157 }
2158 
Jalr(MipsLabel * label,Register indirect_reg)2159 void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
2160   Call(label, indirect_reg);
2161 }
2162 
Beq(Register rs,Register rt,MipsLabel * label)2163 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
2164   Bcond(label, kCondEQ, rs, rt);
2165 }
2166 
Bne(Register rs,Register rt,MipsLabel * label)2167 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
2168   Bcond(label, kCondNE, rs, rt);
2169 }
2170 
Beqz(Register rt,MipsLabel * label)2171 void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
2172   Bcond(label, kCondEQZ, rt);
2173 }
2174 
Bnez(Register rt,MipsLabel * label)2175 void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2176   Bcond(label, kCondNEZ, rt);
2177 }
2178 
Bltz(Register rt,MipsLabel * label)2179 void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2180   Bcond(label, kCondLTZ, rt);
2181 }
2182 
Bgez(Register rt,MipsLabel * label)2183 void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2184   Bcond(label, kCondGEZ, rt);
2185 }
2186 
Blez(Register rt,MipsLabel * label)2187 void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2188   Bcond(label, kCondLEZ, rt);
2189 }
2190 
Bgtz(Register rt,MipsLabel * label)2191 void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2192   Bcond(label, kCondGTZ, rt);
2193 }
2194 
Blt(Register rs,Register rt,MipsLabel * label)2195 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
2196   if (IsR6()) {
2197     Bcond(label, kCondLT, rs, rt);
2198   } else if (!Branch::IsNop(kCondLT, rs, rt)) {
2199     // Synthesize the instruction (not available on R2).
2200     Slt(AT, rs, rt);
2201     Bnez(AT, label);
2202   }
2203 }
2204 
Bge(Register rs,Register rt,MipsLabel * label)2205 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
2206   if (IsR6()) {
2207     Bcond(label, kCondGE, rs, rt);
2208   } else if (Branch::IsUncond(kCondGE, rs, rt)) {
2209     B(label);
2210   } else {
2211     // Synthesize the instruction (not available on R2).
2212     Slt(AT, rs, rt);
2213     Beqz(AT, label);
2214   }
2215 }
2216 
Bltu(Register rs,Register rt,MipsLabel * label)2217 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
2218   if (IsR6()) {
2219     Bcond(label, kCondLTU, rs, rt);
2220   } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
2221     // Synthesize the instruction (not available on R2).
2222     Sltu(AT, rs, rt);
2223     Bnez(AT, label);
2224   }
2225 }
2226 
Bgeu(Register rs,Register rt,MipsLabel * label)2227 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
2228   if (IsR6()) {
2229     Bcond(label, kCondGEU, rs, rt);
2230   } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
2231     B(label);
2232   } else {
2233     // Synthesize the instruction (not available on R2).
2234     Sltu(AT, rs, rt);
2235     Beqz(AT, label);
2236   }
2237 }
2238 
Bc1f(MipsLabel * label)2239 void MipsAssembler::Bc1f(MipsLabel* label) {
2240   Bc1f(0, label);
2241 }
2242 
Bc1f(int cc,MipsLabel * label)2243 void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2244   CHECK(IsUint<3>(cc)) << cc;
2245   Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2246 }
2247 
Bc1t(MipsLabel * label)2248 void MipsAssembler::Bc1t(MipsLabel* label) {
2249   Bc1t(0, label);
2250 }
2251 
Bc1t(int cc,MipsLabel * label)2252 void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2253   CHECK(IsUint<3>(cc)) << cc;
2254   Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2255 }
2256 
Bc1eqz(FRegister ft,MipsLabel * label)2257 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2258   Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2259 }
2260 
Bc1nez(FRegister ft,MipsLabel * label)2261 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2262   Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2263 }
2264 
LoadFromOffset(LoadOperandType type,Register reg,Register base,int32_t offset)2265 void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
2266                                    int32_t offset) {
2267   // IsInt<16> must be passed a signed value.
2268   if (!IsInt<16>(offset) ||
2269       (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2270     LoadConst32(AT, offset);
2271     Addu(AT, AT, base);
2272     base = AT;
2273     offset = 0;
2274   }
2275 
2276   switch (type) {
2277     case kLoadSignedByte:
2278       Lb(reg, base, offset);
2279       break;
2280     case kLoadUnsignedByte:
2281       Lbu(reg, base, offset);
2282       break;
2283     case kLoadSignedHalfword:
2284       Lh(reg, base, offset);
2285       break;
2286     case kLoadUnsignedHalfword:
2287       Lhu(reg, base, offset);
2288       break;
2289     case kLoadWord:
2290       Lw(reg, base, offset);
2291       break;
2292     case kLoadDoubleword:
2293       if (reg == base) {
2294         // This will clobber the base when loading the lower register. Since we have to load the
2295         // higher register as well, this will fail. Solution: reverse the order.
2296         Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2297         Lw(reg, base, offset);
2298       } else {
2299         Lw(reg, base, offset);
2300         Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2301       }
2302       break;
2303     default:
2304       LOG(FATAL) << "UNREACHABLE";
2305   }
2306 }
2307 
LoadSFromOffset(FRegister reg,Register base,int32_t offset)2308 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
2309   if (!IsInt<16>(offset)) {
2310     LoadConst32(AT, offset);
2311     Addu(AT, AT, base);
2312     base = AT;
2313     offset = 0;
2314   }
2315 
2316   Lwc1(reg, base, offset);
2317 }
2318 
LoadDFromOffset(FRegister reg,Register base,int32_t offset)2319 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
2320   // IsInt<16> must be passed a signed value.
2321   if (!IsInt<16>(offset) ||
2322       (!IsAligned<kMipsDoublewordSize>(offset) &&
2323        !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2324     LoadConst32(AT, offset);
2325     Addu(AT, AT, base);
2326     base = AT;
2327     offset = 0;
2328   }
2329 
2330   if (offset & 0x7) {
2331     if (Is32BitFPU()) {
2332       Lwc1(reg, base, offset);
2333       Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2334     } else {
2335       // 64-bit FPU.
2336       Lwc1(reg, base, offset);
2337       Lw(T8, base, offset + kMipsWordSize);
2338       Mthc1(T8, reg);
2339     }
2340   } else {
2341     Ldc1(reg, base, offset);
2342   }
2343 }
2344 
EmitLoad(ManagedRegister m_dst,Register src_register,int32_t src_offset,size_t size)2345 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
2346                              size_t size) {
2347   MipsManagedRegister dst = m_dst.AsMips();
2348   if (dst.IsNoRegister()) {
2349     CHECK_EQ(0u, size) << dst;
2350   } else if (dst.IsCoreRegister()) {
2351     CHECK_EQ(kMipsWordSize, size) << dst;
2352     LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
2353   } else if (dst.IsRegisterPair()) {
2354     CHECK_EQ(kMipsDoublewordSize, size) << dst;
2355     LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
2356   } else if (dst.IsFRegister()) {
2357     if (size == kMipsWordSize) {
2358       LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
2359     } else {
2360       CHECK_EQ(kMipsDoublewordSize, size) << dst;
2361       LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
2362     }
2363   }
2364 }
2365 
StoreToOffset(StoreOperandType type,Register reg,Register base,int32_t offset)2366 void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
2367                                   int32_t offset) {
2368   // IsInt<16> must be passed a signed value.
2369   if (!IsInt<16>(offset) ||
2370       (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2371     LoadConst32(AT, offset);
2372     Addu(AT, AT, base);
2373     base = AT;
2374     offset = 0;
2375   }
2376 
2377   switch (type) {
2378     case kStoreByte:
2379       Sb(reg, base, offset);
2380       break;
2381     case kStoreHalfword:
2382       Sh(reg, base, offset);
2383       break;
2384     case kStoreWord:
2385       Sw(reg, base, offset);
2386       break;
2387     case kStoreDoubleword:
2388       CHECK_NE(reg, base);
2389       CHECK_NE(static_cast<Register>(reg + 1), base);
2390       Sw(reg, base, offset);
2391       Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2392       break;
2393     default:
2394       LOG(FATAL) << "UNREACHABLE";
2395   }
2396 }
2397 
StoreSToOffset(FRegister reg,Register base,int32_t offset)2398 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
2399   if (!IsInt<16>(offset)) {
2400     LoadConst32(AT, offset);
2401     Addu(AT, AT, base);
2402     base = AT;
2403     offset = 0;
2404   }
2405 
2406   Swc1(reg, base, offset);
2407 }
2408 
StoreDToOffset(FRegister reg,Register base,int32_t offset)2409 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
2410   // IsInt<16> must be passed a signed value.
2411   if (!IsInt<16>(offset) ||
2412       (!IsAligned<kMipsDoublewordSize>(offset) &&
2413        !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2414     LoadConst32(AT, offset);
2415     Addu(AT, AT, base);
2416     base = AT;
2417     offset = 0;
2418   }
2419 
2420   if (offset & 0x7) {
2421     if (Is32BitFPU()) {
2422       Swc1(reg, base, offset);
2423       Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2424     } else {
2425       // 64-bit FPU.
2426       Mfhc1(T8, reg);
2427       Swc1(reg, base, offset);
2428       Sw(T8, base, offset + kMipsWordSize);
2429     }
2430   } else {
2431     Sdc1(reg, base, offset);
2432   }
2433 }
2434 
DWARFReg(Register reg)2435 static dwarf::Reg DWARFReg(Register reg) {
2436   return dwarf::Reg::MipsCore(static_cast<int>(reg));
2437 }
2438 
2439 constexpr size_t kFramePointerSize = 4;
2440 
BuildFrame(size_t frame_size,ManagedRegister method_reg,const std::vector<ManagedRegister> & callee_save_regs,const ManagedRegisterEntrySpills & entry_spills)2441 void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
2442                                const std::vector<ManagedRegister>& callee_save_regs,
2443                                const ManagedRegisterEntrySpills& entry_spills) {
2444   CHECK_ALIGNED(frame_size, kStackAlignment);
2445   DCHECK(!overwriting_);
2446 
2447   // Increase frame to required size.
2448   IncreaseFrameSize(frame_size);
2449 
2450   // Push callee saves and return address.
2451   int stack_offset = frame_size - kFramePointerSize;
2452   StoreToOffset(kStoreWord, RA, SP, stack_offset);
2453   cfi_.RelOffset(DWARFReg(RA), stack_offset);
2454   for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2455     stack_offset -= kFramePointerSize;
2456     Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2457     StoreToOffset(kStoreWord, reg, SP, stack_offset);
2458     cfi_.RelOffset(DWARFReg(reg), stack_offset);
2459   }
2460 
2461   // Write out Method*.
2462   StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
2463 
2464   // Write out entry spills.
2465   int32_t offset = frame_size + kFramePointerSize;
2466   for (size_t i = 0; i < entry_spills.size(); ++i) {
2467     MipsManagedRegister reg = entry_spills.at(i).AsMips();
2468     if (reg.IsNoRegister()) {
2469       ManagedRegisterSpill spill = entry_spills.at(i);
2470       offset += spill.getSize();
2471     } else if (reg.IsCoreRegister()) {
2472       StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
2473       offset += kMipsWordSize;
2474     } else if (reg.IsFRegister()) {
2475       StoreSToOffset(reg.AsFRegister(), SP, offset);
2476       offset += kMipsWordSize;
2477     } else if (reg.IsDRegister()) {
2478       StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
2479       offset += kMipsDoublewordSize;
2480     }
2481   }
2482 }
2483 
RemoveFrame(size_t frame_size,const std::vector<ManagedRegister> & callee_save_regs)2484 void MipsAssembler::RemoveFrame(size_t frame_size,
2485                                 const std::vector<ManagedRegister>& callee_save_regs) {
2486   CHECK_ALIGNED(frame_size, kStackAlignment);
2487   DCHECK(!overwriting_);
2488   cfi_.RememberState();
2489 
2490   // Pop callee saves and return address.
2491   int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2492   for (size_t i = 0; i < callee_save_regs.size(); ++i) {
2493     Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2494     LoadFromOffset(kLoadWord, reg, SP, stack_offset);
2495     cfi_.Restore(DWARFReg(reg));
2496     stack_offset += kFramePointerSize;
2497   }
2498   LoadFromOffset(kLoadWord, RA, SP, stack_offset);
2499   cfi_.Restore(DWARFReg(RA));
2500 
2501   // Decrease frame to required size.
2502   DecreaseFrameSize(frame_size);
2503 
2504   // Then jump to the return address.
2505   Jr(RA);
2506   Nop();
2507 
2508   // The CFI should be restored for any code that follows the exit block.
2509   cfi_.RestoreState();
2510   cfi_.DefCFAOffset(frame_size);
2511 }
2512 
IncreaseFrameSize(size_t adjust)2513 void MipsAssembler::IncreaseFrameSize(size_t adjust) {
2514   CHECK_ALIGNED(adjust, kFramePointerSize);
2515   Addiu32(SP, SP, -adjust);
2516   cfi_.AdjustCFAOffset(adjust);
2517   if (overwriting_) {
2518     cfi_.OverrideDelayedPC(overwrite_location_);
2519   }
2520 }
2521 
DecreaseFrameSize(size_t adjust)2522 void MipsAssembler::DecreaseFrameSize(size_t adjust) {
2523   CHECK_ALIGNED(adjust, kFramePointerSize);
2524   Addiu32(SP, SP, adjust);
2525   cfi_.AdjustCFAOffset(-adjust);
2526   if (overwriting_) {
2527     cfi_.OverrideDelayedPC(overwrite_location_);
2528   }
2529 }
2530 
Store(FrameOffset dest,ManagedRegister msrc,size_t size)2531 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2532   MipsManagedRegister src = msrc.AsMips();
2533   if (src.IsNoRegister()) {
2534     CHECK_EQ(0u, size);
2535   } else if (src.IsCoreRegister()) {
2536     CHECK_EQ(kMipsWordSize, size);
2537     StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2538   } else if (src.IsRegisterPair()) {
2539     CHECK_EQ(kMipsDoublewordSize, size);
2540     StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
2541     StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
2542                   SP, dest.Int32Value() + kMipsWordSize);
2543   } else if (src.IsFRegister()) {
2544     if (size == kMipsWordSize) {
2545       StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
2546     } else {
2547       CHECK_EQ(kMipsDoublewordSize, size);
2548       StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
2549     }
2550   }
2551 }
2552 
StoreRef(FrameOffset dest,ManagedRegister msrc)2553 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2554   MipsManagedRegister src = msrc.AsMips();
2555   CHECK(src.IsCoreRegister());
2556   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2557 }
2558 
StoreRawPtr(FrameOffset dest,ManagedRegister msrc)2559 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2560   MipsManagedRegister src = msrc.AsMips();
2561   CHECK(src.IsCoreRegister());
2562   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2563 }
2564 
StoreImmediateToFrame(FrameOffset dest,uint32_t imm,ManagedRegister mscratch)2565 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2566                                           ManagedRegister mscratch) {
2567   MipsManagedRegister scratch = mscratch.AsMips();
2568   CHECK(scratch.IsCoreRegister()) << scratch;
2569   LoadConst32(scratch.AsCoreRegister(), imm);
2570   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2571 }
2572 
StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest,uint32_t imm,ManagedRegister mscratch)2573 void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
2574                                              ManagedRegister mscratch) {
2575   MipsManagedRegister scratch = mscratch.AsMips();
2576   CHECK(scratch.IsCoreRegister()) << scratch;
2577   // Is this function even referenced anywhere else in the code?
2578   LoadConst32(scratch.AsCoreRegister(), imm);
2579   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
2580 }
2581 
StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)2582 void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2583                                                FrameOffset fr_offs,
2584                                                ManagedRegister mscratch) {
2585   MipsManagedRegister scratch = mscratch.AsMips();
2586   CHECK(scratch.IsCoreRegister()) << scratch;
2587   Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
2588   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2589                 S1, thr_offs.Int32Value());
2590 }
2591 
StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs)2592 void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
2593   StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2594 }
2595 
StoreSpanning(FrameOffset dest,ManagedRegister msrc,FrameOffset in_off,ManagedRegister mscratch)2596 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2597                                   FrameOffset in_off, ManagedRegister mscratch) {
2598   MipsManagedRegister src = msrc.AsMips();
2599   MipsManagedRegister scratch = mscratch.AsMips();
2600   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2601   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
2602   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
2603 }
2604 
Load(ManagedRegister mdest,FrameOffset src,size_t size)2605 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2606   return EmitLoad(mdest, SP, src.Int32Value(), size);
2607 }
2608 
LoadFromThread32(ManagedRegister mdest,ThreadOffset<kMipsWordSize> src,size_t size)2609 void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2610                                      ThreadOffset<kMipsWordSize> src, size_t size) {
2611   return EmitLoad(mdest, S1, src.Int32Value(), size);
2612 }
2613 
LoadRef(ManagedRegister mdest,FrameOffset src)2614 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2615   MipsManagedRegister dest = mdest.AsMips();
2616   CHECK(dest.IsCoreRegister());
2617   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
2618 }
2619 
LoadRef(ManagedRegister mdest,ManagedRegister base,MemberOffset offs,bool unpoison_reference)2620 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
2621                             bool unpoison_reference) {
2622   MipsManagedRegister dest = mdest.AsMips();
2623   CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
2624   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2625                  base.AsMips().AsCoreRegister(), offs.Int32Value());
2626   if (kPoisonHeapReferences && unpoison_reference) {
2627     Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
2628   }
2629 }
2630 
LoadRawPtr(ManagedRegister mdest,ManagedRegister base,Offset offs)2631 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
2632   MipsManagedRegister dest = mdest.AsMips();
2633   CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
2634   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2635                  base.AsMips().AsCoreRegister(), offs.Int32Value());
2636 }
2637 
LoadRawPtrFromThread32(ManagedRegister mdest,ThreadOffset<kMipsWordSize> offs)2638 void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
2639                                            ThreadOffset<kMipsWordSize> offs) {
2640   MipsManagedRegister dest = mdest.AsMips();
2641   CHECK(dest.IsCoreRegister());
2642   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
2643 }
2644 
SignExtend(ManagedRegister,size_t)2645 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2646   UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2647 }
2648 
ZeroExtend(ManagedRegister,size_t)2649 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2650   UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2651 }
2652 
Move(ManagedRegister mdest,ManagedRegister msrc,size_t size)2653 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2654   MipsManagedRegister dest = mdest.AsMips();
2655   MipsManagedRegister src = msrc.AsMips();
2656   if (!dest.Equals(src)) {
2657     if (dest.IsCoreRegister()) {
2658       CHECK(src.IsCoreRegister()) << src;
2659       Move(dest.AsCoreRegister(), src.AsCoreRegister());
2660     } else if (dest.IsFRegister()) {
2661       CHECK(src.IsFRegister()) << src;
2662       if (size == kMipsWordSize) {
2663         MovS(dest.AsFRegister(), src.AsFRegister());
2664       } else {
2665         CHECK_EQ(kMipsDoublewordSize, size);
2666         MovD(dest.AsFRegister(), src.AsFRegister());
2667       }
2668     } else if (dest.IsDRegister()) {
2669       CHECK(src.IsDRegister()) << src;
2670       MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
2671     } else {
2672       CHECK(dest.IsRegisterPair()) << dest;
2673       CHECK(src.IsRegisterPair()) << src;
2674       // Ensure that the first move doesn't clobber the input of the second.
2675       if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
2676         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2677         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2678       } else {
2679         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2680         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2681       }
2682     }
2683   }
2684 }
2685 
CopyRef(FrameOffset dest,FrameOffset src,ManagedRegister mscratch)2686 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
2687   MipsManagedRegister scratch = mscratch.AsMips();
2688   CHECK(scratch.IsCoreRegister()) << scratch;
2689   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2690   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2691 }
2692 
CopyRawPtrFromThread32(FrameOffset fr_offs,ThreadOffset<kMipsWordSize> thr_offs,ManagedRegister mscratch)2693 void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
2694                                            ThreadOffset<kMipsWordSize> thr_offs,
2695                                            ManagedRegister mscratch) {
2696   MipsManagedRegister scratch = mscratch.AsMips();
2697   CHECK(scratch.IsCoreRegister()) << scratch;
2698   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2699                  S1, thr_offs.Int32Value());
2700   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2701                 SP, fr_offs.Int32Value());
2702 }
2703 
CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)2704 void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2705                                          FrameOffset fr_offs,
2706                                          ManagedRegister mscratch) {
2707   MipsManagedRegister scratch = mscratch.AsMips();
2708   CHECK(scratch.IsCoreRegister()) << scratch;
2709   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2710                  SP, fr_offs.Int32Value());
2711   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2712                 S1, thr_offs.Int32Value());
2713 }
2714 
Copy(FrameOffset dest,FrameOffset src,ManagedRegister mscratch,size_t size)2715 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
2716   MipsManagedRegister scratch = mscratch.AsMips();
2717   CHECK(scratch.IsCoreRegister()) << scratch;
2718   CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2719   if (size == kMipsWordSize) {
2720     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2721     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2722   } else if (size == kMipsDoublewordSize) {
2723     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2724     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2725     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2726     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
2727   }
2728 }
2729 
Copy(FrameOffset dest,ManagedRegister src_base,Offset src_offset,ManagedRegister mscratch,size_t size)2730 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2731                          ManagedRegister mscratch, size_t size) {
2732   Register scratch = mscratch.AsMips().AsCoreRegister();
2733   CHECK_EQ(size, kMipsWordSize);
2734   LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2735   StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2736 }
2737 
Copy(ManagedRegister dest_base,Offset dest_offset,FrameOffset src,ManagedRegister mscratch,size_t size)2738 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2739                          ManagedRegister mscratch, size_t size) {
2740   Register scratch = mscratch.AsMips().AsCoreRegister();
2741   CHECK_EQ(size, kMipsWordSize);
2742   LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2743   StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2744 }
2745 
Copy(FrameOffset dest ATTRIBUTE_UNUSED,FrameOffset src_base ATTRIBUTE_UNUSED,Offset src_offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)2746 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2747                          FrameOffset src_base ATTRIBUTE_UNUSED,
2748                          Offset src_offset ATTRIBUTE_UNUSED,
2749                          ManagedRegister mscratch ATTRIBUTE_UNUSED,
2750                          size_t size ATTRIBUTE_UNUSED) {
2751   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2752 }
2753 
Copy(ManagedRegister dest,Offset dest_offset,ManagedRegister src,Offset src_offset,ManagedRegister mscratch,size_t size)2754 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2755                          ManagedRegister src, Offset src_offset,
2756                          ManagedRegister mscratch, size_t size) {
2757   CHECK_EQ(size, kMipsWordSize);
2758   Register scratch = mscratch.AsMips().AsCoreRegister();
2759   LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2760   StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2761 }
2762 
Copy(FrameOffset dest ATTRIBUTE_UNUSED,Offset dest_offset ATTRIBUTE_UNUSED,FrameOffset src ATTRIBUTE_UNUSED,Offset src_offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)2763 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2764                          Offset dest_offset ATTRIBUTE_UNUSED,
2765                          FrameOffset src ATTRIBUTE_UNUSED,
2766                          Offset src_offset ATTRIBUTE_UNUSED,
2767                          ManagedRegister mscratch ATTRIBUTE_UNUSED,
2768                          size_t size ATTRIBUTE_UNUSED) {
2769   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2770 }
2771 
MemoryBarrier(ManagedRegister)2772 void MipsAssembler::MemoryBarrier(ManagedRegister) {
2773   // TODO: sync?
2774   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2775 }
2776 
CreateHandleScopeEntry(ManagedRegister mout_reg,FrameOffset handle_scope_offset,ManagedRegister min_reg,bool null_allowed)2777 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
2778                                            FrameOffset handle_scope_offset,
2779                                            ManagedRegister min_reg,
2780                                            bool null_allowed) {
2781   MipsManagedRegister out_reg = mout_reg.AsMips();
2782   MipsManagedRegister in_reg = min_reg.AsMips();
2783   CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2784   CHECK(out_reg.IsCoreRegister()) << out_reg;
2785   if (null_allowed) {
2786     MipsLabel null_arg;
2787     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2788     // the address in the handle scope holding the reference.
2789     // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
2790     if (in_reg.IsNoRegister()) {
2791       LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2792                      SP, handle_scope_offset.Int32Value());
2793       in_reg = out_reg;
2794     }
2795     if (!out_reg.Equals(in_reg)) {
2796       LoadConst32(out_reg.AsCoreRegister(), 0);
2797     }
2798     Beqz(in_reg.AsCoreRegister(), &null_arg);
2799     Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2800     Bind(&null_arg);
2801   } else {
2802     Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2803   }
2804 }
2805 
CreateHandleScopeEntry(FrameOffset out_off,FrameOffset handle_scope_offset,ManagedRegister mscratch,bool null_allowed)2806 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
2807                                            FrameOffset handle_scope_offset,
2808                                            ManagedRegister mscratch,
2809                                            bool null_allowed) {
2810   MipsManagedRegister scratch = mscratch.AsMips();
2811   CHECK(scratch.IsCoreRegister()) << scratch;
2812   if (null_allowed) {
2813     MipsLabel null_arg;
2814     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2815     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2816     // the address in the handle scope holding the reference.
2817     // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2818     Beqz(scratch.AsCoreRegister(), &null_arg);
2819     Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2820     Bind(&null_arg);
2821   } else {
2822     Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2823   }
2824   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2825 }
2826 
2827 // Given a handle scope entry, load the associated reference.
LoadReferenceFromHandleScope(ManagedRegister mout_reg,ManagedRegister min_reg)2828 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
2829                                                  ManagedRegister min_reg) {
2830   MipsManagedRegister out_reg = mout_reg.AsMips();
2831   MipsManagedRegister in_reg = min_reg.AsMips();
2832   CHECK(out_reg.IsCoreRegister()) << out_reg;
2833   CHECK(in_reg.IsCoreRegister()) << in_reg;
2834   MipsLabel null_arg;
2835   if (!out_reg.Equals(in_reg)) {
2836     LoadConst32(out_reg.AsCoreRegister(), 0);
2837   }
2838   Beqz(in_reg.AsCoreRegister(), &null_arg);
2839   LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2840                  in_reg.AsCoreRegister(), 0);
2841   Bind(&null_arg);
2842 }
2843 
VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)2844 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2845                                  bool could_be_null ATTRIBUTE_UNUSED) {
2846   // TODO: not validating references.
2847 }
2848 
VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)2849 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2850                                  bool could_be_null ATTRIBUTE_UNUSED) {
2851   // TODO: not validating references.
2852 }
2853 
Call(ManagedRegister mbase,Offset offset,ManagedRegister mscratch)2854 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2855   MipsManagedRegister base = mbase.AsMips();
2856   MipsManagedRegister scratch = mscratch.AsMips();
2857   CHECK(base.IsCoreRegister()) << base;
2858   CHECK(scratch.IsCoreRegister()) << scratch;
2859   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2860                  base.AsCoreRegister(), offset.Int32Value());
2861   Jalr(scratch.AsCoreRegister());
2862   Nop();
2863   // TODO: place reference map on call.
2864 }
2865 
Call(FrameOffset base,Offset offset,ManagedRegister mscratch)2866 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2867   MipsManagedRegister scratch = mscratch.AsMips();
2868   CHECK(scratch.IsCoreRegister()) << scratch;
2869   // Call *(*(SP + base) + offset)
2870   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
2871   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2872                  scratch.AsCoreRegister(), offset.Int32Value());
2873   Jalr(scratch.AsCoreRegister());
2874   Nop();
2875   // TODO: place reference map on call.
2876 }
2877 
CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED)2878 void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2879                                      ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2880   UNIMPLEMENTED(FATAL) << "no mips implementation";
2881 }
2882 
GetCurrentThread(ManagedRegister tr)2883 void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2884   Move(tr.AsMips().AsCoreRegister(), S1);
2885 }
2886 
GetCurrentThread(FrameOffset offset,ManagedRegister mscratch ATTRIBUTE_UNUSED)2887 void MipsAssembler::GetCurrentThread(FrameOffset offset,
2888                                      ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2889   StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2890 }
2891 
ExceptionPoll(ManagedRegister mscratch,size_t stack_adjust)2892 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2893   MipsManagedRegister scratch = mscratch.AsMips();
2894   exception_blocks_.emplace_back(scratch, stack_adjust);
2895   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2896                  S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2897   // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2898   // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2899   // For now use common for R2 and R6 instructions as this code must execute on both.
2900   Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
2901 }
2902 
EmitExceptionPoll(MipsExceptionSlowPath * exception)2903 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2904   Bind(exception->Entry());
2905   if (exception->stack_adjust_ != 0) {  // Fix up the frame.
2906     DecreaseFrameSize(exception->stack_adjust_);
2907   }
2908   // Pass exception object as argument.
2909   // Don't care about preserving A0 as this call won't return.
2910   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2911   Move(A0, exception->scratch_.AsCoreRegister());
2912   // Set up call to Thread::Current()->pDeliverException.
2913   LoadFromOffset(kLoadWord, T9, S1,
2914     QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2915   Jr(T9);
2916   Nop();
2917 
2918   // Call never returns.
2919   Break();
2920 }
2921 
2922 }  // namespace mips
2923 }  // namespace art
2924