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
26namespace art {
27namespace mips {
28
29std::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
38void MipsAssembler::FinalizeCode() {
39  for (auto& exception_block : exception_blocks_) {
40    EmitExceptionPoll(&exception_block);
41  }
42  PromoteBranches();
43}
44
45void 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
52void 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
102void 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
113void 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
125void 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
138void 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
148void 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
157void 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
163void 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
177void 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
186void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
187  EmitR(0, rs, rt, rd, 0, 0x21);
188}
189
190void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
191  EmitI(0x9, rs, rt, imm16);
192}
193
194void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
195  EmitR(0, rs, rt, rd, 0, 0x23);
196}
197
198void MipsAssembler::MultR2(Register rs, Register rt) {
199  CHECK(!IsR6());
200  EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
201}
202
203void MipsAssembler::MultuR2(Register rs, Register rt) {
204  CHECK(!IsR6());
205  EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
206}
207
208void MipsAssembler::DivR2(Register rs, Register rt) {
209  CHECK(!IsR6());
210  EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
211}
212
213void MipsAssembler::DivuR2(Register rs, Register rt) {
214  CHECK(!IsR6());
215  EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
216}
217
218void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
219  CHECK(!IsR6());
220  EmitR(0x1c, rs, rt, rd, 0, 2);
221}
222
223void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
224  CHECK(!IsR6());
225  DivR2(rs, rt);
226  Mflo(rd);
227}
228
229void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
230  CHECK(!IsR6());
231  DivR2(rs, rt);
232  Mfhi(rd);
233}
234
235void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
236  CHECK(!IsR6());
237  DivuR2(rs, rt);
238  Mflo(rd);
239}
240
241void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
242  CHECK(!IsR6());
243  DivuR2(rs, rt);
244  Mfhi(rd);
245}
246
247void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
248  CHECK(IsR6());
249  EmitR(0, rs, rt, rd, 2, 0x18);
250}
251
252void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
253  CHECK(IsR6());
254  EmitR(0, rs, rt, rd, 3, 0x18);
255}
256
257void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
258  CHECK(IsR6());
259  EmitR(0, rs, rt, rd, 3, 0x19);
260}
261
262void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
263  CHECK(IsR6());
264  EmitR(0, rs, rt, rd, 2, 0x1a);
265}
266
267void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
268  CHECK(IsR6());
269  EmitR(0, rs, rt, rd, 3, 0x1a);
270}
271
272void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
273  CHECK(IsR6());
274  EmitR(0, rs, rt, rd, 2, 0x1b);
275}
276
277void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
278  CHECK(IsR6());
279  EmitR(0, rs, rt, rd, 3, 0x1b);
280}
281
282void MipsAssembler::And(Register rd, Register rs, Register rt) {
283  EmitR(0, rs, rt, rd, 0, 0x24);
284}
285
286void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
287  EmitI(0xc, rs, rt, imm16);
288}
289
290void MipsAssembler::Or(Register rd, Register rs, Register rt) {
291  EmitR(0, rs, rt, rd, 0, 0x25);
292}
293
294void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
295  EmitI(0xd, rs, rt, imm16);
296}
297
298void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
299  EmitR(0, rs, rt, rd, 0, 0x26);
300}
301
302void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
303  EmitI(0xe, rs, rt, imm16);
304}
305
306void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
307  EmitR(0, rs, rt, rd, 0, 0x27);
308}
309
310void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
311  CHECK(!IsR6());
312  EmitR(0, rs, rt, rd, 0, 0x0A);
313}
314
315void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
316  CHECK(!IsR6());
317  EmitR(0, rs, rt, rd, 0, 0x0B);
318}
319
320void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
321  CHECK(IsR6());
322  EmitR(0, rs, rt, rd, 0, 0x35);
323}
324
325void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
326  CHECK(IsR6());
327  EmitR(0, rs, rt, rd, 0, 0x37);
328}
329
330void MipsAssembler::ClzR6(Register rd, Register rs) {
331  CHECK(IsR6());
332  EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10);
333}
334
335void MipsAssembler::ClzR2(Register rd, Register rs) {
336  CHECK(!IsR6());
337  EmitR(0x1C, rs, rd, rd, 0, 0x20);
338}
339
340void MipsAssembler::CloR6(Register rd, Register rs) {
341  CHECK(IsR6());
342  EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11);
343}
344
345void MipsAssembler::CloR2(Register rd, Register rs) {
346  CHECK(!IsR6());
347  EmitR(0x1C, rs, rd, rd, 0, 0x21);
348}
349
350void MipsAssembler::Seb(Register rd, Register rt) {
351  EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
352}
353
354void MipsAssembler::Seh(Register rd, Register rt) {
355  EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20);
356}
357
358void MipsAssembler::Wsbh(Register rd, Register rt) {
359  EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20);
360}
361
362void MipsAssembler::Bitswap(Register rd, Register rt) {
363  CHECK(IsR6());
364  EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20);
365}
366
367void 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
372void 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
377void 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
382void 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
387void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
388  EmitR(0, rs, rt, rd, 0, 0x04);
389}
390
391void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
392  EmitR(0, rs, rt, rd, 0, 0x06);
393}
394
395void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
396  EmitR(0, rs, rt, rd, 1, 0x06);
397}
398
399void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
400  EmitR(0, rs, rt, rd, 0, 0x07);
401}
402
403void 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
410void 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
417void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
418  EmitI(0x20, rs, rt, imm16);
419}
420
421void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
422  EmitI(0x21, rs, rt, imm16);
423}
424
425void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
426  EmitI(0x23, rs, rt, imm16);
427}
428
429void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
430  CHECK(!IsR6());
431  EmitI(0x22, rs, rt, imm16);
432}
433
434void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
435  CHECK(!IsR6());
436  EmitI(0x26, rs, rt, imm16);
437}
438
439void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
440  EmitI(0x24, rs, rt, imm16);
441}
442
443void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
444  EmitI(0x25, rs, rt, imm16);
445}
446
447void MipsAssembler::Lui(Register rt, uint16_t imm16) {
448  EmitI(0xf, static_cast<Register>(0), rt, imm16);
449}
450
451void 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
456void MipsAssembler::Mfhi(Register rd) {
457  CHECK(!IsR6());
458  EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
459}
460
461void MipsAssembler::Mflo(Register rd) {
462  CHECK(!IsR6());
463  EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
464}
465
466void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
467  EmitI(0x28, rs, rt, imm16);
468}
469
470void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
471  EmitI(0x29, rs, rt, imm16);
472}
473
474void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
475  EmitI(0x2b, rs, rt, imm16);
476}
477
478void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
479  CHECK(!IsR6());
480  EmitI(0x2a, rs, rt, imm16);
481}
482
483void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
484  CHECK(!IsR6());
485  EmitI(0x2e, rs, rt, imm16);
486}
487
488void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
489  CHECK(!IsR6());
490  EmitI(0x30, base, rt, imm16);
491}
492
493void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
494  CHECK(!IsR6());
495  EmitI(0x38, base, rt, imm16);
496}
497
498void 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
504void 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
510void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
511  EmitR(0, rs, rt, rd, 0, 0x2a);
512}
513
514void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
515  EmitR(0, rs, rt, rd, 0, 0x2b);
516}
517
518void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
519  EmitI(0xa, rs, rt, imm16);
520}
521
522void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
523  EmitI(0xb, rs, rt, imm16);
524}
525
526void MipsAssembler::B(uint16_t imm16) {
527  EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
528}
529
530void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
531  EmitI(0x4, rs, rt, imm16);
532}
533
534void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
535  EmitI(0x5, rs, rt, imm16);
536}
537
538void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
539  Beq(ZERO, rt, imm16);
540}
541
542void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
543  Bne(ZERO, rt, imm16);
544}
545
546void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
547  EmitI(0x1, rt, static_cast<Register>(0), imm16);
548}
549
550void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
551  EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
552}
553
554void MipsAssembler::Blez(Register rt, uint16_t imm16) {
555  EmitI(0x6, rt, static_cast<Register>(0), imm16);
556}
557
558void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
559  EmitI(0x7, rt, static_cast<Register>(0), imm16);
560}
561
562void MipsAssembler::Bc1f(uint16_t imm16) {
563  Bc1f(0, imm16);
564}
565
566void 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
572void MipsAssembler::Bc1t(uint16_t imm16) {
573  Bc1t(0, imm16);
574}
575
576void 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
582void MipsAssembler::J(uint32_t addr26) {
583  EmitI26(0x2, addr26);
584}
585
586void MipsAssembler::Jal(uint32_t addr26) {
587  EmitI26(0x3, addr26);
588}
589
590void MipsAssembler::Jalr(Register rd, Register rs) {
591  EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
592}
593
594void MipsAssembler::Jalr(Register rs) {
595  Jalr(RA, rs);
596}
597
598void MipsAssembler::Jr(Register rs) {
599  Jalr(ZERO, rs);
600}
601
602void MipsAssembler::Nal() {
603  EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
604}
605
606void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
607  CHECK(IsR6());
608  EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
609}
610
611void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
612  CHECK(IsR6());
613  CHECK(IsUint<19>(imm19)) << imm19;
614  EmitI21(0x3B, rs, imm19);
615}
616
617void MipsAssembler::Bc(uint32_t imm26) {
618  CHECK(IsR6());
619  EmitI26(0x32, imm26);
620}
621
622void MipsAssembler::Jic(Register rt, uint16_t imm16) {
623  CHECK(IsR6());
624  EmitI(0x36, static_cast<Register>(0), rt, imm16);
625}
626
627void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
628  CHECK(IsR6());
629  EmitI(0x3E, static_cast<Register>(0), rt, imm16);
630}
631
632void 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
640void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
641  CHECK(IsR6());
642  CHECK_NE(rt, ZERO);
643  EmitI(0x17, rt, rt, imm16);
644}
645
646void 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
652void 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
660void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
661  CHECK(IsR6());
662  CHECK_NE(rt, ZERO);
663  EmitI(0x16, rt, rt, imm16);
664}
665
666void 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
672void 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
680void 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
688void 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
696void 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
704void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
705  CHECK(IsR6());
706  CHECK_NE(rs, ZERO);
707  EmitI21(0x36, rs, imm21);
708}
709
710void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
711  CHECK(IsR6());
712  CHECK_NE(rs, ZERO);
713  EmitI21(0x3E, rs, imm21);
714}
715
716void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
717  CHECK(IsR6());
718  EmitFI(0x11, 0x9, ft, imm16);
719}
720
721void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
722  CHECK(IsR6());
723  EmitFI(0x11, 0xD, ft, imm16);
724}
725
726void 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
780void 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
844void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
845  EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
846}
847
848void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
849  EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
850}
851
852void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
853  EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
854}
855
856void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
857  EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
858}
859
860void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
861  EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
862}
863
864void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
865  EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
866}
867
868void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
869  EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
870}
871
872void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
873  EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
874}
875
876void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
877  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4);
878}
879
880void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
881  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4);
882}
883
884void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
885  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5);
886}
887
888void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
889  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5);
890}
891
892void MipsAssembler::MovS(FRegister fd, FRegister fs) {
893  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
894}
895
896void MipsAssembler::MovD(FRegister fd, FRegister fs) {
897  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
898}
899
900void MipsAssembler::NegS(FRegister fd, FRegister fs) {
901  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
902}
903
904void MipsAssembler::NegD(FRegister fd, FRegister fs) {
905  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
906}
907
908void MipsAssembler::CunS(FRegister fs, FRegister ft) {
909  CunS(0, fs, ft);
910}
911
912void 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
918void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
919  CeqS(0, fs, ft);
920}
921
922void 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
928void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
929  CueqS(0, fs, ft);
930}
931
932void 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
938void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
939  ColtS(0, fs, ft);
940}
941
942void 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
948void MipsAssembler::CultS(FRegister fs, FRegister ft) {
949  CultS(0, fs, ft);
950}
951
952void 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
958void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
959  ColeS(0, fs, ft);
960}
961
962void 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
968void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
969  CuleS(0, fs, ft);
970}
971
972void 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
978void MipsAssembler::CunD(FRegister fs, FRegister ft) {
979  CunD(0, fs, ft);
980}
981
982void 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
988void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
989  CeqD(0, fs, ft);
990}
991
992void 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
998void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
999  CueqD(0, fs, ft);
1000}
1001
1002void 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
1008void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1009  ColtD(0, fs, ft);
1010}
1011
1012void 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
1018void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1019  CultD(0, fs, ft);
1020}
1021
1022void 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
1028void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1029  ColeD(0, fs, ft);
1030}
1031
1032void 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
1038void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1039  CuleD(0, fs, ft);
1040}
1041
1042void 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
1048void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1049  CHECK(IsR6());
1050  EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1051}
1052
1053void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1054  CHECK(IsR6());
1055  EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1056}
1057
1058void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1059  CHECK(IsR6());
1060  EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1061}
1062
1063void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1064  CHECK(IsR6());
1065  EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1066}
1067
1068void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1069  CHECK(IsR6());
1070  EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1071}
1072
1073void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1074  CHECK(IsR6());
1075  EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1076}
1077
1078void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1079  CHECK(IsR6());
1080  EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1081}
1082
1083void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1084  CHECK(IsR6());
1085  EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1086}
1087
1088void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1089  CHECK(IsR6());
1090  EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1091}
1092
1093void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1094  CHECK(IsR6());
1095  EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1096}
1097
1098void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1099  CHECK(IsR6());
1100  EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1101}
1102
1103void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1104  CHECK(IsR6());
1105  EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1106}
1107
1108void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1109  CHECK(IsR6());
1110  EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1111}
1112
1113void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1114  CHECK(IsR6());
1115  EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1116}
1117
1118void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1119  CHECK(IsR6());
1120  EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1121}
1122
1123void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1124  CHECK(IsR6());
1125  EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1126}
1127
1128void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1129  CHECK(IsR6());
1130  EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1131}
1132
1133void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1134  CHECK(IsR6());
1135  EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1136}
1137
1138void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1139  CHECK(IsR6());
1140  EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1141}
1142
1143void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1144  CHECK(IsR6());
1145  EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1146}
1147
1148void 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
1154void 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
1160void 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
1166void 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
1172void 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
1178void 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
1184void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1185  CHECK(IsR6());
1186  EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
1187}
1188
1189void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1190  CHECK(IsR6());
1191  EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1192}
1193
1194void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1195  CHECK(IsR6());
1196  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b);
1197}
1198
1199void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1200  CHECK(IsR6());
1201  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b);
1202}
1203
1204void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1205  CHECK(IsR6());
1206  EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1207}
1208
1209void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1210  CHECK(IsR6());
1211  EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1212}
1213
1214void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1215  CHECK(IsR6());
1216  EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1217}
1218
1219void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1220  CHECK(IsR6());
1221  EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1222}
1223
1224void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1225  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1226}
1227
1228void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1229  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1230}
1231
1232void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1233  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1234}
1235
1236void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1237  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1238}
1239
1240void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1241  EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1242}
1243
1244void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1245  EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1246}
1247
1248void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1249  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1250}
1251
1252void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1253  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
1254}
1255
1256void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1257  EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1258}
1259
1260void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1261  EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1262}
1263
1264void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1265  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf);
1266}
1267
1268void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1269  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf);
1270}
1271
1272void MipsAssembler::Mfc1(Register rt, FRegister fs) {
1273  EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1274}
1275
1276void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1277  EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1278}
1279
1280void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1281  EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1282}
1283
1284void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1285  EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1286}
1287
1288void 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
1297void 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
1306void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
1307  EmitI(0x31, rs, static_cast<Register>(ft), imm16);
1308}
1309
1310void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1311  EmitI(0x35, rs, static_cast<Register>(ft), imm16);
1312}
1313
1314void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
1315  EmitI(0x39, rs, static_cast<Register>(ft), imm16);
1316}
1317
1318void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1319  EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
1320}
1321
1322void MipsAssembler::Break() {
1323  EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1324        static_cast<Register>(0), 0, 0xD);
1325}
1326
1327void MipsAssembler::Nop() {
1328  EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1329}
1330
1331void MipsAssembler::Move(Register rd, Register rs) {
1332  Or(rd, rs, ZERO);
1333}
1334
1335void MipsAssembler::Clear(Register rd) {
1336  Move(rd, ZERO);
1337}
1338
1339void MipsAssembler::Not(Register rd, Register rs) {
1340  Nor(rd, rs, ZERO);
1341}
1342
1343void MipsAssembler::Push(Register rs) {
1344  IncreaseFrameSize(kMipsWordSize);
1345  Sw(rs, SP, 0);
1346}
1347
1348void MipsAssembler::Pop(Register rd) {
1349  Lw(rd, SP, 0);
1350  DecreaseFrameSize(kMipsWordSize);
1351}
1352
1353void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1354  Lw(rd, SP, 0);
1355  Jr(rt);
1356  DecreaseFrameSize(kMipsWordSize);
1357}
1358
1359void 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
1373void 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
1384void 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
1403void 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
1433void 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
1442void 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
1459void 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
1468void 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
1474void 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
1503bool 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
1515bool 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
1529MipsAssembler::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
1539MipsAssembler::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
1596MipsAssembler::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
1608MipsAssembler::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
1649MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1650  return type_;
1651}
1652
1653MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1654  return condition_;
1655}
1656
1657Register MipsAssembler::Branch::GetLeftRegister() const {
1658  return static_cast<Register>(lhs_reg_);
1659}
1660
1661Register MipsAssembler::Branch::GetRightRegister() const {
1662  return static_cast<Register>(rhs_reg_);
1663}
1664
1665uint32_t MipsAssembler::Branch::GetTarget() const {
1666  return target_;
1667}
1668
1669uint32_t MipsAssembler::Branch::GetLocation() const {
1670  return location_;
1671}
1672
1673uint32_t MipsAssembler::Branch::GetOldLocation() const {
1674  return old_location_;
1675}
1676
1677uint32_t MipsAssembler::Branch::GetLength() const {
1678  return branch_info_[type_].length;
1679}
1680
1681uint32_t MipsAssembler::Branch::GetOldLength() const {
1682  return branch_info_[old_type_].length;
1683}
1684
1685uint32_t MipsAssembler::Branch::GetSize() const {
1686  return GetLength() * sizeof(uint32_t);
1687}
1688
1689uint32_t MipsAssembler::Branch::GetOldSize() const {
1690  return GetOldLength() * sizeof(uint32_t);
1691}
1692
1693uint32_t MipsAssembler::Branch::GetEndLocation() const {
1694  return GetLocation() + GetSize();
1695}
1696
1697uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1698  return GetOldLocation() + GetOldSize();
1699}
1700
1701bool 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
1725bool MipsAssembler::Branch::IsResolved() const {
1726  return target_ != kUnresolved;
1727}
1728
1729MipsAssembler::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
1737MipsAssembler::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
1760void MipsAssembler::Branch::Resolve(uint32_t target) {
1761  target_ = target;
1762}
1763
1764void 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
1776void 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
1805uint32_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
1835uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1836  return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1837}
1838
1839uint32_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
1850MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1851  CHECK_LT(branch_id, branches_.size());
1852  return &branches_[branch_id];
1853}
1854
1855const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1856  CHECK_LT(branch_id, branches_.size());
1857  return &branches_[branch_id];
1858}
1859
1860void 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
1891uint32_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
1903uint32_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
1926void 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
1945void 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
1951void 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
1961void 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
1967void 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.
2008const 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.
2029void 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
2155void MipsAssembler::B(MipsLabel* label) {
2156  Buncond(label);
2157}
2158
2159void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
2160  Call(label, indirect_reg);
2161}
2162
2163void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
2164  Bcond(label, kCondEQ, rs, rt);
2165}
2166
2167void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
2168  Bcond(label, kCondNE, rs, rt);
2169}
2170
2171void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
2172  Bcond(label, kCondEQZ, rt);
2173}
2174
2175void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2176  Bcond(label, kCondNEZ, rt);
2177}
2178
2179void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2180  Bcond(label, kCondLTZ, rt);
2181}
2182
2183void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2184  Bcond(label, kCondGEZ, rt);
2185}
2186
2187void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2188  Bcond(label, kCondLEZ, rt);
2189}
2190
2191void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2192  Bcond(label, kCondGTZ, rt);
2193}
2194
2195void 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
2205void 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
2217void 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
2227void 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
2239void MipsAssembler::Bc1f(MipsLabel* label) {
2240  Bc1f(0, label);
2241}
2242
2243void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2244  CHECK(IsUint<3>(cc)) << cc;
2245  Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2246}
2247
2248void MipsAssembler::Bc1t(MipsLabel* label) {
2249  Bc1t(0, label);
2250}
2251
2252void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2253  CHECK(IsUint<3>(cc)) << cc;
2254  Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2255}
2256
2257void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2258  Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2259}
2260
2261void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2262  Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2263}
2264
2265void 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
2308void 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
2319void 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
2345void 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
2366void 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
2398void 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
2409void 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
2435static dwarf::Reg DWARFReg(Register reg) {
2436  return dwarf::Reg::MipsCore(static_cast<int>(reg));
2437}
2438
2439constexpr size_t kFramePointerSize = 4;
2440
2441void 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
2484void 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
2513void 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
2522void 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
2531void 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
2553void 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
2559void 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
2565void 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
2573void 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
2582void 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
2592void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
2593  StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2594}
2595
2596void 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
2605void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2606  return EmitLoad(mdest, SP, src.Int32Value(), size);
2607}
2608
2609void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2610                                     ThreadOffset<kMipsWordSize> src, size_t size) {
2611  return EmitLoad(mdest, S1, src.Int32Value(), size);
2612}
2613
2614void 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
2620void 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
2631void 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
2638void 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
2645void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2646  UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2647}
2648
2649void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2650  UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2651}
2652
2653void 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
2686void 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
2693void 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
2704void 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
2715void 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
2730void 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
2738void 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
2746void 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
2754void 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
2763void 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
2772void MipsAssembler::MemoryBarrier(ManagedRegister) {
2773  // TODO: sync?
2774  UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2775}
2776
2777void 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
2806void 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.
2828void 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
2844void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2845                                 bool could_be_null ATTRIBUTE_UNUSED) {
2846  // TODO: not validating references.
2847}
2848
2849void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2850                                 bool could_be_null ATTRIBUTE_UNUSED) {
2851  // TODO: not validating references.
2852}
2853
2854void 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
2866void 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
2878void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2879                                     ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2880  UNIMPLEMENTED(FATAL) << "no mips implementation";
2881}
2882
2883void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2884  Move(tr.AsMips().AsCoreRegister(), S1);
2885}
2886
2887void MipsAssembler::GetCurrentThread(FrameOffset offset,
2888                                     ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2889  StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2890}
2891
2892void 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
2903void 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