assembler_mips.cc revision 3acee732f9475fbfc6b046e0044b764e7ff5ac01
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::Slt(Register rd, Register rs, Register rt) {
489  EmitR(0, rs, rt, rd, 0, 0x2a);
490}
491
492void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
493  EmitR(0, rs, rt, rd, 0, 0x2b);
494}
495
496void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
497  EmitI(0xa, rs, rt, imm16);
498}
499
500void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
501  EmitI(0xb, rs, rt, imm16);
502}
503
504void MipsAssembler::B(uint16_t imm16) {
505  EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
506}
507
508void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
509  EmitI(0x4, rs, rt, imm16);
510}
511
512void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
513  EmitI(0x5, rs, rt, imm16);
514}
515
516void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
517  Beq(ZERO, rt, imm16);
518}
519
520void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
521  Bne(ZERO, rt, imm16);
522}
523
524void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
525  EmitI(0x1, rt, static_cast<Register>(0), imm16);
526}
527
528void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
529  EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
530}
531
532void MipsAssembler::Blez(Register rt, uint16_t imm16) {
533  EmitI(0x6, rt, static_cast<Register>(0), imm16);
534}
535
536void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
537  EmitI(0x7, rt, static_cast<Register>(0), imm16);
538}
539
540void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
541  CHECK(!IsR6());
542  CHECK(IsUint<3>(cc)) << cc;
543  EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16);
544}
545
546void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
547  CHECK(!IsR6());
548  CHECK(IsUint<3>(cc)) << cc;
549  EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16);
550}
551
552void MipsAssembler::J(uint32_t addr26) {
553  EmitI26(0x2, addr26);
554}
555
556void MipsAssembler::Jal(uint32_t addr26) {
557  EmitI26(0x3, addr26);
558}
559
560void MipsAssembler::Jalr(Register rd, Register rs) {
561  EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
562}
563
564void MipsAssembler::Jalr(Register rs) {
565  Jalr(RA, rs);
566}
567
568void MipsAssembler::Jr(Register rs) {
569  Jalr(ZERO, rs);
570}
571
572void MipsAssembler::Nal() {
573  EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
574}
575
576void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
577  CHECK(IsR6());
578  EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
579}
580
581void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
582  CHECK(IsR6());
583  CHECK(IsUint<19>(imm19)) << imm19;
584  EmitI21(0x3B, rs, imm19);
585}
586
587void MipsAssembler::Bc(uint32_t imm26) {
588  CHECK(IsR6());
589  EmitI26(0x32, imm26);
590}
591
592void MipsAssembler::Jic(Register rt, uint16_t imm16) {
593  CHECK(IsR6());
594  EmitI(0x36, static_cast<Register>(0), rt, imm16);
595}
596
597void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
598  CHECK(IsR6());
599  EmitI(0x3E, static_cast<Register>(0), rt, imm16);
600}
601
602void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
603  CHECK(IsR6());
604  CHECK_NE(rs, ZERO);
605  CHECK_NE(rt, ZERO);
606  CHECK_NE(rs, rt);
607  EmitI(0x17, rs, rt, imm16);
608}
609
610void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
611  CHECK(IsR6());
612  CHECK_NE(rt, ZERO);
613  EmitI(0x17, rt, rt, imm16);
614}
615
616void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
617  CHECK(IsR6());
618  CHECK_NE(rt, ZERO);
619  EmitI(0x17, static_cast<Register>(0), rt, imm16);
620}
621
622void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
623  CHECK(IsR6());
624  CHECK_NE(rs, ZERO);
625  CHECK_NE(rt, ZERO);
626  CHECK_NE(rs, rt);
627  EmitI(0x16, rs, rt, imm16);
628}
629
630void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
631  CHECK(IsR6());
632  CHECK_NE(rt, ZERO);
633  EmitI(0x16, rt, rt, imm16);
634}
635
636void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
637  CHECK(IsR6());
638  CHECK_NE(rt, ZERO);
639  EmitI(0x16, static_cast<Register>(0), rt, imm16);
640}
641
642void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
643  CHECK(IsR6());
644  CHECK_NE(rs, ZERO);
645  CHECK_NE(rt, ZERO);
646  CHECK_NE(rs, rt);
647  EmitI(0x7, rs, rt, imm16);
648}
649
650void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
651  CHECK(IsR6());
652  CHECK_NE(rs, ZERO);
653  CHECK_NE(rt, ZERO);
654  CHECK_NE(rs, rt);
655  EmitI(0x6, rs, rt, imm16);
656}
657
658void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
659  CHECK(IsR6());
660  CHECK_NE(rs, ZERO);
661  CHECK_NE(rt, ZERO);
662  CHECK_NE(rs, rt);
663  EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
664}
665
666void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
667  CHECK(IsR6());
668  CHECK_NE(rs, ZERO);
669  CHECK_NE(rt, ZERO);
670  CHECK_NE(rs, rt);
671  EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
672}
673
674void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
675  CHECK(IsR6());
676  CHECK_NE(rs, ZERO);
677  EmitI21(0x36, rs, imm21);
678}
679
680void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
681  CHECK(IsR6());
682  CHECK_NE(rs, ZERO);
683  EmitI21(0x3E, rs, imm21);
684}
685
686void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
687  CHECK(IsR6());
688  EmitFI(0x11, 0x9, ft, imm16);
689}
690
691void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
692  CHECK(IsR6());
693  EmitFI(0x11, 0xD, ft, imm16);
694}
695
696void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
697  switch (cond) {
698    case kCondLTZ:
699      CHECK_EQ(rt, ZERO);
700      Bltz(rs, imm16);
701      break;
702    case kCondGEZ:
703      CHECK_EQ(rt, ZERO);
704      Bgez(rs, imm16);
705      break;
706    case kCondLEZ:
707      CHECK_EQ(rt, ZERO);
708      Blez(rs, imm16);
709      break;
710    case kCondGTZ:
711      CHECK_EQ(rt, ZERO);
712      Bgtz(rs, imm16);
713      break;
714    case kCondEQ:
715      Beq(rs, rt, imm16);
716      break;
717    case kCondNE:
718      Bne(rs, rt, imm16);
719      break;
720    case kCondEQZ:
721      CHECK_EQ(rt, ZERO);
722      Beqz(rs, imm16);
723      break;
724    case kCondNEZ:
725      CHECK_EQ(rt, ZERO);
726      Bnez(rs, imm16);
727      break;
728    case kCondF:
729      CHECK_EQ(rt, ZERO);
730      Bc1f(static_cast<int>(rs), imm16);
731      break;
732    case kCondT:
733      CHECK_EQ(rt, ZERO);
734      Bc1t(static_cast<int>(rs), imm16);
735      break;
736    case kCondLT:
737    case kCondGE:
738    case kCondLE:
739    case kCondGT:
740    case kCondLTU:
741    case kCondGEU:
742    case kUncond:
743      // We don't support synthetic R2 branches (preceded with slt[u]) at this level
744      // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
745      LOG(FATAL) << "Unexpected branch condition " << cond;
746      UNREACHABLE();
747  }
748}
749
750void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
751  switch (cond) {
752    case kCondLT:
753      Bltc(rs, rt, imm16_21);
754      break;
755    case kCondGE:
756      Bgec(rs, rt, imm16_21);
757      break;
758    case kCondLE:
759      Bgec(rt, rs, imm16_21);
760      break;
761    case kCondGT:
762      Bltc(rt, rs, imm16_21);
763      break;
764    case kCondLTZ:
765      CHECK_EQ(rt, ZERO);
766      Bltzc(rs, imm16_21);
767      break;
768    case kCondGEZ:
769      CHECK_EQ(rt, ZERO);
770      Bgezc(rs, imm16_21);
771      break;
772    case kCondLEZ:
773      CHECK_EQ(rt, ZERO);
774      Blezc(rs, imm16_21);
775      break;
776    case kCondGTZ:
777      CHECK_EQ(rt, ZERO);
778      Bgtzc(rs, imm16_21);
779      break;
780    case kCondEQ:
781      Beqc(rs, rt, imm16_21);
782      break;
783    case kCondNE:
784      Bnec(rs, rt, imm16_21);
785      break;
786    case kCondEQZ:
787      CHECK_EQ(rt, ZERO);
788      Beqzc(rs, imm16_21);
789      break;
790    case kCondNEZ:
791      CHECK_EQ(rt, ZERO);
792      Bnezc(rs, imm16_21);
793      break;
794    case kCondLTU:
795      Bltuc(rs, rt, imm16_21);
796      break;
797    case kCondGEU:
798      Bgeuc(rs, rt, imm16_21);
799      break;
800    case kCondF:
801      CHECK_EQ(rt, ZERO);
802      Bc1eqz(static_cast<FRegister>(rs), imm16_21);
803      break;
804    case kCondT:
805      CHECK_EQ(rt, ZERO);
806      Bc1nez(static_cast<FRegister>(rs), imm16_21);
807      break;
808    case kUncond:
809      LOG(FATAL) << "Unexpected branch condition " << cond;
810      UNREACHABLE();
811  }
812}
813
814void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
815  EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
816}
817
818void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
819  EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
820}
821
822void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
823  EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
824}
825
826void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
827  EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
828}
829
830void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
831  EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
832}
833
834void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
835  EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
836}
837
838void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
839  EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
840}
841
842void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
843  EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
844}
845
846void MipsAssembler::MovS(FRegister fd, FRegister fs) {
847  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
848}
849
850void MipsAssembler::MovD(FRegister fd, FRegister fs) {
851  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
852}
853
854void MipsAssembler::NegS(FRegister fd, FRegister fs) {
855  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
856}
857
858void MipsAssembler::NegD(FRegister fd, FRegister fs) {
859  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
860}
861
862void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
863  CHECK(!IsR6());
864  CHECK(IsUint<3>(cc)) << cc;
865  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
866}
867
868void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
869  CHECK(!IsR6());
870  CHECK(IsUint<3>(cc)) << cc;
871  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
872}
873
874void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
875  CHECK(!IsR6());
876  CHECK(IsUint<3>(cc)) << cc;
877  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
878}
879
880void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
881  CHECK(!IsR6());
882  CHECK(IsUint<3>(cc)) << cc;
883  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
884}
885
886void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
887  CHECK(!IsR6());
888  CHECK(IsUint<3>(cc)) << cc;
889  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
890}
891
892void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
893  CHECK(!IsR6());
894  CHECK(IsUint<3>(cc)) << cc;
895  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
896}
897
898void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
899  CHECK(!IsR6());
900  CHECK(IsUint<3>(cc)) << cc;
901  EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
902}
903
904void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
905  CHECK(!IsR6());
906  CHECK(IsUint<3>(cc)) << cc;
907  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
908}
909
910void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
911  CHECK(!IsR6());
912  CHECK(IsUint<3>(cc)) << cc;
913  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
914}
915
916void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
917  CHECK(!IsR6());
918  CHECK(IsUint<3>(cc)) << cc;
919  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
920}
921
922void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
923  CHECK(!IsR6());
924  CHECK(IsUint<3>(cc)) << cc;
925  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
926}
927
928void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
929  CHECK(!IsR6());
930  CHECK(IsUint<3>(cc)) << cc;
931  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
932}
933
934void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
935  CHECK(!IsR6());
936  CHECK(IsUint<3>(cc)) << cc;
937  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
938}
939
940void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
941  CHECK(!IsR6());
942  CHECK(IsUint<3>(cc)) << cc;
943  EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
944}
945
946void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
947  CHECK(IsR6());
948  EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
949}
950
951void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
952  CHECK(IsR6());
953  EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
954}
955
956void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
957  CHECK(IsR6());
958  EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
959}
960
961void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
962  CHECK(IsR6());
963  EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
964}
965
966void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
967  CHECK(IsR6());
968  EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
969}
970
971void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
972  CHECK(IsR6());
973  EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
974}
975
976void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
977  CHECK(IsR6());
978  EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
979}
980
981void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
982  CHECK(IsR6());
983  EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
984}
985
986void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
987  CHECK(IsR6());
988  EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
989}
990
991void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
992  CHECK(IsR6());
993  EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
994}
995
996void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
997  CHECK(IsR6());
998  EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
999}
1000
1001void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1002  CHECK(IsR6());
1003  EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1004}
1005
1006void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1007  CHECK(IsR6());
1008  EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1009}
1010
1011void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1012  CHECK(IsR6());
1013  EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1014}
1015
1016void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1017  CHECK(IsR6());
1018  EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1019}
1020
1021void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1022  CHECK(IsR6());
1023  EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1024}
1025
1026void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1027  CHECK(IsR6());
1028  EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1029}
1030
1031void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1032  CHECK(IsR6());
1033  EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1034}
1035
1036void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1037  CHECK(IsR6());
1038  EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1039}
1040
1041void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1042  CHECK(IsR6());
1043  EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1044}
1045
1046void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1047  CHECK(!IsR6());
1048  CHECK(IsUint<3>(cc)) << cc;
1049  EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01);
1050}
1051
1052void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1053  CHECK(!IsR6());
1054  CHECK(IsUint<3>(cc)) << cc;
1055  EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01);
1056}
1057
1058void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1059  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1060}
1061
1062void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1063  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1064}
1065
1066void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1067  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1068}
1069
1070void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1071  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1072}
1073
1074void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1075  EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1076}
1077
1078void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1079  EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1080}
1081
1082void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1083  EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1084}
1085
1086void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1087  EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
1088}
1089
1090void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1091  EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1092}
1093
1094void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1095  EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1096}
1097
1098void MipsAssembler::Mfc1(Register rt, FRegister fs) {
1099  EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1100}
1101
1102void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1103  EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1104}
1105
1106void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1107  EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1108}
1109
1110void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1111  EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1112}
1113
1114void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1115  if (Is32BitFPU()) {
1116    CHECK_EQ(fs % 2, 0) << fs;
1117    Mfc1(rt, static_cast<FRegister>(fs + 1));
1118  } else {
1119    Mfhc1(rt, fs);
1120  }
1121}
1122
1123void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1124  if (Is32BitFPU()) {
1125    CHECK_EQ(fs % 2, 0) << fs;
1126    Mtc1(rt, static_cast<FRegister>(fs + 1));
1127  } else {
1128    Mthc1(rt, fs);
1129  }
1130}
1131
1132void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
1133  EmitI(0x31, rs, static_cast<Register>(ft), imm16);
1134}
1135
1136void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1137  EmitI(0x35, rs, static_cast<Register>(ft), imm16);
1138}
1139
1140void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
1141  EmitI(0x39, rs, static_cast<Register>(ft), imm16);
1142}
1143
1144void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1145  EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
1146}
1147
1148void MipsAssembler::Break() {
1149  EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1150        static_cast<Register>(0), 0, 0xD);
1151}
1152
1153void MipsAssembler::Nop() {
1154  EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1155}
1156
1157void MipsAssembler::Move(Register rd, Register rs) {
1158  Or(rd, rs, ZERO);
1159}
1160
1161void MipsAssembler::Clear(Register rd) {
1162  Move(rd, ZERO);
1163}
1164
1165void MipsAssembler::Not(Register rd, Register rs) {
1166  Nor(rd, rs, ZERO);
1167}
1168
1169void MipsAssembler::Push(Register rs) {
1170  IncreaseFrameSize(kMipsWordSize);
1171  Sw(rs, SP, 0);
1172}
1173
1174void MipsAssembler::Pop(Register rd) {
1175  Lw(rd, SP, 0);
1176  DecreaseFrameSize(kMipsWordSize);
1177}
1178
1179void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1180  Lw(rd, SP, 0);
1181  Jr(rt);
1182  DecreaseFrameSize(kMipsWordSize);
1183}
1184
1185void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1186  if (IsUint<16>(value)) {
1187    // Use OR with (unsigned) immediate to encode 16b unsigned int.
1188    Ori(rd, ZERO, value);
1189  } else if (IsInt<16>(value)) {
1190    // Use ADD with (signed) immediate to encode 16b signed int.
1191    Addiu(rd, ZERO, value);
1192  } else {
1193    Lui(rd, High16Bits(value));
1194    if (value & 0xFFFF)
1195      Ori(rd, rd, Low16Bits(value));
1196  }
1197}
1198
1199void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
1200  uint32_t low = Low32Bits(value);
1201  uint32_t high = High32Bits(value);
1202  LoadConst32(reg_lo, low);
1203  if (high != low) {
1204    LoadConst32(reg_hi, high);
1205  } else {
1206    Move(reg_hi, reg_lo);
1207  }
1208}
1209
1210void MipsAssembler::StoreConst32ToOffset(int32_t value,
1211                                         Register base,
1212                                         int32_t offset,
1213                                         Register temp) {
1214  if (!IsInt<16>(offset)) {
1215    CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
1216    LoadConst32(AT, offset);
1217    Addu(AT, AT, base);
1218    base = AT;
1219    offset = 0;
1220  }
1221  if (value == 0) {
1222    temp = ZERO;
1223  } else {
1224    LoadConst32(temp, value);
1225  }
1226  Sw(temp, base, offset);
1227}
1228
1229void MipsAssembler::StoreConst64ToOffset(int64_t value,
1230                                         Register base,
1231                                         int32_t offset,
1232                                         Register temp) {
1233  // IsInt<16> must be passed a signed value.
1234  if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
1235    CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
1236    LoadConst32(AT, offset);
1237    Addu(AT, AT, base);
1238    base = AT;
1239    offset = 0;
1240  }
1241  uint32_t low = Low32Bits(value);
1242  uint32_t high = High32Bits(value);
1243  if (low == 0) {
1244    Sw(ZERO, base, offset);
1245  } else {
1246    LoadConst32(temp, low);
1247    Sw(temp, base, offset);
1248  }
1249  if (high == 0) {
1250    Sw(ZERO, base, offset + kMipsWordSize);
1251  } else {
1252    if (high != low) {
1253      LoadConst32(temp, high);
1254    }
1255    Sw(temp, base, offset + kMipsWordSize);
1256  }
1257}
1258
1259void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
1260  if (value == 0) {
1261    temp = ZERO;
1262  } else {
1263    LoadConst32(temp, value);
1264  }
1265  Mtc1(temp, r);
1266}
1267
1268void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
1269  uint32_t low = Low32Bits(value);
1270  uint32_t high = High32Bits(value);
1271  if (low == 0) {
1272    Mtc1(ZERO, rd);
1273  } else {
1274    LoadConst32(temp, low);
1275    Mtc1(temp, rd);
1276  }
1277  if (high == 0) {
1278    MoveToFpuHigh(ZERO, rd);
1279  } else {
1280    LoadConst32(temp, high);
1281    MoveToFpuHigh(temp, rd);
1282  }
1283}
1284
1285void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1286  if (IsInt<16>(value)) {
1287    Addiu(rt, rs, value);
1288  } else {
1289    LoadConst32(temp, value);
1290    Addu(rt, rs, temp);
1291  }
1292}
1293
1294void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1295                                            MipsAssembler::Branch::Type short_type,
1296                                            MipsAssembler::Branch::Type long_type) {
1297  type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1298}
1299
1300void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
1301  OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1302  if (is_r6) {
1303    // R6
1304    if (is_call) {
1305      InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1306    } else if (condition_ == kUncond) {
1307      InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1308    } else {
1309      if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1310        // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1311        type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1312      } else {
1313        InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1314      }
1315    }
1316  } else {
1317    // R2
1318    if (is_call) {
1319      InitShortOrLong(offset_size, kCall, kLongCall);
1320    } else if (condition_ == kUncond) {
1321      InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1322    } else {
1323      InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1324    }
1325  }
1326  old_type_ = type_;
1327}
1328
1329bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1330  switch (condition) {
1331    case kCondLT:
1332    case kCondGT:
1333    case kCondNE:
1334    case kCondLTU:
1335      return lhs == rhs;
1336    default:
1337      return false;
1338  }
1339}
1340
1341bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1342  switch (condition) {
1343    case kUncond:
1344      return true;
1345    case kCondGE:
1346    case kCondLE:
1347    case kCondEQ:
1348    case kCondGEU:
1349      return lhs == rhs;
1350    default:
1351      return false;
1352  }
1353}
1354
1355MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
1356    : old_location_(location),
1357      location_(location),
1358      target_(target),
1359      lhs_reg_(0),
1360      rhs_reg_(0),
1361      condition_(kUncond) {
1362  InitializeType(false, is_r6);
1363}
1364
1365MipsAssembler::Branch::Branch(bool is_r6,
1366                              uint32_t location,
1367                              uint32_t target,
1368                              MipsAssembler::BranchCondition condition,
1369                              Register lhs_reg,
1370                              Register rhs_reg)
1371    : old_location_(location),
1372      location_(location),
1373      target_(target),
1374      lhs_reg_(lhs_reg),
1375      rhs_reg_(rhs_reg),
1376      condition_(condition) {
1377  CHECK_NE(condition, kUncond);
1378  switch (condition) {
1379    case kCondLT:
1380    case kCondGE:
1381    case kCondLE:
1382    case kCondGT:
1383    case kCondLTU:
1384    case kCondGEU:
1385      // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1386      // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1387      // We leave this up to the caller.
1388      CHECK(is_r6);
1389      FALLTHROUGH_INTENDED;
1390    case kCondEQ:
1391    case kCondNE:
1392      // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1393      // To compare with 0, use dedicated kCond*Z conditions.
1394      CHECK_NE(lhs_reg, ZERO);
1395      CHECK_NE(rhs_reg, ZERO);
1396      break;
1397    case kCondLTZ:
1398    case kCondGEZ:
1399    case kCondLEZ:
1400    case kCondGTZ:
1401    case kCondEQZ:
1402    case kCondNEZ:
1403      // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1404      CHECK_NE(lhs_reg, ZERO);
1405      CHECK_EQ(rhs_reg, ZERO);
1406      break;
1407    case kCondF:
1408    case kCondT:
1409      CHECK_EQ(rhs_reg, ZERO);
1410      break;
1411    case kUncond:
1412      UNREACHABLE();
1413  }
1414  CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1415  if (IsUncond(condition, lhs_reg, rhs_reg)) {
1416    // Branch condition is always true, make the branch unconditional.
1417    condition_ = kUncond;
1418  }
1419  InitializeType(false, is_r6);
1420}
1421
1422MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
1423    : old_location_(location),
1424      location_(location),
1425      target_(target),
1426      lhs_reg_(indirect_reg),
1427      rhs_reg_(0),
1428      condition_(kUncond) {
1429  CHECK_NE(indirect_reg, ZERO);
1430  CHECK_NE(indirect_reg, AT);
1431  InitializeType(true, is_r6);
1432}
1433
1434MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1435    MipsAssembler::BranchCondition cond) {
1436  switch (cond) {
1437    case kCondLT:
1438      return kCondGE;
1439    case kCondGE:
1440      return kCondLT;
1441    case kCondLE:
1442      return kCondGT;
1443    case kCondGT:
1444      return kCondLE;
1445    case kCondLTZ:
1446      return kCondGEZ;
1447    case kCondGEZ:
1448      return kCondLTZ;
1449    case kCondLEZ:
1450      return kCondGTZ;
1451    case kCondGTZ:
1452      return kCondLEZ;
1453    case kCondEQ:
1454      return kCondNE;
1455    case kCondNE:
1456      return kCondEQ;
1457    case kCondEQZ:
1458      return kCondNEZ;
1459    case kCondNEZ:
1460      return kCondEQZ;
1461    case kCondLTU:
1462      return kCondGEU;
1463    case kCondGEU:
1464      return kCondLTU;
1465    case kCondF:
1466      return kCondT;
1467    case kCondT:
1468      return kCondF;
1469    case kUncond:
1470      LOG(FATAL) << "Unexpected branch condition " << cond;
1471  }
1472  UNREACHABLE();
1473}
1474
1475MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1476  return type_;
1477}
1478
1479MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1480  return condition_;
1481}
1482
1483Register MipsAssembler::Branch::GetLeftRegister() const {
1484  return static_cast<Register>(lhs_reg_);
1485}
1486
1487Register MipsAssembler::Branch::GetRightRegister() const {
1488  return static_cast<Register>(rhs_reg_);
1489}
1490
1491uint32_t MipsAssembler::Branch::GetTarget() const {
1492  return target_;
1493}
1494
1495uint32_t MipsAssembler::Branch::GetLocation() const {
1496  return location_;
1497}
1498
1499uint32_t MipsAssembler::Branch::GetOldLocation() const {
1500  return old_location_;
1501}
1502
1503uint32_t MipsAssembler::Branch::GetLength() const {
1504  return branch_info_[type_].length;
1505}
1506
1507uint32_t MipsAssembler::Branch::GetOldLength() const {
1508  return branch_info_[old_type_].length;
1509}
1510
1511uint32_t MipsAssembler::Branch::GetSize() const {
1512  return GetLength() * sizeof(uint32_t);
1513}
1514
1515uint32_t MipsAssembler::Branch::GetOldSize() const {
1516  return GetOldLength() * sizeof(uint32_t);
1517}
1518
1519uint32_t MipsAssembler::Branch::GetEndLocation() const {
1520  return GetLocation() + GetSize();
1521}
1522
1523uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1524  return GetOldLocation() + GetOldSize();
1525}
1526
1527bool MipsAssembler::Branch::IsLong() const {
1528  switch (type_) {
1529    // R2 short branches.
1530    case kUncondBranch:
1531    case kCondBranch:
1532    case kCall:
1533    // R6 short branches.
1534    case kR6UncondBranch:
1535    case kR6CondBranch:
1536    case kR6Call:
1537      return false;
1538    // R2 long branches.
1539    case kLongUncondBranch:
1540    case kLongCondBranch:
1541    case kLongCall:
1542    // R6 long branches.
1543    case kR6LongUncondBranch:
1544    case kR6LongCondBranch:
1545    case kR6LongCall:
1546      return true;
1547  }
1548  UNREACHABLE();
1549}
1550
1551bool MipsAssembler::Branch::IsResolved() const {
1552  return target_ != kUnresolved;
1553}
1554
1555MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1556  OffsetBits offset_size =
1557      (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1558          ? kOffset23
1559          : branch_info_[type_].offset_size;
1560  return offset_size;
1561}
1562
1563MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1564                                                                             uint32_t target) {
1565  // For unresolved targets assume the shortest encoding
1566  // (later it will be made longer if needed).
1567  if (target == kUnresolved)
1568    return kOffset16;
1569  int64_t distance = static_cast<int64_t>(target) - location;
1570  // To simplify calculations in composite branches consisting of multiple instructions
1571  // bump up the distance by a value larger than the max byte size of a composite branch.
1572  distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1573  if (IsInt<kOffset16>(distance))
1574    return kOffset16;
1575  else if (IsInt<kOffset18>(distance))
1576    return kOffset18;
1577  else if (IsInt<kOffset21>(distance))
1578    return kOffset21;
1579  else if (IsInt<kOffset23>(distance))
1580    return kOffset23;
1581  else if (IsInt<kOffset28>(distance))
1582    return kOffset28;
1583  return kOffset32;
1584}
1585
1586void MipsAssembler::Branch::Resolve(uint32_t target) {
1587  target_ = target;
1588}
1589
1590void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1591  if (location_ > expand_location) {
1592    location_ += delta;
1593  }
1594  if (!IsResolved()) {
1595    return;  // Don't know the target yet.
1596  }
1597  if (target_ > expand_location) {
1598    target_ += delta;
1599  }
1600}
1601
1602void MipsAssembler::Branch::PromoteToLong() {
1603  switch (type_) {
1604    // R2 short branches.
1605    case kUncondBranch:
1606      type_ = kLongUncondBranch;
1607      break;
1608    case kCondBranch:
1609      type_ = kLongCondBranch;
1610      break;
1611    case kCall:
1612      type_ = kLongCall;
1613      break;
1614    // R6 short branches.
1615    case kR6UncondBranch:
1616      type_ = kR6LongUncondBranch;
1617      break;
1618    case kR6CondBranch:
1619      type_ = kR6LongCondBranch;
1620      break;
1621    case kR6Call:
1622      type_ = kR6LongCall;
1623      break;
1624    default:
1625      // Note: 'type_' is already long.
1626      break;
1627  }
1628  CHECK(IsLong());
1629}
1630
1631uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1632  // If the branch is still unresolved or already long, nothing to do.
1633  if (IsLong() || !IsResolved()) {
1634    return 0;
1635  }
1636  // Promote the short branch to long if the offset size is too small
1637  // to hold the distance between location_ and target_.
1638  if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1639    PromoteToLong();
1640    uint32_t old_size = GetOldSize();
1641    uint32_t new_size = GetSize();
1642    CHECK_GT(new_size, old_size);
1643    return new_size - old_size;
1644  }
1645  // The following logic is for debugging/testing purposes.
1646  // Promote some short branches to long when it's not really required.
1647  if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1648    int64_t distance = static_cast<int64_t>(target_) - location_;
1649    distance = (distance >= 0) ? distance : -distance;
1650    if (distance >= max_short_distance) {
1651      PromoteToLong();
1652      uint32_t old_size = GetOldSize();
1653      uint32_t new_size = GetSize();
1654      CHECK_GT(new_size, old_size);
1655      return new_size - old_size;
1656    }
1657  }
1658  return 0;
1659}
1660
1661uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1662  return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1663}
1664
1665uint32_t MipsAssembler::Branch::GetOffset() const {
1666  CHECK(IsResolved());
1667  uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1668  // Calculate the byte distance between instructions and also account for
1669  // different PC-relative origins.
1670  uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1671  // Prepare the offset for encoding into the instruction(s).
1672  offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1673  return offset;
1674}
1675
1676MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1677  CHECK_LT(branch_id, branches_.size());
1678  return &branches_[branch_id];
1679}
1680
1681const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1682  CHECK_LT(branch_id, branches_.size());
1683  return &branches_[branch_id];
1684}
1685
1686void MipsAssembler::Bind(MipsLabel* label) {
1687  CHECK(!label->IsBound());
1688  uint32_t bound_pc = buffer_.Size();
1689
1690  // Walk the list of branches referring to and preceding this label.
1691  // Store the previously unknown target addresses in them.
1692  while (label->IsLinked()) {
1693    uint32_t branch_id = label->Position();
1694    Branch* branch = GetBranch(branch_id);
1695    branch->Resolve(bound_pc);
1696
1697    uint32_t branch_location = branch->GetLocation();
1698    // Extract the location of the previous branch in the list (walking the list backwards;
1699    // the previous branch ID was stored in the space reserved for this branch).
1700    uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1701
1702    // On to the previous branch in the list...
1703    label->position_ = prev;
1704  }
1705
1706  // Now make the label object contain its own location (relative to the end of the preceding
1707  // branch, if any; it will be used by the branches referring to and following this label).
1708  label->prev_branch_id_plus_one_ = branches_.size();
1709  if (label->prev_branch_id_plus_one_) {
1710    uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1711    const Branch* branch = GetBranch(branch_id);
1712    bound_pc -= branch->GetEndLocation();
1713  }
1714  label->BindTo(bound_pc);
1715}
1716
1717uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1718  CHECK(label->IsBound());
1719  uint32_t target = label->Position();
1720  if (label->prev_branch_id_plus_one_) {
1721    // Get label location based on the branch preceding it.
1722    uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1723    const Branch* branch = GetBranch(branch_id);
1724    target += branch->GetEndLocation();
1725  }
1726  return target;
1727}
1728
1729uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1730  // We can reconstruct the adjustment by going through all the branches from the beginning
1731  // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1732  // with increasing old_position, we can use the data from last AdjustedPosition() to
1733  // continue where we left off and the whole loop should be O(m+n) where m is the number
1734  // of positions to adjust and n is the number of branches.
1735  if (old_position < last_old_position_) {
1736    last_position_adjustment_ = 0;
1737    last_old_position_ = 0;
1738    last_branch_id_ = 0;
1739  }
1740  while (last_branch_id_ != branches_.size()) {
1741    const Branch* branch = GetBranch(last_branch_id_);
1742    if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1743      break;
1744    }
1745    last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1746    ++last_branch_id_;
1747  }
1748  last_old_position_ = old_position;
1749  return old_position + last_position_adjustment_;
1750}
1751
1752void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1753  uint32_t length = branches_.back().GetLength();
1754  if (!label->IsBound()) {
1755    // Branch forward (to a following label), distance is unknown.
1756    // The first branch forward will contain 0, serving as the terminator of
1757    // the list of forward-reaching branches.
1758    Emit(label->position_);
1759    length--;
1760    // Now make the label object point to this branch
1761    // (this forms a linked list of branches preceding this label).
1762    uint32_t branch_id = branches_.size() - 1;
1763    label->LinkTo(branch_id);
1764  }
1765  // Reserve space for the branch.
1766  while (length--) {
1767    Nop();
1768  }
1769}
1770
1771void MipsAssembler::Buncond(MipsLabel* label) {
1772  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1773  branches_.emplace_back(IsR6(), buffer_.Size(), target);
1774  FinalizeLabeledBranch(label);
1775}
1776
1777void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1778  // If lhs = rhs, this can be a NOP.
1779  if (Branch::IsNop(condition, lhs, rhs)) {
1780    return;
1781  }
1782  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1783  branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1784  FinalizeLabeledBranch(label);
1785}
1786
1787void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1788  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1789  branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1790  FinalizeLabeledBranch(label);
1791}
1792
1793void MipsAssembler::PromoteBranches() {
1794  // Promote short branches to long as necessary.
1795  bool changed;
1796  do {
1797    changed = false;
1798    for (auto& branch : branches_) {
1799      CHECK(branch.IsResolved());
1800      uint32_t delta = branch.PromoteIfNeeded();
1801      // If this branch has been promoted and needs to expand in size,
1802      // relocate all branches by the expansion size.
1803      if (delta) {
1804        changed = true;
1805        uint32_t expand_location = branch.GetLocation();
1806        for (auto& branch2 : branches_) {
1807          branch2.Relocate(expand_location, delta);
1808        }
1809      }
1810    }
1811  } while (changed);
1812
1813  // Account for branch expansion by resizing the code buffer
1814  // and moving the code in it to its final location.
1815  size_t branch_count = branches_.size();
1816  if (branch_count > 0) {
1817    // Resize.
1818    Branch& last_branch = branches_[branch_count - 1];
1819    uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1820    uint32_t old_size = buffer_.Size();
1821    buffer_.Resize(old_size + size_delta);
1822    // Move the code residing between branch placeholders.
1823    uint32_t end = old_size;
1824    for (size_t i = branch_count; i > 0; ) {
1825      Branch& branch = branches_[--i];
1826      uint32_t size = end - branch.GetOldEndLocation();
1827      buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1828      end = branch.GetOldLocation();
1829    }
1830  }
1831}
1832
1833// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1834const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
1835  // R2 short branches.
1836  {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kUncondBranch
1837  {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCondBranch
1838  {  5, 2, 0, MipsAssembler::Branch::kOffset16, 0 },  // kCall
1839  // R2 long branches.
1840  {  9, 3, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongUncondBranch
1841  { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCondBranch
1842  {  6, 1, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCall
1843  // R6 short branches.
1844  {  1, 0, 1, MipsAssembler::Branch::kOffset28, 2 },  // kR6UncondBranch
1845  {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kR6CondBranch
1846                                                      // Exception: kOffset23 for beqzc/bnezc.
1847  {  2, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Call
1848  // R6 long branches.
1849  {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongUncondBranch
1850  {  3, 1, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCondBranch
1851  {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCall
1852};
1853
1854// Note: make sure branch_info_[] and mitBranch() are kept synchronized.
1855void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
1856  CHECK_EQ(overwriting_, true);
1857  overwrite_location_ = branch->GetLocation();
1858  uint32_t offset = branch->GetOffset();
1859  BranchCondition condition = branch->GetCondition();
1860  Register lhs = branch->GetLeftRegister();
1861  Register rhs = branch->GetRightRegister();
1862  switch (branch->GetType()) {
1863    // R2 short branches.
1864    case Branch::kUncondBranch:
1865      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1866      B(offset);
1867      Nop();  // TODO: improve by filling the delay slot.
1868      break;
1869    case Branch::kCondBranch:
1870      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1871      EmitBcondR2(condition, lhs, rhs, offset);
1872      Nop();  // TODO: improve by filling the delay slot.
1873      break;
1874    case Branch::kCall:
1875      Nal();
1876      Nop();  // TODO: is this NOP really needed here?
1877      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1878      Addiu(lhs, RA, offset);
1879      Jalr(lhs);
1880      Nop();
1881      break;
1882
1883    // R2 long branches.
1884    case Branch::kLongUncondBranch:
1885      // To get the value of the PC register we need to use the NAL instruction.
1886      // NAL clobbers the RA register. However, RA must be preserved if the
1887      // method is compiled without the entry/exit sequences that would take care
1888      // of preserving RA (typically, leaf methods don't preserve RA explicitly).
1889      // So, we need to preserve RA in some temporary storage ourselves. The AT
1890      // register can't be used for this because we need it to load a constant
1891      // which will be added to the value that NAL stores in RA. And we can't
1892      // use T9 for this in the context of the JNI compiler, which uses it
1893      // as a scratch register (see InterproceduralScratchRegister()).
1894      // If we were to add a 32-bit constant to RA using two ADDIU instructions,
1895      // we'd also need to use the ROTR instruction, which requires no less than
1896      // MIPSR2.
1897      // Perhaps, we could use T8 or one of R2's multiplier/divider registers
1898      // (LO or HI) or even a floating-point register, but that doesn't seem
1899      // like a nice solution. We may want this to work on both R6 and pre-R6.
1900      // For now simply use the stack for RA. This should be OK since for the
1901      // vast majority of code a short PC-relative branch is sufficient.
1902      // TODO: can this be improved?
1903      Push(RA);
1904      Nal();
1905      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1906      Lui(AT, High16Bits(offset));
1907      Ori(AT, AT, Low16Bits(offset));
1908      Addu(AT, AT, RA);
1909      Lw(RA, SP, 0);
1910      Jr(AT);
1911      DecreaseFrameSize(kMipsWordSize);
1912      break;
1913    case Branch::kLongCondBranch:
1914      // The comment on case 'Branch::kLongUncondBranch' applies here as well.
1915      // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
1916      // number of instructions skipped:
1917      // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
1918      EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
1919      Push(RA);
1920      Nal();
1921      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1922      Lui(AT, High16Bits(offset));
1923      Ori(AT, AT, Low16Bits(offset));
1924      Addu(AT, AT, RA);
1925      Lw(RA, SP, 0);
1926      Jr(AT);
1927      DecreaseFrameSize(kMipsWordSize);
1928      break;
1929    case Branch::kLongCall:
1930      Nal();
1931      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1932      Lui(AT, High16Bits(offset));
1933      Ori(AT, AT, Low16Bits(offset));
1934      Addu(lhs, AT, RA);
1935      Jalr(lhs);
1936      Nop();
1937      break;
1938
1939    // R6 short branches.
1940    case Branch::kR6UncondBranch:
1941      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1942      Bc(offset);
1943      break;
1944    case Branch::kR6CondBranch:
1945      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1946      EmitBcondR6(condition, lhs, rhs, offset);
1947      Nop();  // TODO: improve by filling the forbidden/delay slot.
1948      break;
1949    case Branch::kR6Call:
1950      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1951      Addiupc(lhs, offset);
1952      Jialc(lhs, 0);
1953      break;
1954
1955    // R6 long branches.
1956    case Branch::kR6LongUncondBranch:
1957      offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
1958      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1959      Auipc(AT, High16Bits(offset));
1960      Jic(AT, Low16Bits(offset));
1961      break;
1962    case Branch::kR6LongCondBranch:
1963      EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
1964      offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
1965      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1966      Auipc(AT, High16Bits(offset));
1967      Jic(AT, Low16Bits(offset));
1968      break;
1969    case Branch::kR6LongCall:
1970      offset += (offset & 0x8000) << 1;  // Account for sign extension in addiu.
1971      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1972      Auipc(lhs, High16Bits(offset));
1973      Addiu(lhs, lhs, Low16Bits(offset));
1974      Jialc(lhs, 0);
1975      break;
1976  }
1977  CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1978  CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
1979}
1980
1981void MipsAssembler::B(MipsLabel* label) {
1982  Buncond(label);
1983}
1984
1985void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
1986  Call(label, indirect_reg);
1987}
1988
1989void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
1990  Bcond(label, kCondEQ, rs, rt);
1991}
1992
1993void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
1994  Bcond(label, kCondNE, rs, rt);
1995}
1996
1997void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
1998  Bcond(label, kCondEQZ, rt);
1999}
2000
2001void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2002  Bcond(label, kCondNEZ, rt);
2003}
2004
2005void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2006  Bcond(label, kCondLTZ, rt);
2007}
2008
2009void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2010  Bcond(label, kCondGEZ, rt);
2011}
2012
2013void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2014  Bcond(label, kCondLEZ, rt);
2015}
2016
2017void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2018  Bcond(label, kCondGTZ, rt);
2019}
2020
2021void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
2022  if (IsR6()) {
2023    Bcond(label, kCondLT, rs, rt);
2024  } else if (!Branch::IsNop(kCondLT, rs, rt)) {
2025    // Synthesize the instruction (not available on R2).
2026    Slt(AT, rs, rt);
2027    Bnez(AT, label);
2028  }
2029}
2030
2031void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
2032  if (IsR6()) {
2033    Bcond(label, kCondGE, rs, rt);
2034  } else if (Branch::IsUncond(kCondGE, rs, rt)) {
2035    B(label);
2036  } else {
2037    // Synthesize the instruction (not available on R2).
2038    Slt(AT, rs, rt);
2039    Beqz(AT, label);
2040  }
2041}
2042
2043void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
2044  if (IsR6()) {
2045    Bcond(label, kCondLTU, rs, rt);
2046  } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
2047    // Synthesize the instruction (not available on R2).
2048    Sltu(AT, rs, rt);
2049    Bnez(AT, label);
2050  }
2051}
2052
2053void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
2054  if (IsR6()) {
2055    Bcond(label, kCondGEU, rs, rt);
2056  } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
2057    B(label);
2058  } else {
2059    // Synthesize the instruction (not available on R2).
2060    Sltu(AT, rs, rt);
2061    Beqz(AT, label);
2062  }
2063}
2064
2065void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2066  CHECK(IsUint<3>(cc)) << cc;
2067  Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2068}
2069
2070void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2071  CHECK(IsUint<3>(cc)) << cc;
2072  Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2073}
2074
2075void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2076  Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2077}
2078
2079void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2080  Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2081}
2082
2083void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
2084                                   int32_t offset) {
2085  // IsInt<16> must be passed a signed value.
2086  if (!IsInt<16>(offset) ||
2087      (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2088    LoadConst32(AT, offset);
2089    Addu(AT, AT, base);
2090    base = AT;
2091    offset = 0;
2092  }
2093
2094  switch (type) {
2095    case kLoadSignedByte:
2096      Lb(reg, base, offset);
2097      break;
2098    case kLoadUnsignedByte:
2099      Lbu(reg, base, offset);
2100      break;
2101    case kLoadSignedHalfword:
2102      Lh(reg, base, offset);
2103      break;
2104    case kLoadUnsignedHalfword:
2105      Lhu(reg, base, offset);
2106      break;
2107    case kLoadWord:
2108      Lw(reg, base, offset);
2109      break;
2110    case kLoadDoubleword:
2111      if (reg == base) {
2112        // This will clobber the base when loading the lower register. Since we have to load the
2113        // higher register as well, this will fail. Solution: reverse the order.
2114        Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2115        Lw(reg, base, offset);
2116      } else {
2117        Lw(reg, base, offset);
2118        Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2119      }
2120      break;
2121    default:
2122      LOG(FATAL) << "UNREACHABLE";
2123  }
2124}
2125
2126void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
2127  if (!IsInt<16>(offset)) {
2128    LoadConst32(AT, offset);
2129    Addu(AT, AT, base);
2130    base = AT;
2131    offset = 0;
2132  }
2133
2134  Lwc1(reg, base, offset);
2135}
2136
2137void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
2138  // IsInt<16> must be passed a signed value.
2139  if (!IsInt<16>(offset) ||
2140      (!IsAligned<kMipsDoublewordSize>(offset) &&
2141       !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2142    LoadConst32(AT, offset);
2143    Addu(AT, AT, base);
2144    base = AT;
2145    offset = 0;
2146  }
2147
2148  if (offset & 0x7) {
2149    if (Is32BitFPU()) {
2150      Lwc1(reg, base, offset);
2151      Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2152    } else {
2153      // 64-bit FPU.
2154      Lwc1(reg, base, offset);
2155      Lw(T8, base, offset + kMipsWordSize);
2156      Mthc1(T8, reg);
2157    }
2158  } else {
2159    Ldc1(reg, base, offset);
2160  }
2161}
2162
2163void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
2164                             size_t size) {
2165  MipsManagedRegister dst = m_dst.AsMips();
2166  if (dst.IsNoRegister()) {
2167    CHECK_EQ(0u, size) << dst;
2168  } else if (dst.IsCoreRegister()) {
2169    CHECK_EQ(kMipsWordSize, size) << dst;
2170    LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
2171  } else if (dst.IsRegisterPair()) {
2172    CHECK_EQ(kMipsDoublewordSize, size) << dst;
2173    LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
2174  } else if (dst.IsFRegister()) {
2175    if (size == kMipsWordSize) {
2176      LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
2177    } else {
2178      CHECK_EQ(kMipsDoublewordSize, size) << dst;
2179      LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
2180    }
2181  }
2182}
2183
2184void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
2185                                  int32_t offset) {
2186  // IsInt<16> must be passed a signed value.
2187  if (!IsInt<16>(offset) ||
2188      (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2189    LoadConst32(AT, offset);
2190    Addu(AT, AT, base);
2191    base = AT;
2192    offset = 0;
2193  }
2194
2195  switch (type) {
2196    case kStoreByte:
2197      Sb(reg, base, offset);
2198      break;
2199    case kStoreHalfword:
2200      Sh(reg, base, offset);
2201      break;
2202    case kStoreWord:
2203      Sw(reg, base, offset);
2204      break;
2205    case kStoreDoubleword:
2206      CHECK_NE(reg, base);
2207      CHECK_NE(static_cast<Register>(reg + 1), base);
2208      Sw(reg, base, offset);
2209      Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2210      break;
2211    default:
2212      LOG(FATAL) << "UNREACHABLE";
2213  }
2214}
2215
2216void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
2217  if (!IsInt<16>(offset)) {
2218    LoadConst32(AT, offset);
2219    Addu(AT, AT, base);
2220    base = AT;
2221    offset = 0;
2222  }
2223
2224  Swc1(reg, base, offset);
2225}
2226
2227void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
2228  // IsInt<16> must be passed a signed value.
2229  if (!IsInt<16>(offset) ||
2230      (!IsAligned<kMipsDoublewordSize>(offset) &&
2231       !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2232    LoadConst32(AT, offset);
2233    Addu(AT, AT, base);
2234    base = AT;
2235    offset = 0;
2236  }
2237
2238  if (offset & 0x7) {
2239    if (Is32BitFPU()) {
2240      Swc1(reg, base, offset);
2241      Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2242    } else {
2243      // 64-bit FPU.
2244      Mfhc1(T8, reg);
2245      Swc1(reg, base, offset);
2246      Sw(T8, base, offset + kMipsWordSize);
2247    }
2248  } else {
2249    Sdc1(reg, base, offset);
2250  }
2251}
2252
2253static dwarf::Reg DWARFReg(Register reg) {
2254  return dwarf::Reg::MipsCore(static_cast<int>(reg));
2255}
2256
2257constexpr size_t kFramePointerSize = 4;
2258
2259void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
2260                               const std::vector<ManagedRegister>& callee_save_regs,
2261                               const ManagedRegisterEntrySpills& entry_spills) {
2262  CHECK_ALIGNED(frame_size, kStackAlignment);
2263  DCHECK(!overwriting_);
2264
2265  // Increase frame to required size.
2266  IncreaseFrameSize(frame_size);
2267
2268  // Push callee saves and return address.
2269  int stack_offset = frame_size - kFramePointerSize;
2270  StoreToOffset(kStoreWord, RA, SP, stack_offset);
2271  cfi_.RelOffset(DWARFReg(RA), stack_offset);
2272  for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2273    stack_offset -= kFramePointerSize;
2274    Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2275    StoreToOffset(kStoreWord, reg, SP, stack_offset);
2276    cfi_.RelOffset(DWARFReg(reg), stack_offset);
2277  }
2278
2279  // Write out Method*.
2280  StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
2281
2282  // Write out entry spills.
2283  int32_t offset = frame_size + kFramePointerSize;
2284  for (size_t i = 0; i < entry_spills.size(); ++i) {
2285    MipsManagedRegister reg = entry_spills.at(i).AsMips();
2286    if (reg.IsNoRegister()) {
2287      ManagedRegisterSpill spill = entry_spills.at(i);
2288      offset += spill.getSize();
2289    } else if (reg.IsCoreRegister()) {
2290      StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
2291      offset += kMipsWordSize;
2292    } else if (reg.IsFRegister()) {
2293      StoreSToOffset(reg.AsFRegister(), SP, offset);
2294      offset += kMipsWordSize;
2295    } else if (reg.IsDRegister()) {
2296      StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
2297      offset += kMipsDoublewordSize;
2298    }
2299  }
2300}
2301
2302void MipsAssembler::RemoveFrame(size_t frame_size,
2303                                const std::vector<ManagedRegister>& callee_save_regs) {
2304  CHECK_ALIGNED(frame_size, kStackAlignment);
2305  DCHECK(!overwriting_);
2306  cfi_.RememberState();
2307
2308  // Pop callee saves and return address.
2309  int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2310  for (size_t i = 0; i < callee_save_regs.size(); ++i) {
2311    Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2312    LoadFromOffset(kLoadWord, reg, SP, stack_offset);
2313    cfi_.Restore(DWARFReg(reg));
2314    stack_offset += kFramePointerSize;
2315  }
2316  LoadFromOffset(kLoadWord, RA, SP, stack_offset);
2317  cfi_.Restore(DWARFReg(RA));
2318
2319  // Decrease frame to required size.
2320  DecreaseFrameSize(frame_size);
2321
2322  // Then jump to the return address.
2323  Jr(RA);
2324  Nop();
2325
2326  // The CFI should be restored for any code that follows the exit block.
2327  cfi_.RestoreState();
2328  cfi_.DefCFAOffset(frame_size);
2329}
2330
2331void MipsAssembler::IncreaseFrameSize(size_t adjust) {
2332  CHECK_ALIGNED(adjust, kFramePointerSize);
2333  Addiu32(SP, SP, -adjust);
2334  cfi_.AdjustCFAOffset(adjust);
2335  if (overwriting_) {
2336    cfi_.OverrideDelayedPC(overwrite_location_);
2337  }
2338}
2339
2340void MipsAssembler::DecreaseFrameSize(size_t adjust) {
2341  CHECK_ALIGNED(adjust, kFramePointerSize);
2342  Addiu32(SP, SP, adjust);
2343  cfi_.AdjustCFAOffset(-adjust);
2344  if (overwriting_) {
2345    cfi_.OverrideDelayedPC(overwrite_location_);
2346  }
2347}
2348
2349void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2350  MipsManagedRegister src = msrc.AsMips();
2351  if (src.IsNoRegister()) {
2352    CHECK_EQ(0u, size);
2353  } else if (src.IsCoreRegister()) {
2354    CHECK_EQ(kMipsWordSize, size);
2355    StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2356  } else if (src.IsRegisterPair()) {
2357    CHECK_EQ(kMipsDoublewordSize, size);
2358    StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
2359    StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
2360                  SP, dest.Int32Value() + kMipsWordSize);
2361  } else if (src.IsFRegister()) {
2362    if (size == kMipsWordSize) {
2363      StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
2364    } else {
2365      CHECK_EQ(kMipsDoublewordSize, size);
2366      StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
2367    }
2368  }
2369}
2370
2371void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2372  MipsManagedRegister src = msrc.AsMips();
2373  CHECK(src.IsCoreRegister());
2374  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2375}
2376
2377void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2378  MipsManagedRegister src = msrc.AsMips();
2379  CHECK(src.IsCoreRegister());
2380  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2381}
2382
2383void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2384                                          ManagedRegister mscratch) {
2385  MipsManagedRegister scratch = mscratch.AsMips();
2386  CHECK(scratch.IsCoreRegister()) << scratch;
2387  LoadConst32(scratch.AsCoreRegister(), imm);
2388  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2389}
2390
2391void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
2392                                             ManagedRegister mscratch) {
2393  MipsManagedRegister scratch = mscratch.AsMips();
2394  CHECK(scratch.IsCoreRegister()) << scratch;
2395  // Is this function even referenced anywhere else in the code?
2396  LoadConst32(scratch.AsCoreRegister(), imm);
2397  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
2398}
2399
2400void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2401                                               FrameOffset fr_offs,
2402                                               ManagedRegister mscratch) {
2403  MipsManagedRegister scratch = mscratch.AsMips();
2404  CHECK(scratch.IsCoreRegister()) << scratch;
2405  Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
2406  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2407                S1, thr_offs.Int32Value());
2408}
2409
2410void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
2411  StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2412}
2413
2414void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2415                                  FrameOffset in_off, ManagedRegister mscratch) {
2416  MipsManagedRegister src = msrc.AsMips();
2417  MipsManagedRegister scratch = mscratch.AsMips();
2418  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2419  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
2420  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
2421}
2422
2423void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2424  return EmitLoad(mdest, SP, src.Int32Value(), size);
2425}
2426
2427void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2428                                     ThreadOffset<kMipsWordSize> src, size_t size) {
2429  return EmitLoad(mdest, S1, src.Int32Value(), size);
2430}
2431
2432void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2433  MipsManagedRegister dest = mdest.AsMips();
2434  CHECK(dest.IsCoreRegister());
2435  LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
2436}
2437
2438void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
2439                            bool unpoison_reference) {
2440  MipsManagedRegister dest = mdest.AsMips();
2441  CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
2442  LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2443                 base.AsMips().AsCoreRegister(), offs.Int32Value());
2444  if (kPoisonHeapReferences && unpoison_reference) {
2445    Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
2446  }
2447}
2448
2449void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
2450  MipsManagedRegister dest = mdest.AsMips();
2451  CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
2452  LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2453                 base.AsMips().AsCoreRegister(), offs.Int32Value());
2454}
2455
2456void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
2457                                           ThreadOffset<kMipsWordSize> offs) {
2458  MipsManagedRegister dest = mdest.AsMips();
2459  CHECK(dest.IsCoreRegister());
2460  LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
2461}
2462
2463void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2464  UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2465}
2466
2467void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2468  UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2469}
2470
2471void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2472  MipsManagedRegister dest = mdest.AsMips();
2473  MipsManagedRegister src = msrc.AsMips();
2474  if (!dest.Equals(src)) {
2475    if (dest.IsCoreRegister()) {
2476      CHECK(src.IsCoreRegister()) << src;
2477      Move(dest.AsCoreRegister(), src.AsCoreRegister());
2478    } else if (dest.IsFRegister()) {
2479      CHECK(src.IsFRegister()) << src;
2480      if (size == kMipsWordSize) {
2481        MovS(dest.AsFRegister(), src.AsFRegister());
2482      } else {
2483        CHECK_EQ(kMipsDoublewordSize, size);
2484        MovD(dest.AsFRegister(), src.AsFRegister());
2485      }
2486    } else if (dest.IsDRegister()) {
2487      CHECK(src.IsDRegister()) << src;
2488      MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
2489    } else {
2490      CHECK(dest.IsRegisterPair()) << dest;
2491      CHECK(src.IsRegisterPair()) << src;
2492      // Ensure that the first move doesn't clobber the input of the second.
2493      if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
2494        Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2495        Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2496      } else {
2497        Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2498        Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2499      }
2500    }
2501  }
2502}
2503
2504void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
2505  MipsManagedRegister scratch = mscratch.AsMips();
2506  CHECK(scratch.IsCoreRegister()) << scratch;
2507  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2508  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2509}
2510
2511void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
2512                                           ThreadOffset<kMipsWordSize> thr_offs,
2513                                           ManagedRegister mscratch) {
2514  MipsManagedRegister scratch = mscratch.AsMips();
2515  CHECK(scratch.IsCoreRegister()) << scratch;
2516  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2517                 S1, thr_offs.Int32Value());
2518  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2519                SP, fr_offs.Int32Value());
2520}
2521
2522void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2523                                         FrameOffset fr_offs,
2524                                         ManagedRegister mscratch) {
2525  MipsManagedRegister scratch = mscratch.AsMips();
2526  CHECK(scratch.IsCoreRegister()) << scratch;
2527  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2528                 SP, fr_offs.Int32Value());
2529  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2530                S1, thr_offs.Int32Value());
2531}
2532
2533void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
2534  MipsManagedRegister scratch = mscratch.AsMips();
2535  CHECK(scratch.IsCoreRegister()) << scratch;
2536  CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2537  if (size == kMipsWordSize) {
2538    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2539    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2540  } else if (size == kMipsDoublewordSize) {
2541    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2542    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2543    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2544    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
2545  }
2546}
2547
2548void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2549                         ManagedRegister mscratch, size_t size) {
2550  Register scratch = mscratch.AsMips().AsCoreRegister();
2551  CHECK_EQ(size, kMipsWordSize);
2552  LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2553  StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2554}
2555
2556void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2557                         ManagedRegister mscratch, size_t size) {
2558  Register scratch = mscratch.AsMips().AsCoreRegister();
2559  CHECK_EQ(size, kMipsWordSize);
2560  LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2561  StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2562}
2563
2564void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2565                         FrameOffset src_base ATTRIBUTE_UNUSED,
2566                         Offset src_offset ATTRIBUTE_UNUSED,
2567                         ManagedRegister mscratch ATTRIBUTE_UNUSED,
2568                         size_t size ATTRIBUTE_UNUSED) {
2569  UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2570}
2571
2572void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2573                         ManagedRegister src, Offset src_offset,
2574                         ManagedRegister mscratch, size_t size) {
2575  CHECK_EQ(size, kMipsWordSize);
2576  Register scratch = mscratch.AsMips().AsCoreRegister();
2577  LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2578  StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2579}
2580
2581void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2582                         Offset dest_offset ATTRIBUTE_UNUSED,
2583                         FrameOffset src ATTRIBUTE_UNUSED,
2584                         Offset src_offset ATTRIBUTE_UNUSED,
2585                         ManagedRegister mscratch ATTRIBUTE_UNUSED,
2586                         size_t size ATTRIBUTE_UNUSED) {
2587  UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2588}
2589
2590void MipsAssembler::MemoryBarrier(ManagedRegister) {
2591  // TODO: sync?
2592  UNIMPLEMENTED(FATAL) << "no MIPS implementation";
2593}
2594
2595void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
2596                                           FrameOffset handle_scope_offset,
2597                                           ManagedRegister min_reg,
2598                                           bool null_allowed) {
2599  MipsManagedRegister out_reg = mout_reg.AsMips();
2600  MipsManagedRegister in_reg = min_reg.AsMips();
2601  CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2602  CHECK(out_reg.IsCoreRegister()) << out_reg;
2603  if (null_allowed) {
2604    MipsLabel null_arg;
2605    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2606    // the address in the handle scope holding the reference.
2607    // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
2608    if (in_reg.IsNoRegister()) {
2609      LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2610                     SP, handle_scope_offset.Int32Value());
2611      in_reg = out_reg;
2612    }
2613    if (!out_reg.Equals(in_reg)) {
2614      LoadConst32(out_reg.AsCoreRegister(), 0);
2615    }
2616    Beqz(in_reg.AsCoreRegister(), &null_arg);
2617    Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2618    Bind(&null_arg);
2619  } else {
2620    Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2621  }
2622}
2623
2624void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
2625                                           FrameOffset handle_scope_offset,
2626                                           ManagedRegister mscratch,
2627                                           bool null_allowed) {
2628  MipsManagedRegister scratch = mscratch.AsMips();
2629  CHECK(scratch.IsCoreRegister()) << scratch;
2630  if (null_allowed) {
2631    MipsLabel null_arg;
2632    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2633    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2634    // the address in the handle scope holding the reference.
2635    // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2636    Beqz(scratch.AsCoreRegister(), &null_arg);
2637    Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2638    Bind(&null_arg);
2639  } else {
2640    Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2641  }
2642  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2643}
2644
2645// Given a handle scope entry, load the associated reference.
2646void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
2647                                                 ManagedRegister min_reg) {
2648  MipsManagedRegister out_reg = mout_reg.AsMips();
2649  MipsManagedRegister in_reg = min_reg.AsMips();
2650  CHECK(out_reg.IsCoreRegister()) << out_reg;
2651  CHECK(in_reg.IsCoreRegister()) << in_reg;
2652  MipsLabel null_arg;
2653  if (!out_reg.Equals(in_reg)) {
2654    LoadConst32(out_reg.AsCoreRegister(), 0);
2655  }
2656  Beqz(in_reg.AsCoreRegister(), &null_arg);
2657  LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2658                 in_reg.AsCoreRegister(), 0);
2659  Bind(&null_arg);
2660}
2661
2662void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2663                                 bool could_be_null ATTRIBUTE_UNUSED) {
2664  // TODO: not validating references.
2665}
2666
2667void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2668                                 bool could_be_null ATTRIBUTE_UNUSED) {
2669  // TODO: not validating references.
2670}
2671
2672void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2673  MipsManagedRegister base = mbase.AsMips();
2674  MipsManagedRegister scratch = mscratch.AsMips();
2675  CHECK(base.IsCoreRegister()) << base;
2676  CHECK(scratch.IsCoreRegister()) << scratch;
2677  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2678                 base.AsCoreRegister(), offset.Int32Value());
2679  Jalr(scratch.AsCoreRegister());
2680  Nop();
2681  // TODO: place reference map on call.
2682}
2683
2684void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2685  MipsManagedRegister scratch = mscratch.AsMips();
2686  CHECK(scratch.IsCoreRegister()) << scratch;
2687  // Call *(*(SP + base) + offset)
2688  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
2689  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2690                 scratch.AsCoreRegister(), offset.Int32Value());
2691  Jalr(scratch.AsCoreRegister());
2692  Nop();
2693  // TODO: place reference map on call.
2694}
2695
2696void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2697                                     ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2698  UNIMPLEMENTED(FATAL) << "no mips implementation";
2699}
2700
2701void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2702  Move(tr.AsMips().AsCoreRegister(), S1);
2703}
2704
2705void MipsAssembler::GetCurrentThread(FrameOffset offset,
2706                                     ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2707  StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2708}
2709
2710void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2711  MipsManagedRegister scratch = mscratch.AsMips();
2712  exception_blocks_.emplace_back(scratch, stack_adjust);
2713  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2714                 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2715  // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2716  // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2717  // For now use common for R2 and R6 instructions as this code must execute on both.
2718  Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
2719}
2720
2721void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2722  Bind(exception->Entry());
2723  if (exception->stack_adjust_ != 0) {  // Fix up the frame.
2724    DecreaseFrameSize(exception->stack_adjust_);
2725  }
2726  // Pass exception object as argument.
2727  // Don't care about preserving A0 as this call won't return.
2728  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2729  Move(A0, exception->scratch_.AsCoreRegister());
2730  // Set up call to Thread::Current()->pDeliverException.
2731  LoadFromOffset(kLoadWord, T9, S1,
2732    QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2733  Jr(T9);
2734  Nop();
2735
2736  // Call never returns.
2737  Break();
2738}
2739
2740}  // namespace mips
2741}  // namespace art
2742