blob: 6f35e9ef59c5f37f9892f32c4e9e1557cd1c24b1 [file] [log] [blame]
jeffhao7fbee072012-08-24 17:56:54 -07001/*
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
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080020#include "base/casts.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "entrypoints/quick/quick_entrypoints.h"
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020022#include "entrypoints/quick/quick_entrypoints_enum.h"
jeffhao7fbee072012-08-24 17:56:54 -070023#include "memory_region.h"
jeffhao7fbee072012-08-24 17:56:54 -070024#include "thread.h"
25
26namespace art {
27namespace mips {
jeffhao7fbee072012-08-24 17:56:54 -070028
jeffhao7fbee072012-08-24 17:56:54 -070029std::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
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020038void MipsAssembler::FinalizeCode() {
39 for (auto& exception_block : exception_blocks_) {
40 EmitExceptionPoll(&exception_block);
41 }
42 PromoteBranches();
43}
44
45void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
46 EmitBranches();
47 Assembler::FinalizeInstructions(region);
48}
49
50void MipsAssembler::EmitBranches() {
51 CHECK(!overwriting_);
52 // Switch from appending instructions at the end of the buffer to overwriting
53 // existing instructions (branch placeholders) in the buffer.
54 overwriting_ = true;
55 for (auto& branch : branches_) {
56 EmitBranch(&branch);
57 }
58 overwriting_ = false;
59}
60
61void MipsAssembler::Emit(uint32_t value) {
62 if (overwriting_) {
63 // Branches to labels are emitted into their placeholders here.
64 buffer_.Store<uint32_t>(overwrite_location_, value);
65 overwrite_location_ += sizeof(uint32_t);
66 } else {
67 // Other instructions are simply appended at the end here.
68 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
69 buffer_.Emit<uint32_t>(value);
70 }
jeffhao7fbee072012-08-24 17:56:54 -070071}
72
73void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
74 CHECK_NE(rs, kNoRegister);
75 CHECK_NE(rt, kNoRegister);
76 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020077 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
78 static_cast<uint32_t>(rs) << kRsShift |
79 static_cast<uint32_t>(rt) << kRtShift |
80 static_cast<uint32_t>(rd) << kRdShift |
81 shamt << kShamtShift |
82 funct;
jeffhao7fbee072012-08-24 17:56:54 -070083 Emit(encoding);
84}
85
86void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
87 CHECK_NE(rs, kNoRegister);
88 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020089 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
90 static_cast<uint32_t>(rs) << kRsShift |
91 static_cast<uint32_t>(rt) << kRtShift |
92 imm;
jeffhao7fbee072012-08-24 17:56:54 -070093 Emit(encoding);
94}
95
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020096void MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
97 CHECK_NE(rs, kNoRegister);
98 CHECK(IsUint<21>(imm21)) << imm21;
99 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
100 static_cast<uint32_t>(rs) << kRsShift |
101 imm21;
jeffhao7fbee072012-08-24 17:56:54 -0700102 Emit(encoding);
103}
104
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200105void MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
106 CHECK(IsUint<26>(imm26)) << imm26;
107 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
108 Emit(encoding);
109}
110
111void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd,
112 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700113 CHECK_NE(ft, kNoFRegister);
114 CHECK_NE(fs, kNoFRegister);
115 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200116 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
117 fmt << kFmtShift |
118 static_cast<uint32_t>(ft) << kFtShift |
119 static_cast<uint32_t>(fs) << kFsShift |
120 static_cast<uint32_t>(fd) << kFdShift |
121 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700122 Emit(encoding);
123}
124
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200125void MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
126 CHECK_NE(ft, kNoFRegister);
127 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
128 fmt << kFmtShift |
129 static_cast<uint32_t>(ft) << kFtShift |
130 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700131 Emit(encoding);
132}
133
jeffhao7fbee072012-08-24 17:56:54 -0700134void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
135 EmitR(0, rs, rt, rd, 0, 0x21);
136}
137
jeffhao7fbee072012-08-24 17:56:54 -0700138void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
139 EmitI(0x9, rs, rt, imm16);
140}
141
jeffhao7fbee072012-08-24 17:56:54 -0700142void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
143 EmitR(0, rs, rt, rd, 0, 0x23);
144}
145
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200146void MipsAssembler::MultR2(Register rs, Register rt) {
147 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700148 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
149}
150
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200151void MipsAssembler::MultuR2(Register rs, Register rt) {
152 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700153 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
154}
155
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200156void MipsAssembler::DivR2(Register rs, Register rt) {
157 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700158 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
159}
160
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200161void MipsAssembler::DivuR2(Register rs, Register rt) {
162 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700163 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
164}
165
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200166void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
167 CHECK(!IsR6());
168 EmitR(0x1c, rs, rt, rd, 0, 2);
169}
170
171void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
172 CHECK(!IsR6());
173 DivR2(rs, rt);
174 Mflo(rd);
175}
176
177void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
178 CHECK(!IsR6());
179 DivR2(rs, rt);
180 Mfhi(rd);
181}
182
183void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
184 CHECK(!IsR6());
185 DivuR2(rs, rt);
186 Mflo(rd);
187}
188
189void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
190 CHECK(!IsR6());
191 DivuR2(rs, rt);
192 Mfhi(rd);
193}
194
195void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
196 CHECK(IsR6());
197 EmitR(0, rs, rt, rd, 2, 0x18);
198}
199
200void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
201 CHECK(IsR6());
202 EmitR(0, rs, rt, rd, 3, 0x19);
203}
204
205void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
206 CHECK(IsR6());
207 EmitR(0, rs, rt, rd, 2, 0x1a);
208}
209
210void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
211 CHECK(IsR6());
212 EmitR(0, rs, rt, rd, 3, 0x1a);
213}
214
215void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
216 CHECK(IsR6());
217 EmitR(0, rs, rt, rd, 2, 0x1b);
218}
219
220void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
221 CHECK(IsR6());
222 EmitR(0, rs, rt, rd, 3, 0x1b);
223}
224
jeffhao7fbee072012-08-24 17:56:54 -0700225void MipsAssembler::And(Register rd, Register rs, Register rt) {
226 EmitR(0, rs, rt, rd, 0, 0x24);
227}
228
229void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
230 EmitI(0xc, rs, rt, imm16);
231}
232
233void MipsAssembler::Or(Register rd, Register rs, Register rt) {
234 EmitR(0, rs, rt, rd, 0, 0x25);
235}
236
237void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
238 EmitI(0xd, rs, rt, imm16);
239}
240
241void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
242 EmitR(0, rs, rt, rd, 0, 0x26);
243}
244
245void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
246 EmitI(0xe, rs, rt, imm16);
247}
248
249void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
250 EmitR(0, rs, rt, rd, 0, 0x27);
251}
252
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200253void MipsAssembler::Seb(Register rd, Register rt) {
254 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700255}
256
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200257void MipsAssembler::Seh(Register rd, Register rt) {
258 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700259}
260
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200261void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
262 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00);
jeffhao7fbee072012-08-24 17:56:54 -0700263}
264
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200265void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
266 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02);
267}
268
269void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
270 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03);
271}
272
273void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700274 EmitR(0, rs, rt, rd, 0, 0x04);
275}
276
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200277void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700278 EmitR(0, rs, rt, rd, 0, 0x06);
279}
280
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200281void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700282 EmitR(0, rs, rt, rd, 0, 0x07);
283}
284
285void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
286 EmitI(0x20, rs, rt, imm16);
287}
288
289void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
290 EmitI(0x21, rs, rt, imm16);
291}
292
293void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
294 EmitI(0x23, rs, rt, imm16);
295}
296
297void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
298 EmitI(0x24, rs, rt, imm16);
299}
300
301void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
302 EmitI(0x25, rs, rt, imm16);
303}
304
305void MipsAssembler::Lui(Register rt, uint16_t imm16) {
306 EmitI(0xf, static_cast<Register>(0), rt, imm16);
307}
308
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200309void MipsAssembler::Sync(uint32_t stype) {
310 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0),
311 stype & 0x1f, 0xf);
312}
313
jeffhao7fbee072012-08-24 17:56:54 -0700314void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200315 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700316 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
317}
318
319void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200320 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700321 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
322}
323
324void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
325 EmitI(0x28, rs, rt, imm16);
326}
327
328void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
329 EmitI(0x29, rs, rt, imm16);
330}
331
332void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
333 EmitI(0x2b, rs, rt, imm16);
334}
335
336void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
337 EmitR(0, rs, rt, rd, 0, 0x2a);
338}
339
340void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
341 EmitR(0, rs, rt, rd, 0, 0x2b);
342}
343
344void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
345 EmitI(0xa, rs, rt, imm16);
346}
347
348void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
349 EmitI(0xb, rs, rt, imm16);
350}
351
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200352void MipsAssembler::B(uint16_t imm16) {
353 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
354}
355
356void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700357 EmitI(0x4, rs, rt, imm16);
358}
359
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200360void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700361 EmitI(0x5, rs, rt, imm16);
362}
363
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200364void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
365 Beq(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700366}
367
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200368void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
369 Bne(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700370}
371
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
373 EmitI(0x1, rt, static_cast<Register>(0), imm16);
374}
375
376void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
377 EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
378}
379
380void MipsAssembler::Blez(Register rt, uint16_t imm16) {
381 EmitI(0x6, rt, static_cast<Register>(0), imm16);
382}
383
384void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
385 EmitI(0x7, rt, static_cast<Register>(0), imm16);
386}
387
388void MipsAssembler::J(uint32_t addr26) {
389 EmitI26(0x2, addr26);
390}
391
392void MipsAssembler::Jal(uint32_t addr26) {
393 EmitI26(0x3, addr26);
394}
395
396void MipsAssembler::Jalr(Register rd, Register rs) {
397 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
jeffhao7fbee072012-08-24 17:56:54 -0700398}
399
400void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200401 Jalr(RA, rs);
402}
403
404void MipsAssembler::Jr(Register rs) {
405 Jalr(ZERO, rs);
406}
407
408void MipsAssembler::Nal() {
409 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
410}
411
412void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
413 CHECK(IsR6());
414 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
415}
416
417void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
418 CHECK(IsR6());
419 CHECK(IsUint<19>(imm19)) << imm19;
420 EmitI21(0x3B, rs, imm19);
421}
422
423void MipsAssembler::Bc(uint32_t imm26) {
424 CHECK(IsR6());
425 EmitI26(0x32, imm26);
426}
427
428void MipsAssembler::Jic(Register rt, uint16_t imm16) {
429 CHECK(IsR6());
430 EmitI(0x36, static_cast<Register>(0), rt, imm16);
431}
432
433void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
434 CHECK(IsR6());
435 EmitI(0x3E, static_cast<Register>(0), rt, imm16);
436}
437
438void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
439 CHECK(IsR6());
440 CHECK_NE(rs, ZERO);
441 CHECK_NE(rt, ZERO);
442 CHECK_NE(rs, rt);
443 EmitI(0x17, rs, rt, imm16);
444}
445
446void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
447 CHECK(IsR6());
448 CHECK_NE(rt, ZERO);
449 EmitI(0x17, rt, rt, imm16);
450}
451
452void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
453 CHECK(IsR6());
454 CHECK_NE(rt, ZERO);
455 EmitI(0x17, static_cast<Register>(0), rt, imm16);
456}
457
458void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
459 CHECK(IsR6());
460 CHECK_NE(rs, ZERO);
461 CHECK_NE(rt, ZERO);
462 CHECK_NE(rs, rt);
463 EmitI(0x16, rs, rt, imm16);
464}
465
466void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
467 CHECK(IsR6());
468 CHECK_NE(rt, ZERO);
469 EmitI(0x16, rt, rt, imm16);
470}
471
472void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
473 CHECK(IsR6());
474 CHECK_NE(rt, ZERO);
475 EmitI(0x16, static_cast<Register>(0), rt, imm16);
476}
477
478void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
479 CHECK(IsR6());
480 CHECK_NE(rs, ZERO);
481 CHECK_NE(rt, ZERO);
482 CHECK_NE(rs, rt);
483 EmitI(0x7, rs, rt, imm16);
484}
485
486void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
487 CHECK(IsR6());
488 CHECK_NE(rs, ZERO);
489 CHECK_NE(rt, ZERO);
490 CHECK_NE(rs, rt);
491 EmitI(0x6, rs, rt, imm16);
492}
493
494void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
495 CHECK(IsR6());
496 CHECK_NE(rs, ZERO);
497 CHECK_NE(rt, ZERO);
498 CHECK_NE(rs, rt);
499 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
500}
501
502void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
503 CHECK(IsR6());
504 CHECK_NE(rs, ZERO);
505 CHECK_NE(rt, ZERO);
506 CHECK_NE(rs, rt);
507 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
508}
509
510void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
511 CHECK(IsR6());
512 CHECK_NE(rs, ZERO);
513 EmitI21(0x36, rs, imm21);
514}
515
516void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
517 CHECK(IsR6());
518 CHECK_NE(rs, ZERO);
519 EmitI21(0x3E, rs, imm21);
520}
521
522void MipsAssembler::EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
523 switch (cond) {
524 case kCondLTZ:
525 CHECK_EQ(rt, ZERO);
526 Bltz(rs, imm16);
527 break;
528 case kCondGEZ:
529 CHECK_EQ(rt, ZERO);
530 Bgez(rs, imm16);
531 break;
532 case kCondLEZ:
533 CHECK_EQ(rt, ZERO);
534 Blez(rs, imm16);
535 break;
536 case kCondGTZ:
537 CHECK_EQ(rt, ZERO);
538 Bgtz(rs, imm16);
539 break;
540 case kCondEQ:
541 Beq(rs, rt, imm16);
542 break;
543 case kCondNE:
544 Bne(rs, rt, imm16);
545 break;
546 case kCondEQZ:
547 CHECK_EQ(rt, ZERO);
548 Beqz(rs, imm16);
549 break;
550 case kCondNEZ:
551 CHECK_EQ(rt, ZERO);
552 Bnez(rs, imm16);
553 break;
554 case kCondLT:
555 case kCondGE:
556 case kCondLE:
557 case kCondGT:
558 case kCondLTU:
559 case kCondGEU:
560 case kUncond:
561 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
562 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
563 LOG(FATAL) << "Unexpected branch condition " << cond;
564 UNREACHABLE();
565 }
566}
567
568void MipsAssembler::EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
569 switch (cond) {
570 case kCondLT:
571 Bltc(rs, rt, imm16_21);
572 break;
573 case kCondGE:
574 Bgec(rs, rt, imm16_21);
575 break;
576 case kCondLE:
577 Bgec(rt, rs, imm16_21);
578 break;
579 case kCondGT:
580 Bltc(rt, rs, imm16_21);
581 break;
582 case kCondLTZ:
583 CHECK_EQ(rt, ZERO);
584 Bltzc(rs, imm16_21);
585 break;
586 case kCondGEZ:
587 CHECK_EQ(rt, ZERO);
588 Bgezc(rs, imm16_21);
589 break;
590 case kCondLEZ:
591 CHECK_EQ(rt, ZERO);
592 Blezc(rs, imm16_21);
593 break;
594 case kCondGTZ:
595 CHECK_EQ(rt, ZERO);
596 Bgtzc(rs, imm16_21);
597 break;
598 case kCondEQ:
599 Beqc(rs, rt, imm16_21);
600 break;
601 case kCondNE:
602 Bnec(rs, rt, imm16_21);
603 break;
604 case kCondEQZ:
605 CHECK_EQ(rt, ZERO);
606 Beqzc(rs, imm16_21);
607 break;
608 case kCondNEZ:
609 CHECK_EQ(rt, ZERO);
610 Bnezc(rs, imm16_21);
611 break;
612 case kCondLTU:
613 Bltuc(rs, rt, imm16_21);
614 break;
615 case kCondGEU:
616 Bgeuc(rs, rt, imm16_21);
617 break;
618 case kUncond:
619 LOG(FATAL) << "Unexpected branch condition " << cond;
620 UNREACHABLE();
621 }
jeffhao7fbee072012-08-24 17:56:54 -0700622}
623
624void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
625 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
626}
627
628void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
629 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
630}
631
632void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
633 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
634}
635
636void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
637 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
638}
639
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200640void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
641 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700642}
643
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200644void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
645 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
jeffhao7fbee072012-08-24 17:56:54 -0700646}
647
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200648void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
649 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
jeffhao7fbee072012-08-24 17:56:54 -0700650}
651
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200652void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
653 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
jeffhao7fbee072012-08-24 17:56:54 -0700654}
655
656void MipsAssembler::MovS(FRegister fd, FRegister fs) {
657 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
658}
659
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200660void MipsAssembler::MovD(FRegister fd, FRegister fs) {
661 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
662}
663
664void MipsAssembler::NegS(FRegister fd, FRegister fs) {
665 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
666}
667
668void MipsAssembler::NegD(FRegister fd, FRegister fs) {
669 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
670}
671
672void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
673 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
674}
675
676void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
677 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
678}
679
680void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
681 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
682}
683
684void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
685 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
jeffhao7fbee072012-08-24 17:56:54 -0700686}
687
688void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200689 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700690}
691
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200692void MipsAssembler::Mtc1(Register rt, FRegister fs) {
693 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
694}
695
696void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
697 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
698}
699
700void MipsAssembler::Mthc1(Register rt, FRegister fs) {
701 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700702}
703
704void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200705 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700706}
707
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200708void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
709 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700710}
711
712void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200713 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700714}
715
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200716void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
717 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700718}
719
720void MipsAssembler::Break() {
721 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
722 static_cast<Register>(0), 0, 0xD);
723}
724
jeffhao07030602012-09-26 14:33:14 -0700725void MipsAssembler::Nop() {
726 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
727}
728
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200729void MipsAssembler::Move(Register rd, Register rs) {
730 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700731}
732
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200733void MipsAssembler::Clear(Register rd) {
734 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700735}
736
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200737void MipsAssembler::Not(Register rd, Register rs) {
738 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700739}
740
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200741void MipsAssembler::Push(Register rs) {
742 IncreaseFrameSize(kMipsWordSize);
743 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -0700744}
745
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200746void MipsAssembler::Pop(Register rd) {
747 Lw(rd, SP, 0);
748 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -0700749}
750
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200751void MipsAssembler::PopAndReturn(Register rd, Register rt) {
752 Lw(rd, SP, 0);
753 Jr(rt);
754 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -0700755}
756
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200757void MipsAssembler::LoadConst32(Register rd, int32_t value) {
758 if (IsUint<16>(value)) {
759 // Use OR with (unsigned) immediate to encode 16b unsigned int.
760 Ori(rd, ZERO, value);
761 } else if (IsInt<16>(value)) {
762 // Use ADD with (signed) immediate to encode 16b signed int.
763 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -0700764 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200765 Lui(rd, High16Bits(value));
766 if (value & 0xFFFF)
767 Ori(rd, rd, Low16Bits(value));
768 }
769}
770
771void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
772 LoadConst32(reg_lo, Low32Bits(value));
773 LoadConst32(reg_hi, High32Bits(value));
774}
775
776void MipsAssembler::StoreConst32ToOffset(int32_t value,
777 Register base,
778 int32_t offset,
779 Register temp) {
780 if (!IsInt<16>(offset)) {
781 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
782 LoadConst32(AT, offset);
783 Addu(AT, AT, base);
784 base = AT;
785 offset = 0;
786 }
787 LoadConst32(temp, value);
788 Sw(temp, base, offset);
789}
790
791void MipsAssembler::StoreConst64ToOffset(int64_t value,
792 Register base,
793 int32_t offset,
794 Register temp) {
795 // IsInt<16> must be passed a signed value.
796 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
797 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
798 LoadConst32(AT, offset);
799 Addu(AT, AT, base);
800 base = AT;
801 offset = 0;
802 }
803 LoadConst32(temp, Low32Bits(value));
804 Sw(temp, base, offset);
805 LoadConst32(temp, High32Bits(value));
806 Sw(temp, base, offset + kMipsWordSize);
807}
808
809void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
810 LoadConst32(temp, value);
811 Mtc1(temp, r);
812}
813
814void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
815 LoadConst32(temp, Low32Bits(value));
816 Mtc1(temp, rd);
817 LoadConst32(temp, High32Bits(value));
818 Mthc1(temp, rd);
819}
820
821void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
822 if (IsInt<16>(value)) {
823 Addiu(rt, rs, value);
824 } else {
825 LoadConst32(temp, value);
826 Addu(rt, rs, temp);
827 }
828}
829
830void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
831 MipsAssembler::Branch::Type short_type,
832 MipsAssembler::Branch::Type long_type) {
833 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
834}
835
836void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
837 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
838 if (is_r6) {
839 // R6
840 if (is_call) {
841 InitShortOrLong(offset_size, kR6Call, kR6LongCall);
842 } else if (condition_ == kUncond) {
843 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
844 } else {
845 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
846 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
847 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
848 } else {
849 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
850 }
851 }
852 } else {
853 // R2
854 if (is_call) {
855 InitShortOrLong(offset_size, kCall, kLongCall);
856 } else if (condition_ == kUncond) {
857 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
858 } else {
859 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
860 }
861 }
862 old_type_ = type_;
863}
864
865bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
866 switch (condition) {
867 case kCondLT:
868 case kCondGT:
869 case kCondNE:
870 case kCondLTU:
871 return lhs == rhs;
872 default:
873 return false;
874 }
875}
876
877bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
878 switch (condition) {
879 case kUncond:
880 return true;
881 case kCondGE:
882 case kCondLE:
883 case kCondEQ:
884 case kCondGEU:
885 return lhs == rhs;
886 default:
887 return false;
888 }
889}
890
891MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
892 : old_location_(location),
893 location_(location),
894 target_(target),
895 lhs_reg_(0),
896 rhs_reg_(0),
897 condition_(kUncond) {
898 InitializeType(false, is_r6);
899}
900
901MipsAssembler::Branch::Branch(bool is_r6,
902 uint32_t location,
903 uint32_t target,
904 MipsAssembler::BranchCondition condition,
905 Register lhs_reg,
906 Register rhs_reg)
907 : old_location_(location),
908 location_(location),
909 target_(target),
910 lhs_reg_(lhs_reg),
911 rhs_reg_(rhs_reg),
912 condition_(condition) {
913 CHECK_NE(condition, kUncond);
914 switch (condition) {
915 case kCondLT:
916 case kCondGE:
917 case kCondLE:
918 case kCondGT:
919 case kCondLTU:
920 case kCondGEU:
921 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
922 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
923 // We leave this up to the caller.
924 CHECK(is_r6);
925 FALLTHROUGH_INTENDED;
926 case kCondEQ:
927 case kCondNE:
928 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
929 // To compare with 0, use dedicated kCond*Z conditions.
930 CHECK_NE(lhs_reg, ZERO);
931 CHECK_NE(rhs_reg, ZERO);
932 break;
933 case kCondLTZ:
934 case kCondGEZ:
935 case kCondLEZ:
936 case kCondGTZ:
937 case kCondEQZ:
938 case kCondNEZ:
939 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
940 CHECK_NE(lhs_reg, ZERO);
941 CHECK_EQ(rhs_reg, ZERO);
942 break;
943 case kUncond:
944 UNREACHABLE();
945 }
946 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
947 if (IsUncond(condition, lhs_reg, rhs_reg)) {
948 // Branch condition is always true, make the branch unconditional.
949 condition_ = kUncond;
950 }
951 InitializeType(false, is_r6);
952}
953
954MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
955 : old_location_(location),
956 location_(location),
957 target_(target),
958 lhs_reg_(indirect_reg),
959 rhs_reg_(0),
960 condition_(kUncond) {
961 CHECK_NE(indirect_reg, ZERO);
962 CHECK_NE(indirect_reg, AT);
963 InitializeType(true, is_r6);
964}
965
966MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
967 MipsAssembler::BranchCondition cond) {
968 switch (cond) {
969 case kCondLT:
970 return kCondGE;
971 case kCondGE:
972 return kCondLT;
973 case kCondLE:
974 return kCondGT;
975 case kCondGT:
976 return kCondLE;
977 case kCondLTZ:
978 return kCondGEZ;
979 case kCondGEZ:
980 return kCondLTZ;
981 case kCondLEZ:
982 return kCondGTZ;
983 case kCondGTZ:
984 return kCondLEZ;
985 case kCondEQ:
986 return kCondNE;
987 case kCondNE:
988 return kCondEQ;
989 case kCondEQZ:
990 return kCondNEZ;
991 case kCondNEZ:
992 return kCondEQZ;
993 case kCondLTU:
994 return kCondGEU;
995 case kCondGEU:
996 return kCondLTU;
997 case kUncond:
998 LOG(FATAL) << "Unexpected branch condition " << cond;
999 }
1000 UNREACHABLE();
1001}
1002
1003MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1004 return type_;
1005}
1006
1007MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1008 return condition_;
1009}
1010
1011Register MipsAssembler::Branch::GetLeftRegister() const {
1012 return static_cast<Register>(lhs_reg_);
1013}
1014
1015Register MipsAssembler::Branch::GetRightRegister() const {
1016 return static_cast<Register>(rhs_reg_);
1017}
1018
1019uint32_t MipsAssembler::Branch::GetTarget() const {
1020 return target_;
1021}
1022
1023uint32_t MipsAssembler::Branch::GetLocation() const {
1024 return location_;
1025}
1026
1027uint32_t MipsAssembler::Branch::GetOldLocation() const {
1028 return old_location_;
1029}
1030
1031uint32_t MipsAssembler::Branch::GetLength() const {
1032 return branch_info_[type_].length;
1033}
1034
1035uint32_t MipsAssembler::Branch::GetOldLength() const {
1036 return branch_info_[old_type_].length;
1037}
1038
1039uint32_t MipsAssembler::Branch::GetSize() const {
1040 return GetLength() * sizeof(uint32_t);
1041}
1042
1043uint32_t MipsAssembler::Branch::GetOldSize() const {
1044 return GetOldLength() * sizeof(uint32_t);
1045}
1046
1047uint32_t MipsAssembler::Branch::GetEndLocation() const {
1048 return GetLocation() + GetSize();
1049}
1050
1051uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1052 return GetOldLocation() + GetOldSize();
1053}
1054
1055bool MipsAssembler::Branch::IsLong() const {
1056 switch (type_) {
1057 // R2 short branches.
1058 case kUncondBranch:
1059 case kCondBranch:
1060 case kCall:
1061 // R6 short branches.
1062 case kR6UncondBranch:
1063 case kR6CondBranch:
1064 case kR6Call:
1065 return false;
1066 // R2 long branches.
1067 case kLongUncondBranch:
1068 case kLongCondBranch:
1069 case kLongCall:
1070 // R6 long branches.
1071 case kR6LongUncondBranch:
1072 case kR6LongCondBranch:
1073 case kR6LongCall:
1074 return true;
1075 }
1076 UNREACHABLE();
1077}
1078
1079bool MipsAssembler::Branch::IsResolved() const {
1080 return target_ != kUnresolved;
1081}
1082
1083MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1084 OffsetBits offset_size =
1085 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1086 ? kOffset23
1087 : branch_info_[type_].offset_size;
1088 return offset_size;
1089}
1090
1091MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1092 uint32_t target) {
1093 // For unresolved targets assume the shortest encoding
1094 // (later it will be made longer if needed).
1095 if (target == kUnresolved)
1096 return kOffset16;
1097 int64_t distance = static_cast<int64_t>(target) - location;
1098 // To simplify calculations in composite branches consisting of multiple instructions
1099 // bump up the distance by a value larger than the max byte size of a composite branch.
1100 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1101 if (IsInt<kOffset16>(distance))
1102 return kOffset16;
1103 else if (IsInt<kOffset18>(distance))
1104 return kOffset18;
1105 else if (IsInt<kOffset21>(distance))
1106 return kOffset21;
1107 else if (IsInt<kOffset23>(distance))
1108 return kOffset23;
1109 else if (IsInt<kOffset28>(distance))
1110 return kOffset28;
1111 return kOffset32;
1112}
1113
1114void MipsAssembler::Branch::Resolve(uint32_t target) {
1115 target_ = target;
1116}
1117
1118void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1119 if (location_ > expand_location) {
1120 location_ += delta;
1121 }
1122 if (!IsResolved()) {
1123 return; // Don't know the target yet.
1124 }
1125 if (target_ > expand_location) {
1126 target_ += delta;
1127 }
1128}
1129
1130void MipsAssembler::Branch::PromoteToLong() {
1131 switch (type_) {
1132 // R2 short branches.
1133 case kUncondBranch:
1134 type_ = kLongUncondBranch;
1135 break;
1136 case kCondBranch:
1137 type_ = kLongCondBranch;
1138 break;
1139 case kCall:
1140 type_ = kLongCall;
1141 break;
1142 // R6 short branches.
1143 case kR6UncondBranch:
1144 type_ = kR6LongUncondBranch;
1145 break;
1146 case kR6CondBranch:
1147 type_ = kR6LongCondBranch;
1148 break;
1149 case kR6Call:
1150 type_ = kR6LongCall;
1151 break;
1152 default:
1153 // Note: 'type_' is already long.
1154 break;
1155 }
1156 CHECK(IsLong());
1157}
1158
1159uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1160 // If the branch is still unresolved or already long, nothing to do.
1161 if (IsLong() || !IsResolved()) {
1162 return 0;
1163 }
1164 // Promote the short branch to long if the offset size is too small
1165 // to hold the distance between location_ and target_.
1166 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1167 PromoteToLong();
1168 uint32_t old_size = GetOldSize();
1169 uint32_t new_size = GetSize();
1170 CHECK_GT(new_size, old_size);
1171 return new_size - old_size;
1172 }
1173 // The following logic is for debugging/testing purposes.
1174 // Promote some short branches to long when it's not really required.
1175 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1176 int64_t distance = static_cast<int64_t>(target_) - location_;
1177 distance = (distance >= 0) ? distance : -distance;
1178 if (distance >= max_short_distance) {
1179 PromoteToLong();
1180 uint32_t old_size = GetOldSize();
1181 uint32_t new_size = GetSize();
1182 CHECK_GT(new_size, old_size);
1183 return new_size - old_size;
1184 }
1185 }
1186 return 0;
1187}
1188
1189uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1190 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1191}
1192
1193uint32_t MipsAssembler::Branch::GetOffset() const {
1194 CHECK(IsResolved());
1195 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1196 // Calculate the byte distance between instructions and also account for
1197 // different PC-relative origins.
1198 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1199 // Prepare the offset for encoding into the instruction(s).
1200 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1201 return offset;
1202}
1203
1204MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1205 CHECK_LT(branch_id, branches_.size());
1206 return &branches_[branch_id];
1207}
1208
1209const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1210 CHECK_LT(branch_id, branches_.size());
1211 return &branches_[branch_id];
1212}
1213
1214void MipsAssembler::Bind(MipsLabel* label) {
1215 CHECK(!label->IsBound());
1216 uint32_t bound_pc = buffer_.Size();
1217
1218 // Walk the list of branches referring to and preceding this label.
1219 // Store the previously unknown target addresses in them.
1220 while (label->IsLinked()) {
1221 uint32_t branch_id = label->Position();
1222 Branch* branch = GetBranch(branch_id);
1223 branch->Resolve(bound_pc);
1224
1225 uint32_t branch_location = branch->GetLocation();
1226 // Extract the location of the previous branch in the list (walking the list backwards;
1227 // the previous branch ID was stored in the space reserved for this branch).
1228 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1229
1230 // On to the previous branch in the list...
1231 label->position_ = prev;
1232 }
1233
1234 // Now make the label object contain its own location (relative to the end of the preceding
1235 // branch, if any; it will be used by the branches referring to and following this label).
1236 label->prev_branch_id_plus_one_ = branches_.size();
1237 if (label->prev_branch_id_plus_one_) {
1238 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1239 const Branch* branch = GetBranch(branch_id);
1240 bound_pc -= branch->GetEndLocation();
1241 }
1242 label->BindTo(bound_pc);
1243}
1244
1245uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1246 CHECK(label->IsBound());
1247 uint32_t target = label->Position();
1248 if (label->prev_branch_id_plus_one_) {
1249 // Get label location based on the branch preceding it.
1250 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1251 const Branch* branch = GetBranch(branch_id);
1252 target += branch->GetEndLocation();
1253 }
1254 return target;
1255}
1256
1257uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1258 // We can reconstruct the adjustment by going through all the branches from the beginning
1259 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1260 // with increasing old_position, we can use the data from last AdjustedPosition() to
1261 // continue where we left off and the whole loop should be O(m+n) where m is the number
1262 // of positions to adjust and n is the number of branches.
1263 if (old_position < last_old_position_) {
1264 last_position_adjustment_ = 0;
1265 last_old_position_ = 0;
1266 last_branch_id_ = 0;
1267 }
1268 while (last_branch_id_ != branches_.size()) {
1269 const Branch* branch = GetBranch(last_branch_id_);
1270 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1271 break;
1272 }
1273 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1274 ++last_branch_id_;
1275 }
1276 last_old_position_ = old_position;
1277 return old_position + last_position_adjustment_;
1278}
1279
1280void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1281 uint32_t length = branches_.back().GetLength();
1282 if (!label->IsBound()) {
1283 // Branch forward (to a following label), distance is unknown.
1284 // The first branch forward will contain 0, serving as the terminator of
1285 // the list of forward-reaching branches.
1286 Emit(label->position_);
1287 length--;
1288 // Now make the label object point to this branch
1289 // (this forms a linked list of branches preceding this label).
1290 uint32_t branch_id = branches_.size() - 1;
1291 label->LinkTo(branch_id);
1292 }
1293 // Reserve space for the branch.
1294 while (length--) {
1295 Nop();
1296 }
1297}
1298
1299void MipsAssembler::Buncond(MipsLabel* label) {
1300 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1301 branches_.emplace_back(IsR6(), buffer_.Size(), target);
1302 FinalizeLabeledBranch(label);
1303}
1304
1305void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1306 // If lhs = rhs, this can be a NOP.
1307 if (Branch::IsNop(condition, lhs, rhs)) {
1308 return;
1309 }
1310 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1311 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1312 FinalizeLabeledBranch(label);
1313}
1314
1315void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1316 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1317 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1318 FinalizeLabeledBranch(label);
1319}
1320
1321void MipsAssembler::PromoteBranches() {
1322 // Promote short branches to long as necessary.
1323 bool changed;
1324 do {
1325 changed = false;
1326 for (auto& branch : branches_) {
1327 CHECK(branch.IsResolved());
1328 uint32_t delta = branch.PromoteIfNeeded();
1329 // If this branch has been promoted and needs to expand in size,
1330 // relocate all branches by the expansion size.
1331 if (delta) {
1332 changed = true;
1333 uint32_t expand_location = branch.GetLocation();
1334 for (auto& branch2 : branches_) {
1335 branch2.Relocate(expand_location, delta);
1336 }
1337 }
1338 }
1339 } while (changed);
1340
1341 // Account for branch expansion by resizing the code buffer
1342 // and moving the code in it to its final location.
1343 size_t branch_count = branches_.size();
1344 if (branch_count > 0) {
1345 // Resize.
1346 Branch& last_branch = branches_[branch_count - 1];
1347 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1348 uint32_t old_size = buffer_.Size();
1349 buffer_.Resize(old_size + size_delta);
1350 // Move the code residing between branch placeholders.
1351 uint32_t end = old_size;
1352 for (size_t i = branch_count; i > 0; ) {
1353 Branch& branch = branches_[--i];
1354 uint32_t size = end - branch.GetOldEndLocation();
1355 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1356 end = branch.GetOldLocation();
1357 }
1358 }
1359}
1360
1361// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1362const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
1363 // R2 short branches.
1364 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
1365 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
1366 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall
1367 // R2 long branches.
1368 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1369 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
1370 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
1371 // R6 short branches.
1372 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
1373 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
1374 // Exception: kOffset23 for beqzc/bnezc.
1375 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call
1376 // R6 long branches.
1377 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
1378 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
1379 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
1380};
1381
1382// Note: make sure branch_info_[] and mitBranch() are kept synchronized.
1383void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
1384 CHECK_EQ(overwriting_, true);
1385 overwrite_location_ = branch->GetLocation();
1386 uint32_t offset = branch->GetOffset();
1387 BranchCondition condition = branch->GetCondition();
1388 Register lhs = branch->GetLeftRegister();
1389 Register rhs = branch->GetRightRegister();
1390 switch (branch->GetType()) {
1391 // R2 short branches.
1392 case Branch::kUncondBranch:
1393 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1394 B(offset);
1395 Nop(); // TODO: improve by filling the delay slot.
1396 break;
1397 case Branch::kCondBranch:
1398 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1399 EmitBcond(condition, lhs, rhs, offset);
1400 Nop(); // TODO: improve by filling the delay slot.
1401 break;
1402 case Branch::kCall:
1403 Nal();
1404 Nop(); // TODO: is this NOP really needed here?
1405 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1406 Addiu(lhs, RA, offset);
1407 Jalr(lhs);
1408 Nop();
1409 break;
1410
1411 // R2 long branches.
1412 case Branch::kLongUncondBranch:
1413 // To get the value of the PC register we need to use the NAL instruction.
1414 // NAL clobbers the RA register. However, RA must be preserved if the
1415 // method is compiled without the entry/exit sequences that would take care
1416 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
1417 // So, we need to preserve RA in some temporary storage ourselves. The AT
1418 // register can't be used for this because we need it to load a constant
1419 // which will be added to the value that NAL stores in RA. And we can't
1420 // use T9 for this in the context of the JNI compiler, which uses it
1421 // as a scratch register (see InterproceduralScratchRegister()).
1422 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
1423 // we'd also need to use the ROTR instruction, which requires no less than
1424 // MIPSR2.
1425 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
1426 // (LO or HI) or even a floating-point register, but that doesn't seem
1427 // like a nice solution. We may want this to work on both R6 and pre-R6.
1428 // For now simply use the stack for RA. This should be OK since for the
1429 // vast majority of code a short PC-relative branch is sufficient.
1430 // TODO: can this be improved?
1431 Push(RA);
1432 Nal();
1433 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1434 Lui(AT, High16Bits(offset));
1435 Ori(AT, AT, Low16Bits(offset));
1436 Addu(AT, AT, RA);
1437 Lw(RA, SP, 0);
1438 Jr(AT);
1439 DecreaseFrameSize(kMipsWordSize);
1440 break;
1441 case Branch::kLongCondBranch:
1442 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
1443 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
1444 // number of instructions skipped:
1445 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
1446 EmitBcond(Branch::OppositeCondition(condition), lhs, rhs, 8);
1447 Push(RA);
1448 Nal();
1449 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1450 Lui(AT, High16Bits(offset));
1451 Ori(AT, AT, Low16Bits(offset));
1452 Addu(AT, AT, RA);
1453 Lw(RA, SP, 0);
1454 Jr(AT);
1455 DecreaseFrameSize(kMipsWordSize);
1456 break;
1457 case Branch::kLongCall:
1458 Nal();
1459 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1460 Lui(AT, High16Bits(offset));
1461 Ori(AT, AT, Low16Bits(offset));
1462 Addu(lhs, AT, RA);
1463 Jalr(lhs);
1464 Nop();
1465 break;
1466
1467 // R6 short branches.
1468 case Branch::kR6UncondBranch:
1469 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1470 Bc(offset);
1471 break;
1472 case Branch::kR6CondBranch:
1473 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1474 EmitBcondc(condition, lhs, rhs, offset);
1475 Nop(); // TODO: improve by filling the forbidden slot.
1476 break;
1477 case Branch::kR6Call:
1478 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1479 Addiupc(lhs, offset);
1480 Jialc(lhs, 0);
1481 break;
1482
1483 // R6 long branches.
1484 case Branch::kR6LongUncondBranch:
1485 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1486 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1487 Auipc(AT, High16Bits(offset));
1488 Jic(AT, Low16Bits(offset));
1489 break;
1490 case Branch::kR6LongCondBranch:
1491 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1492 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1493 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1494 Auipc(AT, High16Bits(offset));
1495 Jic(AT, Low16Bits(offset));
1496 break;
1497 case Branch::kR6LongCall:
1498 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
1499 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1500 Auipc(lhs, High16Bits(offset));
1501 Addiu(lhs, lhs, Low16Bits(offset));
1502 Jialc(lhs, 0);
1503 break;
1504 }
1505 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1506 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
1507}
1508
1509void MipsAssembler::B(MipsLabel* label) {
1510 Buncond(label);
1511}
1512
1513void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
1514 Call(label, indirect_reg);
1515}
1516
1517void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
1518 Bcond(label, kCondEQ, rs, rt);
1519}
1520
1521void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
1522 Bcond(label, kCondNE, rs, rt);
1523}
1524
1525void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
1526 Bcond(label, kCondEQZ, rt);
1527}
1528
1529void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
1530 Bcond(label, kCondNEZ, rt);
1531}
1532
1533void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
1534 Bcond(label, kCondLTZ, rt);
1535}
1536
1537void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
1538 Bcond(label, kCondGEZ, rt);
1539}
1540
1541void MipsAssembler::Blez(Register rt, MipsLabel* label) {
1542 Bcond(label, kCondLEZ, rt);
1543}
1544
1545void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
1546 Bcond(label, kCondGTZ, rt);
1547}
1548
1549void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
1550 if (IsR6()) {
1551 Bcond(label, kCondLT, rs, rt);
1552 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
1553 // Synthesize the instruction (not available on R2).
1554 Slt(AT, rs, rt);
1555 Bnez(AT, label);
1556 }
1557}
1558
1559void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
1560 if (IsR6()) {
1561 Bcond(label, kCondGE, rs, rt);
1562 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
1563 B(label);
1564 } else {
1565 // Synthesize the instruction (not available on R2).
1566 Slt(AT, rs, rt);
1567 Beqz(AT, label);
1568 }
1569}
1570
1571void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
1572 if (IsR6()) {
1573 Bcond(label, kCondLTU, rs, rt);
1574 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
1575 // Synthesize the instruction (not available on R2).
1576 Sltu(AT, rs, rt);
1577 Bnez(AT, label);
1578 }
1579}
1580
1581void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
1582 if (IsR6()) {
1583 Bcond(label, kCondGEU, rs, rt);
1584 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
1585 B(label);
1586 } else {
1587 // Synthesize the instruction (not available on R2).
1588 Sltu(AT, rs, rt);
1589 Beqz(AT, label);
jeffhao7fbee072012-08-24 17:56:54 -07001590 }
1591}
1592
1593void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
1594 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001595 // IsInt<16> must be passed a signed value.
1596 if (!IsInt<16>(offset) ||
1597 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
1598 LoadConst32(AT, offset);
1599 Addu(AT, AT, base);
1600 base = AT;
1601 offset = 0;
1602 }
1603
jeffhao7fbee072012-08-24 17:56:54 -07001604 switch (type) {
1605 case kLoadSignedByte:
1606 Lb(reg, base, offset);
1607 break;
1608 case kLoadUnsignedByte:
1609 Lbu(reg, base, offset);
1610 break;
1611 case kLoadSignedHalfword:
1612 Lh(reg, base, offset);
1613 break;
1614 case kLoadUnsignedHalfword:
1615 Lhu(reg, base, offset);
1616 break;
1617 case kLoadWord:
1618 Lw(reg, base, offset);
1619 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001620 case kLoadDoubleword:
1621 if (reg == base) {
1622 // This will clobber the base when loading the lower register. Since we have to load the
1623 // higher register as well, this will fail. Solution: reverse the order.
1624 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
1625 Lw(reg, base, offset);
1626 } else {
1627 Lw(reg, base, offset);
1628 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
1629 }
jeffhao7fbee072012-08-24 17:56:54 -07001630 break;
1631 default:
1632 LOG(FATAL) << "UNREACHABLE";
1633 }
1634}
1635
1636void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001637 if (!IsInt<16>(offset)) {
1638 LoadConst32(AT, offset);
1639 Addu(AT, AT, base);
1640 base = AT;
1641 offset = 0;
1642 }
1643
jeffhao7fbee072012-08-24 17:56:54 -07001644 Lwc1(reg, base, offset);
1645}
1646
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001647void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
1648 // IsInt<16> must be passed a signed value.
1649 if (!IsInt<16>(offset) ||
1650 (!IsAligned<kMipsDoublewordSize>(offset) &&
1651 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
1652 LoadConst32(AT, offset);
1653 Addu(AT, AT, base);
1654 base = AT;
1655 offset = 0;
1656 }
1657
1658 if (offset & 0x7) {
1659 if (Is32BitFPU()) {
1660 Lwc1(reg, base, offset);
1661 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
1662 } else {
1663 // 64-bit FPU.
1664 Lwc1(reg, base, offset);
1665 Lw(T8, base, offset + kMipsWordSize);
1666 Mthc1(T8, reg);
1667 }
1668 } else {
1669 Ldc1(reg, base, offset);
1670 }
1671}
1672
1673void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
1674 size_t size) {
1675 MipsManagedRegister dst = m_dst.AsMips();
1676 if (dst.IsNoRegister()) {
1677 CHECK_EQ(0u, size) << dst;
1678 } else if (dst.IsCoreRegister()) {
1679 CHECK_EQ(kMipsWordSize, size) << dst;
1680 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
1681 } else if (dst.IsRegisterPair()) {
1682 CHECK_EQ(kMipsDoublewordSize, size) << dst;
1683 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
1684 } else if (dst.IsFRegister()) {
1685 if (size == kMipsWordSize) {
1686 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
1687 } else {
1688 CHECK_EQ(kMipsDoublewordSize, size) << dst;
1689 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
1690 }
1691 }
jeffhao7fbee072012-08-24 17:56:54 -07001692}
1693
1694void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
1695 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001696 // IsInt<16> must be passed a signed value.
1697 if (!IsInt<16>(offset) ||
1698 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
1699 LoadConst32(AT, offset);
1700 Addu(AT, AT, base);
1701 base = AT;
1702 offset = 0;
1703 }
1704
jeffhao7fbee072012-08-24 17:56:54 -07001705 switch (type) {
1706 case kStoreByte:
1707 Sb(reg, base, offset);
1708 break;
1709 case kStoreHalfword:
1710 Sh(reg, base, offset);
1711 break;
1712 case kStoreWord:
1713 Sw(reg, base, offset);
1714 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001715 case kStoreDoubleword:
1716 CHECK_NE(reg, base);
1717 CHECK_NE(static_cast<Register>(reg + 1), base);
1718 Sw(reg, base, offset);
1719 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001720 break;
1721 default:
1722 LOG(FATAL) << "UNREACHABLE";
1723 }
1724}
1725
Goran Jakovljevicff734982015-08-24 12:58:55 +00001726void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001727 if (!IsInt<16>(offset)) {
1728 LoadConst32(AT, offset);
1729 Addu(AT, AT, base);
1730 base = AT;
1731 offset = 0;
1732 }
1733
jeffhao7fbee072012-08-24 17:56:54 -07001734 Swc1(reg, base, offset);
1735}
1736
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001737void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
1738 // IsInt<16> must be passed a signed value.
1739 if (!IsInt<16>(offset) ||
1740 (!IsAligned<kMipsDoublewordSize>(offset) &&
1741 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
1742 LoadConst32(AT, offset);
1743 Addu(AT, AT, base);
1744 base = AT;
1745 offset = 0;
1746 }
1747
1748 if (offset & 0x7) {
1749 if (Is32BitFPU()) {
1750 Swc1(reg, base, offset);
1751 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
1752 } else {
1753 // 64-bit FPU.
1754 Mfhc1(T8, reg);
1755 Swc1(reg, base, offset);
1756 Sw(T8, base, offset + kMipsWordSize);
1757 }
1758 } else {
1759 Sdc1(reg, base, offset);
1760 }
jeffhao7fbee072012-08-24 17:56:54 -07001761}
1762
David Srbeckydd973932015-04-07 20:29:48 +01001763static dwarf::Reg DWARFReg(Register reg) {
1764 return dwarf::Reg::MipsCore(static_cast<int>(reg));
1765}
1766
Ian Rogers790a6b72014-04-01 10:36:00 -07001767constexpr size_t kFramePointerSize = 4;
1768
jeffhao7fbee072012-08-24 17:56:54 -07001769void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
1770 const std::vector<ManagedRegister>& callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07001771 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07001772 CHECK_ALIGNED(frame_size, kStackAlignment);
1773
1774 // Increase frame to required size.
1775 IncreaseFrameSize(frame_size);
1776
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001777 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07001778 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07001779 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001780 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07001781 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07001782 stack_offset -= kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07001783 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
1784 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001785 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07001786 }
1787
1788 // Write out Method*.
1789 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
1790
1791 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00001792 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07001793 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00001794 MipsManagedRegister reg = entry_spills.at(i).AsMips();
1795 if (reg.IsNoRegister()) {
1796 ManagedRegisterSpill spill = entry_spills.at(i);
1797 offset += spill.getSize();
1798 } else if (reg.IsCoreRegister()) {
1799 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001800 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00001801 } else if (reg.IsFRegister()) {
1802 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001803 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00001804 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001805 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
1806 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00001807 }
jeffhao7fbee072012-08-24 17:56:54 -07001808 }
1809}
1810
1811void MipsAssembler::RemoveFrame(size_t frame_size,
1812 const std::vector<ManagedRegister>& callee_save_regs) {
1813 CHECK_ALIGNED(frame_size, kStackAlignment);
David Srbeckydd973932015-04-07 20:29:48 +01001814 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07001815
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001816 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07001817 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07001818 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
1819 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
1820 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001821 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07001822 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07001823 }
1824 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001825 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07001826
1827 // Decrease frame to required size.
1828 DecreaseFrameSize(frame_size);
jeffhao07030602012-09-26 14:33:14 -07001829
1830 // Then jump to the return address.
1831 Jr(RA);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001832 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01001833
1834 // The CFI should be restored for any code that follows the exit block.
1835 cfi_.RestoreState();
1836 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07001837}
1838
1839void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001840 CHECK_ALIGNED(adjust, kFramePointerSize);
1841 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01001842 cfi_.AdjustCFAOffset(adjust);
jeffhao7fbee072012-08-24 17:56:54 -07001843}
1844
1845void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001846 CHECK_ALIGNED(adjust, kFramePointerSize);
1847 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01001848 cfi_.AdjustCFAOffset(-adjust);
jeffhao7fbee072012-08-24 17:56:54 -07001849}
1850
1851void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
1852 MipsManagedRegister src = msrc.AsMips();
1853 if (src.IsNoRegister()) {
1854 CHECK_EQ(0u, size);
1855 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001856 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07001857 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
1858 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001859 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07001860 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
1861 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001862 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001863 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001864 if (size == kMipsWordSize) {
1865 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
1866 } else {
1867 CHECK_EQ(kMipsDoublewordSize, size);
1868 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
1869 }
jeffhao7fbee072012-08-24 17:56:54 -07001870 }
1871}
1872
1873void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
1874 MipsManagedRegister src = msrc.AsMips();
1875 CHECK(src.IsCoreRegister());
1876 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
1877}
1878
1879void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
1880 MipsManagedRegister src = msrc.AsMips();
1881 CHECK(src.IsCoreRegister());
1882 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
1883}
1884
1885void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
1886 ManagedRegister mscratch) {
1887 MipsManagedRegister scratch = mscratch.AsMips();
1888 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001889 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07001890 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
1891}
1892
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001893void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
jeffhao7fbee072012-08-24 17:56:54 -07001894 ManagedRegister mscratch) {
1895 MipsManagedRegister scratch = mscratch.AsMips();
1896 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001897 // Is this function even referenced anywhere else in the code?
1898 LoadConst32(scratch.AsCoreRegister(), imm);
1899 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
1900}
1901
1902void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
1903 FrameOffset fr_offs,
1904 ManagedRegister mscratch) {
1905 MipsManagedRegister scratch = mscratch.AsMips();
1906 CHECK(scratch.IsCoreRegister()) << scratch;
1907 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07001908 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
1909 S1, thr_offs.Int32Value());
1910}
1911
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001912void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07001913 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
1914}
1915
1916void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
1917 FrameOffset in_off, ManagedRegister mscratch) {
1918 MipsManagedRegister src = msrc.AsMips();
1919 MipsManagedRegister scratch = mscratch.AsMips();
1920 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
1921 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001922 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001923}
1924
1925void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
1926 return EmitLoad(mdest, SP, src.Int32Value(), size);
1927}
1928
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001929void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
1930 ThreadOffset<kMipsWordSize> src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07001931 return EmitLoad(mdest, S1, src.Int32Value(), size);
1932}
1933
1934void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
1935 MipsManagedRegister dest = mdest.AsMips();
1936 CHECK(dest.IsCoreRegister());
1937 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
1938}
1939
Mathieu Chartiere401d142015-04-22 13:56:20 -07001940void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01001941 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07001942 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001943 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07001944 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
1945 base.AsMips().AsCoreRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01001946 if (kPoisonHeapReferences && unpoison_reference) {
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08001947 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
1948 }
jeffhao7fbee072012-08-24 17:56:54 -07001949}
1950
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001951void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07001952 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001953 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07001954 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
1955 base.AsMips().AsCoreRegister(), offs.Int32Value());
1956}
1957
Ian Rogersdd7624d2014-03-14 17:43:00 -07001958void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001959 ThreadOffset<kMipsWordSize> offs) {
jeffhao7fbee072012-08-24 17:56:54 -07001960 MipsManagedRegister dest = mdest.AsMips();
1961 CHECK(dest.IsCoreRegister());
1962 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
1963}
1964
1965void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
1966 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
1967}
1968
1969void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
1970 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
1971}
1972
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001973void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07001974 MipsManagedRegister dest = mdest.AsMips();
1975 MipsManagedRegister src = msrc.AsMips();
1976 if (!dest.Equals(src)) {
1977 if (dest.IsCoreRegister()) {
1978 CHECK(src.IsCoreRegister()) << src;
1979 Move(dest.AsCoreRegister(), src.AsCoreRegister());
1980 } else if (dest.IsFRegister()) {
1981 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001982 if (size == kMipsWordSize) {
1983 MovS(dest.AsFRegister(), src.AsFRegister());
1984 } else {
1985 CHECK_EQ(kMipsDoublewordSize, size);
1986 MovD(dest.AsFRegister(), src.AsFRegister());
1987 }
jeffhao7fbee072012-08-24 17:56:54 -07001988 } else if (dest.IsDRegister()) {
1989 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001990 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07001991 } else {
1992 CHECK(dest.IsRegisterPair()) << dest;
1993 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001994 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07001995 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
1996 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
1997 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
1998 } else {
1999 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2000 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2001 }
2002 }
2003 }
2004}
2005
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002006void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002007 MipsManagedRegister scratch = mscratch.AsMips();
2008 CHECK(scratch.IsCoreRegister()) << scratch;
2009 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2010 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2011}
2012
Ian Rogersdd7624d2014-03-14 17:43:00 -07002013void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002014 ThreadOffset<kMipsWordSize> thr_offs,
2015 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002016 MipsManagedRegister scratch = mscratch.AsMips();
2017 CHECK(scratch.IsCoreRegister()) << scratch;
2018 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2019 S1, thr_offs.Int32Value());
2020 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2021 SP, fr_offs.Int32Value());
2022}
2023
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002024void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2025 FrameOffset fr_offs,
2026 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002027 MipsManagedRegister scratch = mscratch.AsMips();
2028 CHECK(scratch.IsCoreRegister()) << scratch;
2029 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2030 SP, fr_offs.Int32Value());
2031 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2032 S1, thr_offs.Int32Value());
2033}
2034
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002035void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002036 MipsManagedRegister scratch = mscratch.AsMips();
2037 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002038 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2039 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002040 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2041 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002042 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002043 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2044 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002045 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2046 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002047 }
2048}
2049
2050void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2051 ManagedRegister mscratch, size_t size) {
2052 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002053 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002054 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2055 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2056}
2057
2058void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2059 ManagedRegister mscratch, size_t size) {
2060 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002061 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002062 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2063 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2064}
2065
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002066void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2067 FrameOffset src_base ATTRIBUTE_UNUSED,
2068 Offset src_offset ATTRIBUTE_UNUSED,
2069 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2070 size_t size ATTRIBUTE_UNUSED) {
2071 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002072}
2073
2074void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2075 ManagedRegister src, Offset src_offset,
2076 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002077 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002078 Register scratch = mscratch.AsMips().AsCoreRegister();
2079 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2080 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2081}
2082
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002083void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2084 Offset dest_offset ATTRIBUTE_UNUSED,
2085 FrameOffset src ATTRIBUTE_UNUSED,
2086 Offset src_offset ATTRIBUTE_UNUSED,
2087 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2088 size_t size ATTRIBUTE_UNUSED) {
2089 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002090}
2091
2092void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002093 // TODO: sync?
2094 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002095}
2096
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002097void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002098 FrameOffset handle_scope_offset,
2099 ManagedRegister min_reg,
2100 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002101 MipsManagedRegister out_reg = mout_reg.AsMips();
2102 MipsManagedRegister in_reg = min_reg.AsMips();
2103 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2104 CHECK(out_reg.IsCoreRegister()) << out_reg;
2105 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002106 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002107 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2108 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002109 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07002110 if (in_reg.IsNoRegister()) {
2111 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002112 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002113 in_reg = out_reg;
2114 }
2115 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002116 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002117 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002118 Beqz(in_reg.AsCoreRegister(), &null_arg);
2119 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2120 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002121 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002122 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002123 }
2124}
2125
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002126void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002127 FrameOffset handle_scope_offset,
2128 ManagedRegister mscratch,
2129 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002130 MipsManagedRegister scratch = mscratch.AsMips();
2131 CHECK(scratch.IsCoreRegister()) << scratch;
2132 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002133 MipsLabel null_arg;
2134 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002135 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2136 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002137 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2138 Beqz(scratch.AsCoreRegister(), &null_arg);
2139 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2140 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002141 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002142 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002143 }
2144 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2145}
2146
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002147// Given a handle scope entry, load the associated reference.
2148void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002149 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07002150 MipsManagedRegister out_reg = mout_reg.AsMips();
2151 MipsManagedRegister in_reg = min_reg.AsMips();
2152 CHECK(out_reg.IsCoreRegister()) << out_reg;
2153 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002154 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07002155 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002156 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002157 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002158 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002159 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2160 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002161 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002162}
2163
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002164void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2165 bool could_be_null ATTRIBUTE_UNUSED) {
2166 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002167}
2168
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002169void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2170 bool could_be_null ATTRIBUTE_UNUSED) {
2171 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002172}
2173
2174void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2175 MipsManagedRegister base = mbase.AsMips();
2176 MipsManagedRegister scratch = mscratch.AsMips();
2177 CHECK(base.IsCoreRegister()) << base;
2178 CHECK(scratch.IsCoreRegister()) << scratch;
2179 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2180 base.AsCoreRegister(), offset.Int32Value());
2181 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002182 Nop();
2183 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002184}
2185
2186void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2187 MipsManagedRegister scratch = mscratch.AsMips();
2188 CHECK(scratch.IsCoreRegister()) << scratch;
2189 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002190 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002191 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2192 scratch.AsCoreRegister(), offset.Int32Value());
2193 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002194 Nop();
2195 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002196}
2197
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002198void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2199 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07002200 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002201}
2202
2203void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2204 Move(tr.AsMips().AsCoreRegister(), S1);
2205}
2206
2207void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002208 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07002209 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2210}
2211
jeffhao7fbee072012-08-24 17:56:54 -07002212void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2213 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002214 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07002215 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002216 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2217 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2218 // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2219 // For now use common for R2 and R6 instructions as this code must execute on both.
2220 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07002221}
2222
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002223void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2224 Bind(exception->Entry());
2225 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2226 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07002227 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002228 // Pass exception object as argument.
2229 // Don't care about preserving A0 as this call won't return.
2230 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2231 Move(A0, exception->scratch_.AsCoreRegister());
2232 // Set up call to Thread::Current()->pDeliverException.
2233 LoadFromOffset(kLoadWord, T9, S1,
2234 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2235 Jr(T9);
2236 Nop();
2237
2238 // Call never returns.
2239 Break();
jeffhao7fbee072012-08-24 17:56:54 -07002240}
2241
2242} // namespace mips
2243} // namespace art