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