1/*
2 * Copyright (C) 2014 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_mips64.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 mips64 {
28
29void Mips64Assembler::FinalizeCode() {
30  for (auto& exception_block : exception_blocks_) {
31    EmitExceptionPoll(&exception_block);
32  }
33  PromoteBranches();
34}
35
36void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
37  EmitBranches();
38  Assembler::FinalizeInstructions(region);
39  PatchCFI();
40}
41
42void Mips64Assembler::PatchCFI() {
43  if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
44    return;
45  }
46
47  typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
48  const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
49  const std::vector<uint8_t>& old_stream = data.first;
50  const std::vector<DelayedAdvancePC>& advances = data.second;
51
52  // Refill our data buffer with patched opcodes.
53  cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
54  size_t stream_pos = 0;
55  for (const DelayedAdvancePC& advance : advances) {
56    DCHECK_GE(advance.stream_pos, stream_pos);
57    // Copy old data up to the point where advance was issued.
58    cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
59    stream_pos = advance.stream_pos;
60    // Insert the advance command with its final offset.
61    size_t final_pc = GetAdjustedPosition(advance.pc);
62    cfi().AdvancePC(final_pc);
63  }
64  // Copy the final segment if any.
65  cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
66}
67
68void Mips64Assembler::EmitBranches() {
69  CHECK(!overwriting_);
70  // Switch from appending instructions at the end of the buffer to overwriting
71  // existing instructions (branch placeholders) in the buffer.
72  overwriting_ = true;
73  for (auto& branch : branches_) {
74    EmitBranch(&branch);
75  }
76  overwriting_ = false;
77}
78
79void Mips64Assembler::Emit(uint32_t value) {
80  if (overwriting_) {
81    // Branches to labels are emitted into their placeholders here.
82    buffer_.Store<uint32_t>(overwrite_location_, value);
83    overwrite_location_ += sizeof(uint32_t);
84  } else {
85    // Other instructions are simply appended at the end here.
86    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
87    buffer_.Emit<uint32_t>(value);
88  }
89}
90
91void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
92                            int shamt, int funct) {
93  CHECK_NE(rs, kNoGpuRegister);
94  CHECK_NE(rt, kNoGpuRegister);
95  CHECK_NE(rd, kNoGpuRegister);
96  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
97                      static_cast<uint32_t>(rs) << kRsShift |
98                      static_cast<uint32_t>(rt) << kRtShift |
99                      static_cast<uint32_t>(rd) << kRdShift |
100                      shamt << kShamtShift |
101                      funct;
102  Emit(encoding);
103}
104
105void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
106                              int shamt, int funct) {
107  CHECK_NE(rs, kNoGpuRegister);
108  CHECK_NE(rd, kNoGpuRegister);
109  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
110                      static_cast<uint32_t>(rs) << kRsShift |
111                      static_cast<uint32_t>(ZERO) << kRtShift |
112                      static_cast<uint32_t>(rd) << kRdShift |
113                      shamt << kShamtShift |
114                      funct;
115  Emit(encoding);
116}
117
118void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
119                              int shamt, int funct) {
120  CHECK_NE(rt, kNoGpuRegister);
121  CHECK_NE(rd, kNoGpuRegister);
122  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
123                      static_cast<uint32_t>(ZERO) << kRsShift |
124                      static_cast<uint32_t>(rt) << kRtShift |
125                      static_cast<uint32_t>(rd) << kRdShift |
126                      shamt << kShamtShift |
127                      funct;
128  Emit(encoding);
129}
130
131void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
132  CHECK_NE(rs, kNoGpuRegister);
133  CHECK_NE(rt, kNoGpuRegister);
134  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
135                      static_cast<uint32_t>(rs) << kRsShift |
136                      static_cast<uint32_t>(rt) << kRtShift |
137                      imm;
138  Emit(encoding);
139}
140
141void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
142  CHECK_NE(rs, kNoGpuRegister);
143  CHECK(IsUint<21>(imm21)) << imm21;
144  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
145                      static_cast<uint32_t>(rs) << kRsShift |
146                      imm21;
147  Emit(encoding);
148}
149
150void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
151  CHECK(IsUint<26>(imm26)) << imm26;
152  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
153  Emit(encoding);
154}
155
156void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
157                             int funct) {
158  CHECK_NE(ft, kNoFpuRegister);
159  CHECK_NE(fs, kNoFpuRegister);
160  CHECK_NE(fd, kNoFpuRegister);
161  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
162                      fmt << kFmtShift |
163                      static_cast<uint32_t>(ft) << kFtShift |
164                      static_cast<uint32_t>(fs) << kFsShift |
165                      static_cast<uint32_t>(fd) << kFdShift |
166                      funct;
167  Emit(encoding);
168}
169
170void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
171  CHECK_NE(ft, kNoFpuRegister);
172  uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
173                      fmt << kFmtShift |
174                      static_cast<uint32_t>(ft) << kFtShift |
175                      imm;
176  Emit(encoding);
177}
178
179void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
180  EmitR(0, rs, rt, rd, 0, 0x21);
181}
182
183void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
184  EmitI(0x9, rs, rt, imm16);
185}
186
187void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
188  EmitR(0, rs, rt, rd, 0, 0x2d);
189}
190
191void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
192  EmitI(0x19, rs, rt, imm16);
193}
194
195void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
196  EmitR(0, rs, rt, rd, 0, 0x23);
197}
198
199void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
200  EmitR(0, rs, rt, rd, 0, 0x2f);
201}
202
203void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
204  EmitR(0, rs, rt, rd, 2, 0x18);
205}
206
207void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
208  EmitR(0, rs, rt, rd, 3, 0x18);
209}
210
211void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
212  EmitR(0, rs, rt, rd, 2, 0x1a);
213}
214
215void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
216  EmitR(0, rs, rt, rd, 3, 0x1a);
217}
218
219void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
220  EmitR(0, rs, rt, rd, 2, 0x1b);
221}
222
223void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
224  EmitR(0, rs, rt, rd, 3, 0x1b);
225}
226
227void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
228  EmitR(0, rs, rt, rd, 2, 0x1c);
229}
230
231void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
232  EmitR(0, rs, rt, rd, 3, 0x1c);
233}
234
235void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
236  EmitR(0, rs, rt, rd, 2, 0x1e);
237}
238
239void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
240  EmitR(0, rs, rt, rd, 3, 0x1e);
241}
242
243void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
244  EmitR(0, rs, rt, rd, 2, 0x1f);
245}
246
247void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
248  EmitR(0, rs, rt, rd, 3, 0x1f);
249}
250
251void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
252  EmitR(0, rs, rt, rd, 0, 0x24);
253}
254
255void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
256  EmitI(0xc, rs, rt, imm16);
257}
258
259void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
260  EmitR(0, rs, rt, rd, 0, 0x25);
261}
262
263void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
264  EmitI(0xd, rs, rt, imm16);
265}
266
267void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
268  EmitR(0, rs, rt, rd, 0, 0x26);
269}
270
271void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
272  EmitI(0xe, rs, rt, imm16);
273}
274
275void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
276  EmitR(0, rs, rt, rd, 0, 0x27);
277}
278
279void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
280  EmitRtd(0x1f, rt, rd, 0x0, 0x20);
281}
282
283void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
284  EmitRtd(0x1f, rt, rd, 0x0, 0x24);
285}
286
287void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
288  EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
289}
290
291void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
292  EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
293}
294
295void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
296  EmitRtd(0x1f, rt, rd, 0x2, 0x24);
297}
298
299void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
300  EmitRtd(0x1f, rt, rd, 0x5, 0x24);
301}
302
303void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
304  CHECK(IsUint<5>(pos)) << pos;
305  CHECK(IsUint<5>(size - 1)) << size;
306  EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
307}
308
309void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
310  CHECK(IsUint<5>(pos - 32)) << pos;
311  CHECK(IsUint<5>(size - 1)) << size;
312  CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
313  EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
314}
315
316void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
317  EmitRtd(0x1f, rt, rd, 2, 0x20);
318}
319
320void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
321  CHECK(IsInt<9>(imm9));
322  EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
323}
324
325void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
326  CHECK(IsInt<9>(imm9));
327  EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
328}
329
330void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
331  CHECK(IsInt<9>(imm9));
332  EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
333}
334
335void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
336  CHECK(IsInt<9>(imm9));
337  EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
338}
339
340void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
341  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
342}
343
344void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
345  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
346}
347
348void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
349  EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
350}
351
352void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
353  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
354}
355
356void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
357  EmitR(0, rs, rt, rd, 0, 0x04);
358}
359
360void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
361  EmitR(0, rs, rt, rd, 1, 0x06);
362}
363
364void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
365  EmitR(0, rs, rt, rd, 0, 0x06);
366}
367
368void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
369  EmitR(0, rs, rt, rd, 0, 0x07);
370}
371
372void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
373  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
374}
375
376void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
377  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
378}
379
380void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
381  EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
382}
383
384void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
385  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
386}
387
388void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
389  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
390}
391
392void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
393  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
394}
395
396void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
397  EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
398}
399
400void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
401  EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
402}
403
404void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
405  EmitR(0, rs, rt, rd, 0, 0x14);
406}
407
408void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
409  EmitR(0, rs, rt, rd, 0, 0x16);
410}
411
412void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
413  EmitR(0, rs, rt, rd, 1, 0x16);
414}
415
416void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
417  EmitR(0, rs, rt, rd, 0, 0x17);
418}
419
420void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
421  EmitI(0x20, rs, rt, imm16);
422}
423
424void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
425  EmitI(0x21, rs, rt, imm16);
426}
427
428void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
429  EmitI(0x23, rs, rt, imm16);
430}
431
432void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
433  EmitI(0x37, rs, rt, imm16);
434}
435
436void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
437  EmitI(0x24, rs, rt, imm16);
438}
439
440void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
441  EmitI(0x25, rs, rt, imm16);
442}
443
444void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
445  EmitI(0x27, rs, rt, imm16);
446}
447
448void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
449  EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
450}
451
452void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
453  EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
454}
455
456void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
457  EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
458}
459
460void Mips64Assembler::Sync(uint32_t stype) {
461  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
462           static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
463}
464
465void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
466  EmitI(0x28, rs, rt, imm16);
467}
468
469void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
470  EmitI(0x29, rs, rt, imm16);
471}
472
473void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
474  EmitI(0x2b, rs, rt, imm16);
475}
476
477void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
478  EmitI(0x3f, rs, rt, imm16);
479}
480
481void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
482  EmitR(0, rs, rt, rd, 0, 0x2a);
483}
484
485void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
486  EmitR(0, rs, rt, rd, 0, 0x2b);
487}
488
489void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
490  EmitI(0xa, rs, rt, imm16);
491}
492
493void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
494  EmitI(0xb, rs, rt, imm16);
495}
496
497void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
498  EmitR(0, rs, rt, rd, 0, 0x35);
499}
500
501void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
502  EmitR(0, rs, rt, rd, 0, 0x37);
503}
504
505void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
506  EmitRsd(0, rs, rd, 0x01, 0x10);
507}
508
509void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
510  EmitRsd(0, rs, rd, 0x01, 0x11);
511}
512
513void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
514  EmitRsd(0, rs, rd, 0x01, 0x12);
515}
516
517void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
518  EmitRsd(0, rs, rd, 0x01, 0x13);
519}
520
521void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
522  EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
523}
524
525void Mips64Assembler::Jalr(GpuRegister rs) {
526  Jalr(RA, rs);
527}
528
529void Mips64Assembler::Jr(GpuRegister rs) {
530  Jalr(ZERO, rs);
531}
532
533void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
534  EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
535}
536
537void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
538  CHECK(IsUint<19>(imm19)) << imm19;
539  EmitI21(0x3B, rs, imm19);
540}
541
542void Mips64Assembler::Bc(uint32_t imm26) {
543  EmitI26(0x32, imm26);
544}
545
546void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
547  EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
548}
549
550void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
551  EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
552}
553
554void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
555  CHECK_NE(rs, ZERO);
556  CHECK_NE(rt, ZERO);
557  CHECK_NE(rs, rt);
558  EmitI(0x17, rs, rt, imm16);
559}
560
561void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
562  CHECK_NE(rt, ZERO);
563  EmitI(0x17, rt, rt, imm16);
564}
565
566void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
567  CHECK_NE(rt, ZERO);
568  EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
569}
570
571void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
572  CHECK_NE(rs, ZERO);
573  CHECK_NE(rt, ZERO);
574  CHECK_NE(rs, rt);
575  EmitI(0x16, rs, rt, imm16);
576}
577
578void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
579  CHECK_NE(rt, ZERO);
580  EmitI(0x16, rt, rt, imm16);
581}
582
583void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
584  CHECK_NE(rt, ZERO);
585  EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
586}
587
588void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
589  CHECK_NE(rs, ZERO);
590  CHECK_NE(rt, ZERO);
591  CHECK_NE(rs, rt);
592  EmitI(0x7, rs, rt, imm16);
593}
594
595void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
596  CHECK_NE(rs, ZERO);
597  CHECK_NE(rt, ZERO);
598  CHECK_NE(rs, rt);
599  EmitI(0x6, rs, rt, imm16);
600}
601
602void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
603  CHECK_NE(rs, ZERO);
604  CHECK_NE(rt, ZERO);
605  CHECK_NE(rs, rt);
606  EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
607}
608
609void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
610  CHECK_NE(rs, ZERO);
611  CHECK_NE(rt, ZERO);
612  CHECK_NE(rs, rt);
613  EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
614}
615
616void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
617  CHECK_NE(rs, ZERO);
618  EmitI21(0x36, rs, imm21);
619}
620
621void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
622  CHECK_NE(rs, ZERO);
623  EmitI21(0x3E, rs, imm21);
624}
625
626void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
627  EmitFI(0x11, 0x9, ft, imm16);
628}
629
630void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
631  EmitFI(0x11, 0xD, ft, imm16);
632}
633
634void Mips64Assembler::EmitBcondc(BranchCondition cond,
635                                 GpuRegister rs,
636                                 GpuRegister rt,
637                                 uint32_t imm16_21) {
638  switch (cond) {
639    case kCondLT:
640      Bltc(rs, rt, imm16_21);
641      break;
642    case kCondGE:
643      Bgec(rs, rt, imm16_21);
644      break;
645    case kCondLE:
646      Bgec(rt, rs, imm16_21);
647      break;
648    case kCondGT:
649      Bltc(rt, rs, imm16_21);
650      break;
651    case kCondLTZ:
652      CHECK_EQ(rt, ZERO);
653      Bltzc(rs, imm16_21);
654      break;
655    case kCondGEZ:
656      CHECK_EQ(rt, ZERO);
657      Bgezc(rs, imm16_21);
658      break;
659    case kCondLEZ:
660      CHECK_EQ(rt, ZERO);
661      Blezc(rs, imm16_21);
662      break;
663    case kCondGTZ:
664      CHECK_EQ(rt, ZERO);
665      Bgtzc(rs, imm16_21);
666      break;
667    case kCondEQ:
668      Beqc(rs, rt, imm16_21);
669      break;
670    case kCondNE:
671      Bnec(rs, rt, imm16_21);
672      break;
673    case kCondEQZ:
674      CHECK_EQ(rt, ZERO);
675      Beqzc(rs, imm16_21);
676      break;
677    case kCondNEZ:
678      CHECK_EQ(rt, ZERO);
679      Bnezc(rs, imm16_21);
680      break;
681    case kCondLTU:
682      Bltuc(rs, rt, imm16_21);
683      break;
684    case kCondGEU:
685      Bgeuc(rs, rt, imm16_21);
686      break;
687    case kCondF:
688      CHECK_EQ(rt, ZERO);
689      Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
690      break;
691    case kCondT:
692      CHECK_EQ(rt, ZERO);
693      Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
694      break;
695    case kUncond:
696      LOG(FATAL) << "Unexpected branch condition " << cond;
697      UNREACHABLE();
698  }
699}
700
701void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
702  EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
703}
704
705void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
706  EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
707}
708
709void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
710  EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
711}
712
713void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
714  EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
715}
716
717void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
718  EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
719}
720
721void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
722  EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
723}
724
725void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
726  EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
727}
728
729void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
730  EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
731}
732
733void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
734  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
735}
736
737void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
738  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
739}
740
741void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
742  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
743}
744
745void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
746  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
747}
748
749void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
750  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
751}
752
753void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
754  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
755}
756
757void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
758  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
759}
760
761void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
762  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
763}
764
765void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
766  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
767}
768
769void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
770  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
771}
772
773void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
774  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
775}
776
777void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
778  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
779}
780
781void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
782  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
783}
784
785void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
786  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
787}
788
789void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
790  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
791}
792
793void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
794  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
795}
796
797void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
798  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
799}
800
801void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
802  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
803}
804
805void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
806  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
807}
808
809void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
810  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
811}
812
813void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
814  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
815}
816
817void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
818  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
819}
820
821void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
822  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
823}
824
825void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
826  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
827}
828
829void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
830  EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
831}
832
833void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
834  EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
835}
836
837void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
838  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
839}
840
841void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
842  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
843}
844
845void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
846  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
847}
848
849void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
850  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
851}
852
853void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
854  EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
855}
856
857void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
858  EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
859}
860
861void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
862  EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
863}
864
865void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
866  EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
867}
868
869void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
870  EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
871}
872
873void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
874  EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
875}
876
877void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
878  EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
879}
880
881void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
882  EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
883}
884
885void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
886  EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
887}
888
889void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
890  EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
891}
892
893void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
894  EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
895}
896
897void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
898  EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
899}
900
901void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
902  EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
903}
904
905void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
906  EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
907}
908
909void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
910  EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
911}
912
913void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
914  EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
915}
916
917void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
918  EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
919}
920
921void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
922  EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
923}
924
925void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
926  EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
927}
928
929void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
930  EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
931}
932
933void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
934  EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
935}
936
937void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
938  EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
939}
940
941void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
942  EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
943}
944
945void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
946  EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
947}
948
949void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
950  EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
951}
952
953void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
954  EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
955}
956
957void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
958  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
959}
960
961void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
962  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
963}
964
965void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
966  EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
967}
968
969void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
970  EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
971}
972
973void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
974  EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
975}
976
977void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
978  EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
979}
980
981void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
982  EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
983}
984
985void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
986  EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
987}
988
989void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
990  EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
991}
992
993void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
994  EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
995}
996
997void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
998  EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
999}
1000
1001void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1002  EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1003}
1004
1005void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1006  EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1007}
1008
1009void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1010  EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1011}
1012
1013void Mips64Assembler::Break() {
1014  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1015        static_cast<GpuRegister>(0), 0, 0xD);
1016}
1017
1018void Mips64Assembler::Nop() {
1019  EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1020        static_cast<GpuRegister>(0), 0, 0x0);
1021}
1022
1023void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1024  Or(rd, rs, ZERO);
1025}
1026
1027void Mips64Assembler::Clear(GpuRegister rd) {
1028  Move(rd, ZERO);
1029}
1030
1031void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1032  Nor(rd, rs, ZERO);
1033}
1034
1035void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
1036  if (IsUint<16>(value)) {
1037    // Use OR with (unsigned) immediate to encode 16b unsigned int.
1038    Ori(rd, ZERO, value);
1039  } else if (IsInt<16>(value)) {
1040    // Use ADD with (signed) immediate to encode 16b signed int.
1041    Addiu(rd, ZERO, value);
1042  } else {
1043    Lui(rd, value >> 16);
1044    if (value & 0xFFFF)
1045      Ori(rd, rd, value);
1046  }
1047}
1048
1049void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
1050  int bit31 = (value & UINT64_C(0x80000000)) != 0;
1051
1052  // Loads with 1 instruction.
1053  if (IsUint<16>(value)) {
1054    Ori(rd, ZERO, value);
1055  } else if (IsInt<16>(value)) {
1056    Daddiu(rd, ZERO, value);
1057  } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
1058    Lui(rd, value >> 16);
1059  } else if (IsInt<32>(value)) {
1060    // Loads with 2 instructions.
1061    Lui(rd, value >> 16);
1062    Ori(rd, rd, value);
1063  } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
1064    Ori(rd, ZERO, value);
1065    Dahi(rd, value >> 32);
1066  } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
1067    Ori(rd, ZERO, value);
1068    Dati(rd, value >> 48);
1069  } else if ((value & 0xFFFF) == 0 &&
1070             (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
1071    Lui(rd, value >> 16);
1072    Dahi(rd, (value >> 32) + bit31);
1073  } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
1074    Lui(rd, value >> 16);
1075    Dati(rd, (value >> 48) + bit31);
1076  } else if (IsPowerOfTwo(value + UINT64_C(1))) {
1077    int shift_cnt = 64 - CTZ(value + UINT64_C(1));
1078    Daddiu(rd, ZERO, -1);
1079    if (shift_cnt < 32) {
1080      Dsrl(rd, rd, shift_cnt);
1081    } else {
1082      Dsrl32(rd, rd, shift_cnt & 31);
1083    }
1084  } else {
1085    int shift_cnt = CTZ(value);
1086    int64_t tmp = value >> shift_cnt;
1087    if (IsUint<16>(tmp)) {
1088      Ori(rd, ZERO, tmp);
1089      if (shift_cnt < 32) {
1090        Dsll(rd, rd, shift_cnt);
1091      } else {
1092        Dsll32(rd, rd, shift_cnt & 31);
1093      }
1094    } else if (IsInt<16>(tmp)) {
1095      Daddiu(rd, ZERO, tmp);
1096      if (shift_cnt < 32) {
1097        Dsll(rd, rd, shift_cnt);
1098      } else {
1099        Dsll32(rd, rd, shift_cnt & 31);
1100      }
1101    } else if (IsInt<32>(tmp)) {
1102      // Loads with 3 instructions.
1103      Lui(rd, tmp >> 16);
1104      Ori(rd, rd, tmp);
1105      if (shift_cnt < 32) {
1106        Dsll(rd, rd, shift_cnt);
1107      } else {
1108        Dsll32(rd, rd, shift_cnt & 31);
1109      }
1110    } else {
1111      shift_cnt = 16 + CTZ(value >> 16);
1112      tmp = value >> shift_cnt;
1113      if (IsUint<16>(tmp)) {
1114        Ori(rd, ZERO, tmp);
1115        if (shift_cnt < 32) {
1116          Dsll(rd, rd, shift_cnt);
1117        } else {
1118          Dsll32(rd, rd, shift_cnt & 31);
1119        }
1120        Ori(rd, rd, value);
1121      } else if (IsInt<16>(tmp)) {
1122        Daddiu(rd, ZERO, tmp);
1123        if (shift_cnt < 32) {
1124          Dsll(rd, rd, shift_cnt);
1125        } else {
1126          Dsll32(rd, rd, shift_cnt & 31);
1127        }
1128        Ori(rd, rd, value);
1129      } else {
1130        // Loads with 3-4 instructions.
1131        uint64_t tmp2 = value;
1132        bool used_lui = false;
1133        if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
1134          Lui(rd, tmp2 >> 16);
1135          used_lui = true;
1136        }
1137        if ((tmp2 & 0xFFFF) != 0) {
1138          if (used_lui) {
1139            Ori(rd, rd, tmp2);
1140          } else {
1141            Ori(rd, ZERO, tmp2);
1142          }
1143        }
1144        if (bit31) {
1145          tmp2 += UINT64_C(0x100000000);
1146        }
1147        if (((tmp2 >> 32) & 0xFFFF) != 0) {
1148          Dahi(rd, tmp2 >> 32);
1149        }
1150        if (tmp2 & UINT64_C(0x800000000000)) {
1151          tmp2 += UINT64_C(0x1000000000000);
1152        }
1153        if ((tmp2 >> 48) != 0) {
1154          Dati(rd, tmp2 >> 48);
1155        }
1156      }
1157    }
1158  }
1159}
1160
1161void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1162  if (IsInt<16>(value)) {
1163    Daddiu(rt, rs, value);
1164  } else {
1165    LoadConst64(rtmp, value);
1166    Daddu(rt, rs, rtmp);
1167  }
1168}
1169
1170void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1171                                              Mips64Assembler::Branch::Type short_type,
1172                                              Mips64Assembler::Branch::Type long_type) {
1173  type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1174}
1175
1176void Mips64Assembler::Branch::InitializeType(bool is_call) {
1177  OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1178  if (is_call) {
1179    InitShortOrLong(offset_size, kCall, kLongCall);
1180  } else if (condition_ == kUncond) {
1181    InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1182  } else {
1183    if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1184      // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1185      type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1186    } else {
1187      InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1188    }
1189  }
1190  old_type_ = type_;
1191}
1192
1193bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1194  switch (condition) {
1195    case kCondLT:
1196    case kCondGT:
1197    case kCondNE:
1198    case kCondLTU:
1199      return lhs == rhs;
1200    default:
1201      return false;
1202  }
1203}
1204
1205bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1206                                       GpuRegister lhs,
1207                                       GpuRegister rhs) {
1208  switch (condition) {
1209    case kUncond:
1210      return true;
1211    case kCondGE:
1212    case kCondLE:
1213    case kCondEQ:
1214    case kCondGEU:
1215      return lhs == rhs;
1216    default:
1217      return false;
1218  }
1219}
1220
1221Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1222    : old_location_(location),
1223      location_(location),
1224      target_(target),
1225      lhs_reg_(ZERO),
1226      rhs_reg_(ZERO),
1227      condition_(kUncond) {
1228  InitializeType(false);
1229}
1230
1231Mips64Assembler::Branch::Branch(uint32_t location,
1232                                uint32_t target,
1233                                Mips64Assembler::BranchCondition condition,
1234                                GpuRegister lhs_reg,
1235                                GpuRegister rhs_reg)
1236    : old_location_(location),
1237      location_(location),
1238      target_(target),
1239      lhs_reg_(lhs_reg),
1240      rhs_reg_(rhs_reg),
1241      condition_(condition) {
1242  CHECK_NE(condition, kUncond);
1243  switch (condition) {
1244    case kCondEQ:
1245    case kCondNE:
1246    case kCondLT:
1247    case kCondGE:
1248    case kCondLE:
1249    case kCondGT:
1250    case kCondLTU:
1251    case kCondGEU:
1252      CHECK_NE(lhs_reg, ZERO);
1253      CHECK_NE(rhs_reg, ZERO);
1254      break;
1255    case kCondLTZ:
1256    case kCondGEZ:
1257    case kCondLEZ:
1258    case kCondGTZ:
1259    case kCondEQZ:
1260    case kCondNEZ:
1261      CHECK_NE(lhs_reg, ZERO);
1262      CHECK_EQ(rhs_reg, ZERO);
1263      break;
1264    case kCondF:
1265    case kCondT:
1266      CHECK_EQ(rhs_reg, ZERO);
1267      break;
1268    case kUncond:
1269      UNREACHABLE();
1270  }
1271  CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1272  if (IsUncond(condition, lhs_reg, rhs_reg)) {
1273    // Branch condition is always true, make the branch unconditional.
1274    condition_ = kUncond;
1275  }
1276  InitializeType(false);
1277}
1278
1279Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1280    : old_location_(location),
1281      location_(location),
1282      target_(target),
1283      lhs_reg_(indirect_reg),
1284      rhs_reg_(ZERO),
1285      condition_(kUncond) {
1286  CHECK_NE(indirect_reg, ZERO);
1287  CHECK_NE(indirect_reg, AT);
1288  InitializeType(true);
1289}
1290
1291Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1292    Mips64Assembler::BranchCondition cond) {
1293  switch (cond) {
1294    case kCondLT:
1295      return kCondGE;
1296    case kCondGE:
1297      return kCondLT;
1298    case kCondLE:
1299      return kCondGT;
1300    case kCondGT:
1301      return kCondLE;
1302    case kCondLTZ:
1303      return kCondGEZ;
1304    case kCondGEZ:
1305      return kCondLTZ;
1306    case kCondLEZ:
1307      return kCondGTZ;
1308    case kCondGTZ:
1309      return kCondLEZ;
1310    case kCondEQ:
1311      return kCondNE;
1312    case kCondNE:
1313      return kCondEQ;
1314    case kCondEQZ:
1315      return kCondNEZ;
1316    case kCondNEZ:
1317      return kCondEQZ;
1318    case kCondLTU:
1319      return kCondGEU;
1320    case kCondGEU:
1321      return kCondLTU;
1322    case kCondF:
1323      return kCondT;
1324    case kCondT:
1325      return kCondF;
1326    case kUncond:
1327      LOG(FATAL) << "Unexpected branch condition " << cond;
1328  }
1329  UNREACHABLE();
1330}
1331
1332Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1333  return type_;
1334}
1335
1336Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1337  return condition_;
1338}
1339
1340GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1341  return lhs_reg_;
1342}
1343
1344GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1345  return rhs_reg_;
1346}
1347
1348uint32_t Mips64Assembler::Branch::GetTarget() const {
1349  return target_;
1350}
1351
1352uint32_t Mips64Assembler::Branch::GetLocation() const {
1353  return location_;
1354}
1355
1356uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1357  return old_location_;
1358}
1359
1360uint32_t Mips64Assembler::Branch::GetLength() const {
1361  return branch_info_[type_].length;
1362}
1363
1364uint32_t Mips64Assembler::Branch::GetOldLength() const {
1365  return branch_info_[old_type_].length;
1366}
1367
1368uint32_t Mips64Assembler::Branch::GetSize() const {
1369  return GetLength() * sizeof(uint32_t);
1370}
1371
1372uint32_t Mips64Assembler::Branch::GetOldSize() const {
1373  return GetOldLength() * sizeof(uint32_t);
1374}
1375
1376uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1377  return GetLocation() + GetSize();
1378}
1379
1380uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1381  return GetOldLocation() + GetOldSize();
1382}
1383
1384bool Mips64Assembler::Branch::IsLong() const {
1385  switch (type_) {
1386    // Short branches.
1387    case kUncondBranch:
1388    case kCondBranch:
1389    case kCall:
1390      return false;
1391    // Long branches.
1392    case kLongUncondBranch:
1393    case kLongCondBranch:
1394    case kLongCall:
1395      return true;
1396  }
1397  UNREACHABLE();
1398}
1399
1400bool Mips64Assembler::Branch::IsResolved() const {
1401  return target_ != kUnresolved;
1402}
1403
1404Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1405  OffsetBits offset_size =
1406      (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1407          ? kOffset23
1408          : branch_info_[type_].offset_size;
1409  return offset_size;
1410}
1411
1412Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1413                                                                                 uint32_t target) {
1414  // For unresolved targets assume the shortest encoding
1415  // (later it will be made longer if needed).
1416  if (target == kUnresolved)
1417    return kOffset16;
1418  int64_t distance = static_cast<int64_t>(target) - location;
1419  // To simplify calculations in composite branches consisting of multiple instructions
1420  // bump up the distance by a value larger than the max byte size of a composite branch.
1421  distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1422  if (IsInt<kOffset16>(distance))
1423    return kOffset16;
1424  else if (IsInt<kOffset18>(distance))
1425    return kOffset18;
1426  else if (IsInt<kOffset21>(distance))
1427    return kOffset21;
1428  else if (IsInt<kOffset23>(distance))
1429    return kOffset23;
1430  else if (IsInt<kOffset28>(distance))
1431    return kOffset28;
1432  return kOffset32;
1433}
1434
1435void Mips64Assembler::Branch::Resolve(uint32_t target) {
1436  target_ = target;
1437}
1438
1439void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1440  if (location_ > expand_location) {
1441    location_ += delta;
1442  }
1443  if (!IsResolved()) {
1444    return;  // Don't know the target yet.
1445  }
1446  if (target_ > expand_location) {
1447    target_ += delta;
1448  }
1449}
1450
1451void Mips64Assembler::Branch::PromoteToLong() {
1452  switch (type_) {
1453    // Short branches.
1454    case kUncondBranch:
1455      type_ = kLongUncondBranch;
1456      break;
1457    case kCondBranch:
1458      type_ = kLongCondBranch;
1459      break;
1460    case kCall:
1461      type_ = kLongCall;
1462      break;
1463    default:
1464      // Note: 'type_' is already long.
1465      break;
1466  }
1467  CHECK(IsLong());
1468}
1469
1470uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1471  // If the branch is still unresolved or already long, nothing to do.
1472  if (IsLong() || !IsResolved()) {
1473    return 0;
1474  }
1475  // Promote the short branch to long if the offset size is too small
1476  // to hold the distance between location_ and target_.
1477  if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1478    PromoteToLong();
1479    uint32_t old_size = GetOldSize();
1480    uint32_t new_size = GetSize();
1481    CHECK_GT(new_size, old_size);
1482    return new_size - old_size;
1483  }
1484  // The following logic is for debugging/testing purposes.
1485  // Promote some short branches to long when it's not really required.
1486  if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1487    int64_t distance = static_cast<int64_t>(target_) - location_;
1488    distance = (distance >= 0) ? distance : -distance;
1489    if (distance >= max_short_distance) {
1490      PromoteToLong();
1491      uint32_t old_size = GetOldSize();
1492      uint32_t new_size = GetSize();
1493      CHECK_GT(new_size, old_size);
1494      return new_size - old_size;
1495    }
1496  }
1497  return 0;
1498}
1499
1500uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1501  return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1502}
1503
1504uint32_t Mips64Assembler::Branch::GetOffset() const {
1505  CHECK(IsResolved());
1506  uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1507  // Calculate the byte distance between instructions and also account for
1508  // different PC-relative origins.
1509  uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1510  // Prepare the offset for encoding into the instruction(s).
1511  offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1512  return offset;
1513}
1514
1515Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1516  CHECK_LT(branch_id, branches_.size());
1517  return &branches_[branch_id];
1518}
1519
1520const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1521  CHECK_LT(branch_id, branches_.size());
1522  return &branches_[branch_id];
1523}
1524
1525void Mips64Assembler::Bind(Mips64Label* label) {
1526  CHECK(!label->IsBound());
1527  uint32_t bound_pc = buffer_.Size();
1528
1529  // Walk the list of branches referring to and preceding this label.
1530  // Store the previously unknown target addresses in them.
1531  while (label->IsLinked()) {
1532    uint32_t branch_id = label->Position();
1533    Branch* branch = GetBranch(branch_id);
1534    branch->Resolve(bound_pc);
1535
1536    uint32_t branch_location = branch->GetLocation();
1537    // Extract the location of the previous branch in the list (walking the list backwards;
1538    // the previous branch ID was stored in the space reserved for this branch).
1539    uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1540
1541    // On to the previous branch in the list...
1542    label->position_ = prev;
1543  }
1544
1545  // Now make the label object contain its own location (relative to the end of the preceding
1546  // branch, if any; it will be used by the branches referring to and following this label).
1547  label->prev_branch_id_plus_one_ = branches_.size();
1548  if (label->prev_branch_id_plus_one_) {
1549    uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1550    const Branch* branch = GetBranch(branch_id);
1551    bound_pc -= branch->GetEndLocation();
1552  }
1553  label->BindTo(bound_pc);
1554}
1555
1556uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1557  CHECK(label->IsBound());
1558  uint32_t target = label->Position();
1559  if (label->prev_branch_id_plus_one_) {
1560    // Get label location based on the branch preceding it.
1561    uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1562    const Branch* branch = GetBranch(branch_id);
1563    target += branch->GetEndLocation();
1564  }
1565  return target;
1566}
1567
1568uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1569  // We can reconstruct the adjustment by going through all the branches from the beginning
1570  // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1571  // with increasing old_position, we can use the data from last AdjustedPosition() to
1572  // continue where we left off and the whole loop should be O(m+n) where m is the number
1573  // of positions to adjust and n is the number of branches.
1574  if (old_position < last_old_position_) {
1575    last_position_adjustment_ = 0;
1576    last_old_position_ = 0;
1577    last_branch_id_ = 0;
1578  }
1579  while (last_branch_id_ != branches_.size()) {
1580    const Branch* branch = GetBranch(last_branch_id_);
1581    if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1582      break;
1583    }
1584    last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1585    ++last_branch_id_;
1586  }
1587  last_old_position_ = old_position;
1588  return old_position + last_position_adjustment_;
1589}
1590
1591void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1592  uint32_t length = branches_.back().GetLength();
1593  if (!label->IsBound()) {
1594    // Branch forward (to a following label), distance is unknown.
1595    // The first branch forward will contain 0, serving as the terminator of
1596    // the list of forward-reaching branches.
1597    Emit(label->position_);
1598    length--;
1599    // Now make the label object point to this branch
1600    // (this forms a linked list of branches preceding this label).
1601    uint32_t branch_id = branches_.size() - 1;
1602    label->LinkTo(branch_id);
1603  }
1604  // Reserve space for the branch.
1605  while (length--) {
1606    Nop();
1607  }
1608}
1609
1610void Mips64Assembler::Buncond(Mips64Label* label) {
1611  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1612  branches_.emplace_back(buffer_.Size(), target);
1613  FinalizeLabeledBranch(label);
1614}
1615
1616void Mips64Assembler::Bcond(Mips64Label* label,
1617                            BranchCondition condition,
1618                            GpuRegister lhs,
1619                            GpuRegister rhs) {
1620  // If lhs = rhs, this can be a NOP.
1621  if (Branch::IsNop(condition, lhs, rhs)) {
1622    return;
1623  }
1624  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1625  branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1626  FinalizeLabeledBranch(label);
1627}
1628
1629void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1630  uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1631  branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1632  FinalizeLabeledBranch(label);
1633}
1634
1635void Mips64Assembler::PromoteBranches() {
1636  // Promote short branches to long as necessary.
1637  bool changed;
1638  do {
1639    changed = false;
1640    for (auto& branch : branches_) {
1641      CHECK(branch.IsResolved());
1642      uint32_t delta = branch.PromoteIfNeeded();
1643      // If this branch has been promoted and needs to expand in size,
1644      // relocate all branches by the expansion size.
1645      if (delta) {
1646        changed = true;
1647        uint32_t expand_location = branch.GetLocation();
1648        for (auto& branch2 : branches_) {
1649          branch2.Relocate(expand_location, delta);
1650        }
1651      }
1652    }
1653  } while (changed);
1654
1655  // Account for branch expansion by resizing the code buffer
1656  // and moving the code in it to its final location.
1657  size_t branch_count = branches_.size();
1658  if (branch_count > 0) {
1659    // Resize.
1660    Branch& last_branch = branches_[branch_count - 1];
1661    uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1662    uint32_t old_size = buffer_.Size();
1663    buffer_.Resize(old_size + size_delta);
1664    // Move the code residing between branch placeholders.
1665    uint32_t end = old_size;
1666    for (size_t i = branch_count; i > 0; ) {
1667      Branch& branch = branches_[--i];
1668      uint32_t size = end - branch.GetOldEndLocation();
1669      buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1670      end = branch.GetOldLocation();
1671    }
1672  }
1673}
1674
1675// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1676const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1677  // Short branches.
1678  {  1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 },  // kUncondBranch
1679  {  2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 },  // kCondBranch
1680                                                        // Exception: kOffset23 for beqzc/bnezc
1681  {  2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 },  // kCall
1682  // Long branches.
1683  {  2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 },  // kLongUncondBranch
1684  {  3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 },  // kLongCondBranch
1685  {  3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 },  // kLongCall
1686};
1687
1688// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1689void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1690  CHECK(overwriting_);
1691  overwrite_location_ = branch->GetLocation();
1692  uint32_t offset = branch->GetOffset();
1693  BranchCondition condition = branch->GetCondition();
1694  GpuRegister lhs = branch->GetLeftRegister();
1695  GpuRegister rhs = branch->GetRightRegister();
1696  switch (branch->GetType()) {
1697    // Short branches.
1698    case Branch::kUncondBranch:
1699      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1700      Bc(offset);
1701      break;
1702    case Branch::kCondBranch:
1703      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1704      EmitBcondc(condition, lhs, rhs, offset);
1705      Nop();  // TODO: improve by filling the forbidden/delay slot.
1706      break;
1707    case Branch::kCall:
1708      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1709      Addiupc(lhs, offset);
1710      Jialc(lhs, 0);
1711      break;
1712
1713    // Long branches.
1714    case Branch::kLongUncondBranch:
1715      offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
1716      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1717      Auipc(AT, High16Bits(offset));
1718      Jic(AT, Low16Bits(offset));
1719      break;
1720    case Branch::kLongCondBranch:
1721      EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1722      offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
1723      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1724      Auipc(AT, High16Bits(offset));
1725      Jic(AT, Low16Bits(offset));
1726      break;
1727    case Branch::kLongCall:
1728      offset += (offset & 0x8000) << 1;  // Account for sign extension in daddiu.
1729      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1730      Auipc(lhs, High16Bits(offset));
1731      Daddiu(lhs, lhs, Low16Bits(offset));
1732      Jialc(lhs, 0);
1733      break;
1734  }
1735  CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1736  CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
1737}
1738
1739void Mips64Assembler::Bc(Mips64Label* label) {
1740  Buncond(label);
1741}
1742
1743void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1744  Call(label, indirect_reg);
1745}
1746
1747void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1748  Bcond(label, kCondLT, rs, rt);
1749}
1750
1751void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1752  Bcond(label, kCondLTZ, rt);
1753}
1754
1755void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1756  Bcond(label, kCondGTZ, rt);
1757}
1758
1759void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1760  Bcond(label, kCondGE, rs, rt);
1761}
1762
1763void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1764  Bcond(label, kCondGEZ, rt);
1765}
1766
1767void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1768  Bcond(label, kCondLEZ, rt);
1769}
1770
1771void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1772  Bcond(label, kCondLTU, rs, rt);
1773}
1774
1775void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1776  Bcond(label, kCondGEU, rs, rt);
1777}
1778
1779void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1780  Bcond(label, kCondEQ, rs, rt);
1781}
1782
1783void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1784  Bcond(label, kCondNE, rs, rt);
1785}
1786
1787void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1788  Bcond(label, kCondEQZ, rs);
1789}
1790
1791void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1792  Bcond(label, kCondNEZ, rs);
1793}
1794
1795void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1796  Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1797}
1798
1799void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1800  Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1801}
1802
1803void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1804                                     int32_t offset) {
1805  if (!IsInt<16>(offset) ||
1806      (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1807       !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1808    LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
1809    Daddu(AT, AT, base);
1810    base = AT;
1811    offset &= (kMips64DoublewordSize - 1);
1812  }
1813
1814  switch (type) {
1815    case kLoadSignedByte:
1816      Lb(reg, base, offset);
1817      break;
1818    case kLoadUnsignedByte:
1819      Lbu(reg, base, offset);
1820      break;
1821    case kLoadSignedHalfword:
1822      Lh(reg, base, offset);
1823      break;
1824    case kLoadUnsignedHalfword:
1825      Lhu(reg, base, offset);
1826      break;
1827    case kLoadWord:
1828      CHECK_ALIGNED(offset, kMips64WordSize);
1829      Lw(reg, base, offset);
1830      break;
1831    case kLoadUnsignedWord:
1832      CHECK_ALIGNED(offset, kMips64WordSize);
1833      Lwu(reg, base, offset);
1834      break;
1835    case kLoadDoubleword:
1836      if (!IsAligned<kMips64DoublewordSize>(offset)) {
1837        CHECK_ALIGNED(offset, kMips64WordSize);
1838        Lwu(reg, base, offset);
1839        Lwu(TMP2, base, offset + kMips64WordSize);
1840        Dinsu(reg, TMP2, 32, 32);
1841      } else {
1842        Ld(reg, base, offset);
1843      }
1844      break;
1845  }
1846}
1847
1848void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1849                                        int32_t offset) {
1850  if (!IsInt<16>(offset) ||
1851      (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1852       !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1853    LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
1854    Daddu(AT, AT, base);
1855    base = AT;
1856    offset &= (kMips64DoublewordSize - 1);
1857  }
1858
1859  switch (type) {
1860    case kLoadWord:
1861      CHECK_ALIGNED(offset, kMips64WordSize);
1862      Lwc1(reg, base, offset);
1863      break;
1864    case kLoadDoubleword:
1865      if (!IsAligned<kMips64DoublewordSize>(offset)) {
1866        CHECK_ALIGNED(offset, kMips64WordSize);
1867        Lwc1(reg, base, offset);
1868        Lw(TMP2, base, offset + kMips64WordSize);
1869        Mthc1(TMP2, reg);
1870      } else {
1871        Ldc1(reg, base, offset);
1872      }
1873      break;
1874    default:
1875      LOG(FATAL) << "UNREACHABLE";
1876  }
1877}
1878
1879void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1880                               size_t size) {
1881  Mips64ManagedRegister dst = m_dst.AsMips64();
1882  if (dst.IsNoRegister()) {
1883    CHECK_EQ(0u, size) << dst;
1884  } else if (dst.IsGpuRegister()) {
1885    if (size == 4) {
1886      LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1887    } else if (size == 8) {
1888      CHECK_EQ(8u, size) << dst;
1889      LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1890    } else {
1891      UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1892    }
1893  } else if (dst.IsFpuRegister()) {
1894    if (size == 4) {
1895      CHECK_EQ(4u, size) << dst;
1896      LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1897    } else if (size == 8) {
1898      CHECK_EQ(8u, size) << dst;
1899      LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1900    } else {
1901      UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1902    }
1903  }
1904}
1905
1906void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1907                                    int32_t offset) {
1908  if (!IsInt<16>(offset) ||
1909      (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1910       !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1911    LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
1912    Daddu(AT, AT, base);
1913    base = AT;
1914    offset &= (kMips64DoublewordSize - 1);
1915  }
1916
1917  switch (type) {
1918    case kStoreByte:
1919      Sb(reg, base, offset);
1920      break;
1921    case kStoreHalfword:
1922      Sh(reg, base, offset);
1923      break;
1924    case kStoreWord:
1925      CHECK_ALIGNED(offset, kMips64WordSize);
1926      Sw(reg, base, offset);
1927      break;
1928    case kStoreDoubleword:
1929      if (!IsAligned<kMips64DoublewordSize>(offset)) {
1930        CHECK_ALIGNED(offset, kMips64WordSize);
1931        Sw(reg, base, offset);
1932        Dsrl32(TMP2, reg, 0);
1933        Sw(TMP2, base, offset + kMips64WordSize);
1934      } else {
1935        Sd(reg, base, offset);
1936      }
1937      break;
1938    default:
1939      LOG(FATAL) << "UNREACHABLE";
1940  }
1941}
1942
1943void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1944                                       int32_t offset) {
1945  if (!IsInt<16>(offset) ||
1946      (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1947       !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1948    LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
1949    Daddu(AT, AT, base);
1950    base = AT;
1951    offset &= (kMips64DoublewordSize - 1);
1952  }
1953
1954  switch (type) {
1955    case kStoreWord:
1956      CHECK_ALIGNED(offset, kMips64WordSize);
1957      Swc1(reg, base, offset);
1958      break;
1959    case kStoreDoubleword:
1960      if (!IsAligned<kMips64DoublewordSize>(offset)) {
1961        CHECK_ALIGNED(offset, kMips64WordSize);
1962        Mfhc1(TMP2, reg);
1963        Swc1(reg, base, offset);
1964        Sw(TMP2, base, offset + kMips64WordSize);
1965      } else {
1966        Sdc1(reg, base, offset);
1967      }
1968      break;
1969    default:
1970      LOG(FATAL) << "UNREACHABLE";
1971  }
1972}
1973
1974static dwarf::Reg DWARFReg(GpuRegister reg) {
1975  return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1976}
1977
1978constexpr size_t kFramePointerSize = 8;
1979
1980void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
1981                                 const std::vector<ManagedRegister>& callee_save_regs,
1982                                 const ManagedRegisterEntrySpills& entry_spills) {
1983  CHECK_ALIGNED(frame_size, kStackAlignment);
1984  DCHECK(!overwriting_);
1985
1986  // Increase frame to required size.
1987  IncreaseFrameSize(frame_size);
1988
1989  // Push callee saves and return address
1990  int stack_offset = frame_size - kFramePointerSize;
1991  StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
1992  cfi_.RelOffset(DWARFReg(RA), stack_offset);
1993  for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1994    stack_offset -= kFramePointerSize;
1995    GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
1996    StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
1997    cfi_.RelOffset(DWARFReg(reg), stack_offset);
1998  }
1999
2000  // Write out Method*.
2001  StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
2002
2003  // Write out entry spills.
2004  int32_t offset = frame_size + kFramePointerSize;
2005  for (size_t i = 0; i < entry_spills.size(); ++i) {
2006    Mips64ManagedRegister reg = entry_spills.at(i).AsMips64();
2007    ManagedRegisterSpill spill = entry_spills.at(i);
2008    int32_t size = spill.getSize();
2009    if (reg.IsNoRegister()) {
2010      // only increment stack offset.
2011      offset += size;
2012    } else if (reg.IsFpuRegister()) {
2013      StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2014          reg.AsFpuRegister(), SP, offset);
2015      offset += size;
2016    } else if (reg.IsGpuRegister()) {
2017      StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2018          reg.AsGpuRegister(), SP, offset);
2019      offset += size;
2020    }
2021  }
2022}
2023
2024void Mips64Assembler::RemoveFrame(size_t frame_size,
2025                                  const std::vector<ManagedRegister>& callee_save_regs) {
2026  CHECK_ALIGNED(frame_size, kStackAlignment);
2027  DCHECK(!overwriting_);
2028  cfi_.RememberState();
2029
2030  // Pop callee saves and return address
2031  int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2032  for (size_t i = 0; i < callee_save_regs.size(); ++i) {
2033    GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
2034    LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
2035    cfi_.Restore(DWARFReg(reg));
2036    stack_offset += kFramePointerSize;
2037  }
2038  LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
2039  cfi_.Restore(DWARFReg(RA));
2040
2041  // Decrease frame to required size.
2042  DecreaseFrameSize(frame_size);
2043
2044  // Then jump to the return address.
2045  Jr(RA);
2046  Nop();
2047
2048  // The CFI should be restored for any code that follows the exit block.
2049  cfi_.RestoreState();
2050  cfi_.DefCFAOffset(frame_size);
2051}
2052
2053void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
2054  CHECK_ALIGNED(adjust, kFramePointerSize);
2055  DCHECK(!overwriting_);
2056  Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
2057  cfi_.AdjustCFAOffset(adjust);
2058}
2059
2060void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
2061  CHECK_ALIGNED(adjust, kFramePointerSize);
2062  DCHECK(!overwriting_);
2063  Daddiu64(SP, SP, static_cast<int32_t>(adjust));
2064  cfi_.AdjustCFAOffset(-adjust);
2065}
2066
2067void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2068  Mips64ManagedRegister src = msrc.AsMips64();
2069  if (src.IsNoRegister()) {
2070    CHECK_EQ(0u, size);
2071  } else if (src.IsGpuRegister()) {
2072    CHECK(size == 4 || size == 8) << size;
2073    if (size == 8) {
2074      StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2075    } else if (size == 4) {
2076      StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2077    } else {
2078      UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2079    }
2080  } else if (src.IsFpuRegister()) {
2081    CHECK(size == 4 || size == 8) << size;
2082    if (size == 8) {
2083      StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2084    } else if (size == 4) {
2085      StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2086    } else {
2087      UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2088    }
2089  }
2090}
2091
2092void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2093  Mips64ManagedRegister src = msrc.AsMips64();
2094  CHECK(src.IsGpuRegister());
2095  StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2096}
2097
2098void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2099  Mips64ManagedRegister src = msrc.AsMips64();
2100  CHECK(src.IsGpuRegister());
2101  StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2102}
2103
2104void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2105                                            ManagedRegister mscratch) {
2106  Mips64ManagedRegister scratch = mscratch.AsMips64();
2107  CHECK(scratch.IsGpuRegister()) << scratch;
2108  LoadConst32(scratch.AsGpuRegister(), imm);
2109  StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2110}
2111
2112void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
2113                                                 FrameOffset fr_offs,
2114                                                 ManagedRegister mscratch) {
2115  Mips64ManagedRegister scratch = mscratch.AsMips64();
2116  CHECK(scratch.IsGpuRegister()) << scratch;
2117  Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2118  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2119}
2120
2121void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs) {
2122  StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2123}
2124
2125void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2126                                    FrameOffset in_off, ManagedRegister mscratch) {
2127  Mips64ManagedRegister src = msrc.AsMips64();
2128  Mips64ManagedRegister scratch = mscratch.AsMips64();
2129  StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2130  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2131  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2132}
2133
2134void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2135  return EmitLoad(mdest, SP, src.Int32Value(), size);
2136}
2137
2138void Mips64Assembler::LoadFromThread64(ManagedRegister mdest,
2139                                       ThreadOffset<kMips64DoublewordSize> src,
2140                                       size_t size) {
2141  return EmitLoad(mdest, S1, src.Int32Value(), size);
2142}
2143
2144void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2145  Mips64ManagedRegister dest = mdest.AsMips64();
2146  CHECK(dest.IsGpuRegister());
2147  LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
2148}
2149
2150void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
2151                              bool unpoison_reference) {
2152  Mips64ManagedRegister dest = mdest.AsMips64();
2153  CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2154  LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
2155                 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2156  if (kPoisonHeapReferences && unpoison_reference) {
2157    // TODO: review
2158    // Negate the 32-bit ref
2159    Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2160    // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
2161    Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
2162  }
2163}
2164
2165void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
2166                                 Offset offs) {
2167  Mips64ManagedRegister dest = mdest.AsMips64();
2168  CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2169  LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2170                 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2171}
2172
2173void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
2174                                             ThreadOffset<kMips64DoublewordSize> offs) {
2175  Mips64ManagedRegister dest = mdest.AsMips64();
2176  CHECK(dest.IsGpuRegister());
2177  LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2178}
2179
2180void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2181                                 size_t size ATTRIBUTE_UNUSED) {
2182  UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
2183}
2184
2185void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2186                                 size_t size ATTRIBUTE_UNUSED) {
2187  UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
2188}
2189
2190void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2191  Mips64ManagedRegister dest = mdest.AsMips64();
2192  Mips64ManagedRegister src = msrc.AsMips64();
2193  if (!dest.Equals(src)) {
2194    if (dest.IsGpuRegister()) {
2195      CHECK(src.IsGpuRegister()) << src;
2196      Move(dest.AsGpuRegister(), src.AsGpuRegister());
2197    } else if (dest.IsFpuRegister()) {
2198      CHECK(src.IsFpuRegister()) << src;
2199      if (size == 4) {
2200        MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2201      } else if (size == 8) {
2202        MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2203      } else {
2204        UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2205      }
2206    }
2207  }
2208}
2209
2210void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2211                              ManagedRegister mscratch) {
2212  Mips64ManagedRegister scratch = mscratch.AsMips64();
2213  CHECK(scratch.IsGpuRegister()) << scratch;
2214  LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2215  StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2216}
2217
2218void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
2219                                             ThreadOffset<kMips64DoublewordSize> thr_offs,
2220                                             ManagedRegister mscratch) {
2221  Mips64ManagedRegister scratch = mscratch.AsMips64();
2222  CHECK(scratch.IsGpuRegister()) << scratch;
2223  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2224  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2225}
2226
2227void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
2228                                           FrameOffset fr_offs,
2229                                           ManagedRegister mscratch) {
2230  Mips64ManagedRegister scratch = mscratch.AsMips64();
2231  CHECK(scratch.IsGpuRegister()) << scratch;
2232  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2233                 SP, fr_offs.Int32Value());
2234  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2235                S1, thr_offs.Int32Value());
2236}
2237
2238void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2239                           ManagedRegister mscratch, size_t size) {
2240  Mips64ManagedRegister scratch = mscratch.AsMips64();
2241  CHECK(scratch.IsGpuRegister()) << scratch;
2242  CHECK(size == 4 || size == 8) << size;
2243  if (size == 4) {
2244    LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2245    StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2246  } else if (size == 8) {
2247    LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2248    StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2249  } else {
2250    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2251  }
2252}
2253
2254void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2255                           ManagedRegister mscratch, size_t size) {
2256  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2257  CHECK(size == 4 || size == 8) << size;
2258  if (size == 4) {
2259    LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2260                   src_offset.Int32Value());
2261    StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2262  } else if (size == 8) {
2263    LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2264                   src_offset.Int32Value());
2265    StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2266  } else {
2267    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2268  }
2269}
2270
2271void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2272                           ManagedRegister mscratch, size_t size) {
2273  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2274  CHECK(size == 4 || size == 8) << size;
2275  if (size == 4) {
2276    LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2277    StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2278                  dest_offset.Int32Value());
2279  } else if (size == 8) {
2280    LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2281    StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2282                  dest_offset.Int32Value());
2283  } else {
2284    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2285  }
2286}
2287
2288void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2289                           FrameOffset src_base ATTRIBUTE_UNUSED,
2290                           Offset src_offset ATTRIBUTE_UNUSED,
2291                           ManagedRegister mscratch ATTRIBUTE_UNUSED,
2292                           size_t size ATTRIBUTE_UNUSED) {
2293  UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
2294}
2295
2296void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
2297                           ManagedRegister src, Offset src_offset,
2298                           ManagedRegister mscratch, size_t size) {
2299  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2300  CHECK(size == 4 || size == 8) << size;
2301  if (size == 4) {
2302    LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
2303    StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
2304  } else if (size == 8) {
2305    LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2306                   src_offset.Int32Value());
2307    StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2308                  dest_offset.Int32Value());
2309  } else {
2310    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2311  }
2312}
2313
2314void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2315                           Offset dest_offset ATTRIBUTE_UNUSED,
2316                           FrameOffset src ATTRIBUTE_UNUSED,
2317                           Offset src_offset ATTRIBUTE_UNUSED,
2318                           ManagedRegister mscratch ATTRIBUTE_UNUSED,
2319                           size_t size ATTRIBUTE_UNUSED) {
2320  UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
2321}
2322
2323void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
2324  // TODO: sync?
2325  UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
2326}
2327
2328void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
2329                                             FrameOffset handle_scope_offset,
2330                                             ManagedRegister min_reg,
2331                                             bool null_allowed) {
2332  Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2333  Mips64ManagedRegister in_reg = min_reg.AsMips64();
2334  CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2335  CHECK(out_reg.IsGpuRegister()) << out_reg;
2336  if (null_allowed) {
2337    Mips64Label null_arg;
2338    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2339    // the address in the handle scope holding the reference.
2340    // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2341    if (in_reg.IsNoRegister()) {
2342      LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
2343                     SP, handle_scope_offset.Int32Value());
2344      in_reg = out_reg;
2345    }
2346    if (!out_reg.Equals(in_reg)) {
2347      LoadConst32(out_reg.AsGpuRegister(), 0);
2348    }
2349    Beqzc(in_reg.AsGpuRegister(), &null_arg);
2350    Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2351    Bind(&null_arg);
2352  } else {
2353    Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2354  }
2355}
2356
2357void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
2358                                             FrameOffset handle_scope_offset,
2359                                             ManagedRegister mscratch,
2360                                             bool null_allowed) {
2361  Mips64ManagedRegister scratch = mscratch.AsMips64();
2362  CHECK(scratch.IsGpuRegister()) << scratch;
2363  if (null_allowed) {
2364    Mips64Label null_arg;
2365    LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
2366                   handle_scope_offset.Int32Value());
2367    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
2368    // the address in the handle scope holding the reference.
2369    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
2370    Beqzc(scratch.AsGpuRegister(), &null_arg);
2371    Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2372    Bind(&null_arg);
2373  } else {
2374    Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2375  }
2376  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2377}
2378
2379// Given a handle scope entry, load the associated reference.
2380void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
2381                                                   ManagedRegister min_reg) {
2382  Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2383  Mips64ManagedRegister in_reg = min_reg.AsMips64();
2384  CHECK(out_reg.IsGpuRegister()) << out_reg;
2385  CHECK(in_reg.IsGpuRegister()) << in_reg;
2386  Mips64Label null_arg;
2387  if (!out_reg.Equals(in_reg)) {
2388    LoadConst32(out_reg.AsGpuRegister(), 0);
2389  }
2390  Beqzc(in_reg.AsGpuRegister(), &null_arg);
2391  LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2392                 in_reg.AsGpuRegister(), 0);
2393  Bind(&null_arg);
2394}
2395
2396void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2397                                   bool could_be_null ATTRIBUTE_UNUSED) {
2398  // TODO: not validating references
2399}
2400
2401void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2402                                   bool could_be_null ATTRIBUTE_UNUSED) {
2403  // TODO: not validating references
2404}
2405
2406void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2407  Mips64ManagedRegister base = mbase.AsMips64();
2408  Mips64ManagedRegister scratch = mscratch.AsMips64();
2409  CHECK(base.IsGpuRegister()) << base;
2410  CHECK(scratch.IsGpuRegister()) << scratch;
2411  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2412                 base.AsGpuRegister(), offset.Int32Value());
2413  Jalr(scratch.AsGpuRegister());
2414  Nop();
2415  // TODO: place reference map on call
2416}
2417
2418void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2419  Mips64ManagedRegister scratch = mscratch.AsMips64();
2420  CHECK(scratch.IsGpuRegister()) << scratch;
2421  // Call *(*(SP + base) + offset)
2422  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2423                 SP, base.Int32Value());
2424  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2425                 scratch.AsGpuRegister(), offset.Int32Value());
2426  Jalr(scratch.AsGpuRegister());
2427  Nop();
2428  // TODO: place reference map on call
2429}
2430
2431void Mips64Assembler::CallFromThread64(ThreadOffset<kMips64DoublewordSize> offset ATTRIBUTE_UNUSED,
2432                                       ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2433  UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
2434}
2435
2436void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2437  Move(tr.AsMips64().AsGpuRegister(), S1);
2438}
2439
2440void Mips64Assembler::GetCurrentThread(FrameOffset offset,
2441                                       ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2442  StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2443}
2444
2445void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2446  Mips64ManagedRegister scratch = mscratch.AsMips64();
2447  exception_blocks_.emplace_back(scratch, stack_adjust);
2448  LoadFromOffset(kLoadDoubleword,
2449                 scratch.AsGpuRegister(),
2450                 S1,
2451                 Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value());
2452  Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
2453}
2454
2455void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2456  Bind(exception->Entry());
2457  if (exception->stack_adjust_ != 0) {  // Fix up the frame.
2458    DecreaseFrameSize(exception->stack_adjust_);
2459  }
2460  // Pass exception object as argument.
2461  // Don't care about preserving A0 as this call won't return.
2462  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2463  Move(A0, exception->scratch_.AsGpuRegister());
2464  // Set up call to Thread::Current()->pDeliverException
2465  LoadFromOffset(kLoadDoubleword,
2466                 T9,
2467                 S1,
2468                 QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pDeliverException).Int32Value());
2469  Jr(T9);
2470  Nop();
2471
2472  // Call never returns
2473  Break();
2474}
2475
2476}  // namespace mips64
2477}  // namespace art
2478