blob: 7c41813457cd233582bf29e6eb0b015619a7961f [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) {
Vladimir Marko10ef6942015-10-22 15:25:54 +010046 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020047 EmitBranches();
48 Assembler::FinalizeInstructions(region);
Vladimir Marko10ef6942015-10-22 15:25:54 +010049 PatchCFI(number_of_delayed_adjust_pcs);
50}
51
52void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
53 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
54 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
55 return;
56 }
57
58 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
59 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
60 const std::vector<uint8_t>& old_stream = data.first;
61 const std::vector<DelayedAdvancePC>& advances = data.second;
62
63 // PCs recorded before EmitBranches() need to be adjusted.
64 // PCs recorded during EmitBranches() are already adjusted.
65 // Both ranges are separately sorted but they may overlap.
66 if (kIsDebugBuild) {
67 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
68 return lhs.pc < rhs.pc;
69 };
70 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
71 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
72 }
73
74 // Append initial CFI data if any.
75 size_t size = advances.size();
76 DCHECK_NE(size, 0u);
77 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
78 // Emit PC adjustments interleaved with the old CFI stream.
79 size_t adjust_pos = 0u;
80 size_t late_emit_pos = number_of_delayed_adjust_pcs;
81 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
82 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
83 ? GetAdjustedPosition(advances[adjust_pos].pc)
84 : static_cast<size_t>(-1);
85 size_t late_emit_pc = (late_emit_pos != size)
86 ? advances[late_emit_pos].pc
87 : static_cast<size_t>(-1);
88 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
89 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
90 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
91 if (adjusted_pc <= late_emit_pc) {
92 ++adjust_pos;
93 } else {
94 ++late_emit_pos;
95 }
96 cfi().AdvancePC(advance_pc);
97 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
98 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
99 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200100}
101
102void MipsAssembler::EmitBranches() {
103 CHECK(!overwriting_);
104 // Switch from appending instructions at the end of the buffer to overwriting
105 // existing instructions (branch placeholders) in the buffer.
106 overwriting_ = true;
107 for (auto& branch : branches_) {
108 EmitBranch(&branch);
109 }
110 overwriting_ = false;
111}
112
113void MipsAssembler::Emit(uint32_t value) {
114 if (overwriting_) {
115 // Branches to labels are emitted into their placeholders here.
116 buffer_.Store<uint32_t>(overwrite_location_, value);
117 overwrite_location_ += sizeof(uint32_t);
118 } else {
119 // Other instructions are simply appended at the end here.
120 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
121 buffer_.Emit<uint32_t>(value);
122 }
jeffhao7fbee072012-08-24 17:56:54 -0700123}
124
125void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
126 CHECK_NE(rs, kNoRegister);
127 CHECK_NE(rt, kNoRegister);
128 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200129 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;
jeffhao7fbee072012-08-24 17:56:54 -0700135 Emit(encoding);
136}
137
138void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
139 CHECK_NE(rs, kNoRegister);
140 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200141 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;
jeffhao7fbee072012-08-24 17:56:54 -0700145 Emit(encoding);
146}
147
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200148void 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;
jeffhao7fbee072012-08-24 17:56:54 -0700154 Emit(encoding);
155}
156
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200157void MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
158 CHECK(IsUint<26>(imm26)) << imm26;
159 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
160 Emit(encoding);
161}
162
163void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd,
164 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700165 CHECK_NE(ft, kNoFRegister);
166 CHECK_NE(fs, kNoFRegister);
167 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200168 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;
jeffhao7fbee072012-08-24 17:56:54 -0700174 Emit(encoding);
175}
176
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200177void 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;
jeffhao7fbee072012-08-24 17:56:54 -0700183 Emit(encoding);
184}
185
jeffhao7fbee072012-08-24 17:56:54 -0700186void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
187 EmitR(0, rs, rt, rd, 0, 0x21);
188}
189
jeffhao7fbee072012-08-24 17:56:54 -0700190void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
191 EmitI(0x9, rs, rt, imm16);
192}
193
jeffhao7fbee072012-08-24 17:56:54 -0700194void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
195 EmitR(0, rs, rt, rd, 0, 0x23);
196}
197
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200198void MipsAssembler::MultR2(Register rs, Register rt) {
199 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700200 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
201}
202
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200203void MipsAssembler::MultuR2(Register rs, Register rt) {
204 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700205 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
206}
207
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200208void MipsAssembler::DivR2(Register rs, Register rt) {
209 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700210 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
211}
212
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200213void MipsAssembler::DivuR2(Register rs, Register rt) {
214 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700215 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
216}
217
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200218void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
219 CHECK(!IsR6());
220 EmitR(0x1c, rs, rt, rd, 0, 2);
221}
222
223void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
224 CHECK(!IsR6());
225 DivR2(rs, rt);
226 Mflo(rd);
227}
228
229void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
230 CHECK(!IsR6());
231 DivR2(rs, rt);
232 Mfhi(rd);
233}
234
235void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
236 CHECK(!IsR6());
237 DivuR2(rs, rt);
238 Mflo(rd);
239}
240
241void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
242 CHECK(!IsR6());
243 DivuR2(rs, rt);
244 Mfhi(rd);
245}
246
247void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
248 CHECK(IsR6());
249 EmitR(0, rs, rt, rd, 2, 0x18);
250}
251
Alexey Frunze7e99e052015-11-24 19:28:01 -0800252void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
253 CHECK(IsR6());
254 EmitR(0, rs, rt, rd, 3, 0x18);
255}
256
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200257void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
258 CHECK(IsR6());
259 EmitR(0, rs, rt, rd, 3, 0x19);
260}
261
262void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
263 CHECK(IsR6());
264 EmitR(0, rs, rt, rd, 2, 0x1a);
265}
266
267void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
268 CHECK(IsR6());
269 EmitR(0, rs, rt, rd, 3, 0x1a);
270}
271
272void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
273 CHECK(IsR6());
274 EmitR(0, rs, rt, rd, 2, 0x1b);
275}
276
277void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
278 CHECK(IsR6());
279 EmitR(0, rs, rt, rd, 3, 0x1b);
280}
281
jeffhao7fbee072012-08-24 17:56:54 -0700282void MipsAssembler::And(Register rd, Register rs, Register rt) {
283 EmitR(0, rs, rt, rd, 0, 0x24);
284}
285
286void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
287 EmitI(0xc, rs, rt, imm16);
288}
289
290void MipsAssembler::Or(Register rd, Register rs, Register rt) {
291 EmitR(0, rs, rt, rd, 0, 0x25);
292}
293
294void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
295 EmitI(0xd, rs, rt, imm16);
296}
297
298void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
299 EmitR(0, rs, rt, rd, 0, 0x26);
300}
301
302void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
303 EmitI(0xe, rs, rt, imm16);
304}
305
306void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
307 EmitR(0, rs, rt, rd, 0, 0x27);
308}
309
Chris Larsene3845472015-11-18 12:27:15 -0800310void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
311 CHECK(!IsR6());
312 EmitR(0, rs, rt, rd, 0, 0x0A);
313}
314
315void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
316 CHECK(!IsR6());
317 EmitR(0, rs, rt, rd, 0, 0x0B);
318}
319
320void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
321 CHECK(IsR6());
322 EmitR(0, rs, rt, rd, 0, 0x35);
323}
324
325void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
326 CHECK(IsR6());
327 EmitR(0, rs, rt, rd, 0, 0x37);
328}
329
330void MipsAssembler::ClzR6(Register rd, Register rs) {
331 CHECK(IsR6());
332 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10);
333}
334
335void MipsAssembler::ClzR2(Register rd, Register rs) {
336 CHECK(!IsR6());
337 EmitR(0x1C, rs, rd, rd, 0, 0x20);
338}
339
340void MipsAssembler::CloR6(Register rd, Register rs) {
341 CHECK(IsR6());
342 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11);
343}
344
345void MipsAssembler::CloR2(Register rd, Register rs) {
346 CHECK(!IsR6());
347 EmitR(0x1C, rs, rd, rd, 0, 0x21);
348}
349
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200350void MipsAssembler::Seb(Register rd, Register rt) {
351 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700352}
353
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200354void MipsAssembler::Seh(Register rd, Register rt) {
355 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700356}
357
Chris Larsen3f8bf652015-10-28 10:08:56 -0700358void MipsAssembler::Wsbh(Register rd, Register rt) {
359 EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20);
360}
361
Chris Larsen70014c82015-11-18 12:26:08 -0800362void MipsAssembler::Bitswap(Register rd, Register rt) {
363 CHECK(IsR6());
364 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20);
365}
366
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200367void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700368 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200369 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00);
jeffhao7fbee072012-08-24 17:56:54 -0700370}
371
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700373 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200374 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02);
375}
376
Chris Larsen3f8bf652015-10-28 10:08:56 -0700377void 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
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200382void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700383 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200384 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03);
385}
386
387void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700388 EmitR(0, rs, rt, rd, 0, 0x04);
389}
390
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200391void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700392 EmitR(0, rs, rt, rd, 0, 0x06);
393}
394
Chris Larsene16ce5a2015-11-18 12:30:20 -0800395void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
396 EmitR(0, rs, rt, rd, 1, 0x06);
397}
398
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200399void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700400 EmitR(0, rs, rt, rd, 0, 0x07);
401}
402
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800403void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
404 CHECK(IsUint<5>(pos)) << pos;
405 CHECK(0 < size && size <= 32) << size;
406 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
407 EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00);
408}
409
410void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
411 CHECK(IsUint<5>(pos)) << pos;
412 CHECK(0 < size && size <= 32) << size;
413 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
414 EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04);
415}
416
jeffhao7fbee072012-08-24 17:56:54 -0700417void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
418 EmitI(0x20, rs, rt, imm16);
419}
420
421void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
422 EmitI(0x21, rs, rt, imm16);
423}
424
425void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
426 EmitI(0x23, rs, rt, imm16);
427}
428
Chris Larsen3acee732015-11-18 13:31:08 -0800429void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
430 CHECK(!IsR6());
431 EmitI(0x22, rs, rt, imm16);
432}
433
434void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
435 CHECK(!IsR6());
436 EmitI(0x26, rs, rt, imm16);
437}
438
jeffhao7fbee072012-08-24 17:56:54 -0700439void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
440 EmitI(0x24, rs, rt, imm16);
441}
442
443void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
444 EmitI(0x25, rs, rt, imm16);
445}
446
447void MipsAssembler::Lui(Register rt, uint16_t imm16) {
448 EmitI(0xf, static_cast<Register>(0), rt, imm16);
449}
450
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200451void 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
jeffhao7fbee072012-08-24 17:56:54 -0700456void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200457 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700458 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
459}
460
461void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200462 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700463 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
464}
465
466void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
467 EmitI(0x28, rs, rt, imm16);
468}
469
470void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
471 EmitI(0x29, rs, rt, imm16);
472}
473
474void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
475 EmitI(0x2b, rs, rt, imm16);
476}
477
Chris Larsen3acee732015-11-18 13:31:08 -0800478void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
479 CHECK(!IsR6());
480 EmitI(0x2a, rs, rt, imm16);
481}
482
483void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
484 CHECK(!IsR6());
485 EmitI(0x2e, rs, rt, imm16);
486}
487
jeffhao7fbee072012-08-24 17:56:54 -0700488void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
489 EmitR(0, rs, rt, rd, 0, 0x2a);
490}
491
492void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
493 EmitR(0, rs, rt, rd, 0, 0x2b);
494}
495
496void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
497 EmitI(0xa, rs, rt, imm16);
498}
499
500void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
501 EmitI(0xb, rs, rt, imm16);
502}
503
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200504void MipsAssembler::B(uint16_t imm16) {
505 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
506}
507
508void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700509 EmitI(0x4, rs, rt, imm16);
510}
511
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200512void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700513 EmitI(0x5, rs, rt, imm16);
514}
515
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200516void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
517 Beq(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700518}
519
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200520void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
521 Bne(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700522}
523
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200524void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
525 EmitI(0x1, rt, static_cast<Register>(0), imm16);
526}
527
528void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
529 EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
530}
531
532void MipsAssembler::Blez(Register rt, uint16_t imm16) {
533 EmitI(0x6, rt, static_cast<Register>(0), imm16);
534}
535
536void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
537 EmitI(0x7, rt, static_cast<Register>(0), imm16);
538}
539
Chris Larsenb74353a2015-11-20 09:07:09 -0800540void MipsAssembler::Bc1f(uint16_t imm16) {
541 Bc1f(0, imm16);
542}
543
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800544void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
545 CHECK(!IsR6());
546 CHECK(IsUint<3>(cc)) << cc;
547 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16);
548}
549
Chris Larsenb74353a2015-11-20 09:07:09 -0800550void MipsAssembler::Bc1t(uint16_t imm16) {
551 Bc1t(0, imm16);
552}
553
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800554void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
555 CHECK(!IsR6());
556 CHECK(IsUint<3>(cc)) << cc;
557 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16);
558}
559
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200560void MipsAssembler::J(uint32_t addr26) {
561 EmitI26(0x2, addr26);
562}
563
564void MipsAssembler::Jal(uint32_t addr26) {
565 EmitI26(0x3, addr26);
566}
567
568void MipsAssembler::Jalr(Register rd, Register rs) {
569 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
jeffhao7fbee072012-08-24 17:56:54 -0700570}
571
572void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200573 Jalr(RA, rs);
574}
575
576void MipsAssembler::Jr(Register rs) {
577 Jalr(ZERO, rs);
578}
579
580void MipsAssembler::Nal() {
581 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
582}
583
584void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
585 CHECK(IsR6());
586 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
587}
588
589void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
590 CHECK(IsR6());
591 CHECK(IsUint<19>(imm19)) << imm19;
592 EmitI21(0x3B, rs, imm19);
593}
594
595void MipsAssembler::Bc(uint32_t imm26) {
596 CHECK(IsR6());
597 EmitI26(0x32, imm26);
598}
599
600void MipsAssembler::Jic(Register rt, uint16_t imm16) {
601 CHECK(IsR6());
602 EmitI(0x36, static_cast<Register>(0), rt, imm16);
603}
604
605void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
606 CHECK(IsR6());
607 EmitI(0x3E, static_cast<Register>(0), rt, imm16);
608}
609
610void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
611 CHECK(IsR6());
612 CHECK_NE(rs, ZERO);
613 CHECK_NE(rt, ZERO);
614 CHECK_NE(rs, rt);
615 EmitI(0x17, rs, rt, imm16);
616}
617
618void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
619 CHECK(IsR6());
620 CHECK_NE(rt, ZERO);
621 EmitI(0x17, rt, rt, imm16);
622}
623
624void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
625 CHECK(IsR6());
626 CHECK_NE(rt, ZERO);
627 EmitI(0x17, static_cast<Register>(0), rt, imm16);
628}
629
630void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
631 CHECK(IsR6());
632 CHECK_NE(rs, ZERO);
633 CHECK_NE(rt, ZERO);
634 CHECK_NE(rs, rt);
635 EmitI(0x16, rs, rt, imm16);
636}
637
638void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
639 CHECK(IsR6());
640 CHECK_NE(rt, ZERO);
641 EmitI(0x16, rt, rt, imm16);
642}
643
644void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
645 CHECK(IsR6());
646 CHECK_NE(rt, ZERO);
647 EmitI(0x16, static_cast<Register>(0), rt, imm16);
648}
649
650void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
651 CHECK(IsR6());
652 CHECK_NE(rs, ZERO);
653 CHECK_NE(rt, ZERO);
654 CHECK_NE(rs, rt);
655 EmitI(0x7, rs, rt, imm16);
656}
657
658void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
659 CHECK(IsR6());
660 CHECK_NE(rs, ZERO);
661 CHECK_NE(rt, ZERO);
662 CHECK_NE(rs, rt);
663 EmitI(0x6, rs, rt, imm16);
664}
665
666void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
667 CHECK(IsR6());
668 CHECK_NE(rs, ZERO);
669 CHECK_NE(rt, ZERO);
670 CHECK_NE(rs, rt);
671 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
672}
673
674void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
675 CHECK(IsR6());
676 CHECK_NE(rs, ZERO);
677 CHECK_NE(rt, ZERO);
678 CHECK_NE(rs, rt);
679 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
680}
681
682void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
683 CHECK(IsR6());
684 CHECK_NE(rs, ZERO);
685 EmitI21(0x36, rs, imm21);
686}
687
688void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
689 CHECK(IsR6());
690 CHECK_NE(rs, ZERO);
691 EmitI21(0x3E, rs, imm21);
692}
693
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800694void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
695 CHECK(IsR6());
696 EmitFI(0x11, 0x9, ft, imm16);
697}
698
699void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
700 CHECK(IsR6());
701 EmitFI(0x11, 0xD, ft, imm16);
702}
703
704void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200705 switch (cond) {
706 case kCondLTZ:
707 CHECK_EQ(rt, ZERO);
708 Bltz(rs, imm16);
709 break;
710 case kCondGEZ:
711 CHECK_EQ(rt, ZERO);
712 Bgez(rs, imm16);
713 break;
714 case kCondLEZ:
715 CHECK_EQ(rt, ZERO);
716 Blez(rs, imm16);
717 break;
718 case kCondGTZ:
719 CHECK_EQ(rt, ZERO);
720 Bgtz(rs, imm16);
721 break;
722 case kCondEQ:
723 Beq(rs, rt, imm16);
724 break;
725 case kCondNE:
726 Bne(rs, rt, imm16);
727 break;
728 case kCondEQZ:
729 CHECK_EQ(rt, ZERO);
730 Beqz(rs, imm16);
731 break;
732 case kCondNEZ:
733 CHECK_EQ(rt, ZERO);
734 Bnez(rs, imm16);
735 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800736 case kCondF:
737 CHECK_EQ(rt, ZERO);
738 Bc1f(static_cast<int>(rs), imm16);
739 break;
740 case kCondT:
741 CHECK_EQ(rt, ZERO);
742 Bc1t(static_cast<int>(rs), imm16);
743 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200744 case kCondLT:
745 case kCondGE:
746 case kCondLE:
747 case kCondGT:
748 case kCondLTU:
749 case kCondGEU:
750 case kUncond:
751 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
752 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
753 LOG(FATAL) << "Unexpected branch condition " << cond;
754 UNREACHABLE();
755 }
756}
757
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800758void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200759 switch (cond) {
760 case kCondLT:
761 Bltc(rs, rt, imm16_21);
762 break;
763 case kCondGE:
764 Bgec(rs, rt, imm16_21);
765 break;
766 case kCondLE:
767 Bgec(rt, rs, imm16_21);
768 break;
769 case kCondGT:
770 Bltc(rt, rs, imm16_21);
771 break;
772 case kCondLTZ:
773 CHECK_EQ(rt, ZERO);
774 Bltzc(rs, imm16_21);
775 break;
776 case kCondGEZ:
777 CHECK_EQ(rt, ZERO);
778 Bgezc(rs, imm16_21);
779 break;
780 case kCondLEZ:
781 CHECK_EQ(rt, ZERO);
782 Blezc(rs, imm16_21);
783 break;
784 case kCondGTZ:
785 CHECK_EQ(rt, ZERO);
786 Bgtzc(rs, imm16_21);
787 break;
788 case kCondEQ:
789 Beqc(rs, rt, imm16_21);
790 break;
791 case kCondNE:
792 Bnec(rs, rt, imm16_21);
793 break;
794 case kCondEQZ:
795 CHECK_EQ(rt, ZERO);
796 Beqzc(rs, imm16_21);
797 break;
798 case kCondNEZ:
799 CHECK_EQ(rt, ZERO);
800 Bnezc(rs, imm16_21);
801 break;
802 case kCondLTU:
803 Bltuc(rs, rt, imm16_21);
804 break;
805 case kCondGEU:
806 Bgeuc(rs, rt, imm16_21);
807 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800808 case kCondF:
809 CHECK_EQ(rt, ZERO);
810 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
811 break;
812 case kCondT:
813 CHECK_EQ(rt, ZERO);
814 Bc1nez(static_cast<FRegister>(rs), imm16_21);
815 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200816 case kUncond:
817 LOG(FATAL) << "Unexpected branch condition " << cond;
818 UNREACHABLE();
819 }
jeffhao7fbee072012-08-24 17:56:54 -0700820}
821
822void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
823 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
824}
825
826void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
827 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
828}
829
830void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
831 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
832}
833
834void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
835 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
836}
837
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200838void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
839 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700840}
841
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200842void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
843 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
jeffhao7fbee072012-08-24 17:56:54 -0700844}
845
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200846void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
847 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
jeffhao7fbee072012-08-24 17:56:54 -0700848}
849
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200850void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
851 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
jeffhao7fbee072012-08-24 17:56:54 -0700852}
853
Chris Larsenb74353a2015-11-20 09:07:09 -0800854void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
855 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4);
856}
857
858void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
859 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4);
860}
861
862void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
863 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5);
864}
865
866void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
867 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5);
868}
869
jeffhao7fbee072012-08-24 17:56:54 -0700870void MipsAssembler::MovS(FRegister fd, FRegister fs) {
871 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
872}
873
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200874void MipsAssembler::MovD(FRegister fd, FRegister fs) {
875 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
876}
877
878void MipsAssembler::NegS(FRegister fd, FRegister fs) {
879 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
880}
881
882void MipsAssembler::NegD(FRegister fd, FRegister fs) {
883 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
884}
885
Chris Larsenb74353a2015-11-20 09:07:09 -0800886void MipsAssembler::CunS(FRegister fs, FRegister ft) {
887 CunS(0, fs, ft);
888}
889
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800890void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
891 CHECK(!IsR6());
892 CHECK(IsUint<3>(cc)) << cc;
893 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
894}
895
Chris Larsenb74353a2015-11-20 09:07:09 -0800896void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
897 CeqS(0, fs, ft);
898}
899
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800900void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
901 CHECK(!IsR6());
902 CHECK(IsUint<3>(cc)) << cc;
903 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
904}
905
Chris Larsenb74353a2015-11-20 09:07:09 -0800906void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
907 CueqS(0, fs, ft);
908}
909
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800910void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
911 CHECK(!IsR6());
912 CHECK(IsUint<3>(cc)) << cc;
913 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
914}
915
Chris Larsenb74353a2015-11-20 09:07:09 -0800916void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
917 ColtS(0, fs, ft);
918}
919
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800920void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
921 CHECK(!IsR6());
922 CHECK(IsUint<3>(cc)) << cc;
923 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
924}
925
Chris Larsenb74353a2015-11-20 09:07:09 -0800926void MipsAssembler::CultS(FRegister fs, FRegister ft) {
927 CultS(0, fs, ft);
928}
929
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800930void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
931 CHECK(!IsR6());
932 CHECK(IsUint<3>(cc)) << cc;
933 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
934}
935
Chris Larsenb74353a2015-11-20 09:07:09 -0800936void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
937 ColeS(0, fs, ft);
938}
939
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800940void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
941 CHECK(!IsR6());
942 CHECK(IsUint<3>(cc)) << cc;
943 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
944}
945
Chris Larsenb74353a2015-11-20 09:07:09 -0800946void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
947 CuleS(0, fs, ft);
948}
949
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800950void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
951 CHECK(!IsR6());
952 CHECK(IsUint<3>(cc)) << cc;
953 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
954}
955
Chris Larsenb74353a2015-11-20 09:07:09 -0800956void MipsAssembler::CunD(FRegister fs, FRegister ft) {
957 CunD(0, fs, ft);
958}
959
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800960void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
961 CHECK(!IsR6());
962 CHECK(IsUint<3>(cc)) << cc;
963 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
964}
965
Chris Larsenb74353a2015-11-20 09:07:09 -0800966void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
967 CeqD(0, fs, ft);
968}
969
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800970void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
971 CHECK(!IsR6());
972 CHECK(IsUint<3>(cc)) << cc;
973 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
974}
975
Chris Larsenb74353a2015-11-20 09:07:09 -0800976void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
977 CueqD(0, fs, ft);
978}
979
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800980void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
981 CHECK(!IsR6());
982 CHECK(IsUint<3>(cc)) << cc;
983 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
984}
985
Chris Larsenb74353a2015-11-20 09:07:09 -0800986void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
987 ColtD(0, fs, ft);
988}
989
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800990void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
991 CHECK(!IsR6());
992 CHECK(IsUint<3>(cc)) << cc;
993 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
994}
995
Chris Larsenb74353a2015-11-20 09:07:09 -0800996void MipsAssembler::CultD(FRegister fs, FRegister ft) {
997 CultD(0, fs, ft);
998}
999
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001000void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1001 CHECK(!IsR6());
1002 CHECK(IsUint<3>(cc)) << cc;
1003 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
1004}
1005
Chris Larsenb74353a2015-11-20 09:07:09 -08001006void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1007 ColeD(0, fs, ft);
1008}
1009
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001010void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1011 CHECK(!IsR6());
1012 CHECK(IsUint<3>(cc)) << cc;
1013 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
1014}
1015
Chris Larsenb74353a2015-11-20 09:07:09 -08001016void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1017 CuleD(0, fs, ft);
1018}
1019
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001020void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1021 CHECK(!IsR6());
1022 CHECK(IsUint<3>(cc)) << cc;
1023 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
1024}
1025
1026void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1027 CHECK(IsR6());
1028 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1029}
1030
1031void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1032 CHECK(IsR6());
1033 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1034}
1035
1036void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1037 CHECK(IsR6());
1038 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1039}
1040
1041void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1042 CHECK(IsR6());
1043 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1044}
1045
1046void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1047 CHECK(IsR6());
1048 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1049}
1050
1051void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1052 CHECK(IsR6());
1053 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1054}
1055
1056void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1057 CHECK(IsR6());
1058 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1059}
1060
1061void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1062 CHECK(IsR6());
1063 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1064}
1065
1066void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1067 CHECK(IsR6());
1068 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1069}
1070
1071void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1072 CHECK(IsR6());
1073 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1074}
1075
1076void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1077 CHECK(IsR6());
1078 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1079}
1080
1081void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1082 CHECK(IsR6());
1083 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1084}
1085
1086void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1087 CHECK(IsR6());
1088 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1089}
1090
1091void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1092 CHECK(IsR6());
1093 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1094}
1095
1096void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1097 CHECK(IsR6());
1098 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1099}
1100
1101void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1102 CHECK(IsR6());
1103 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1104}
1105
1106void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1107 CHECK(IsR6());
1108 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1109}
1110
1111void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1112 CHECK(IsR6());
1113 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1114}
1115
1116void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1117 CHECK(IsR6());
1118 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1119}
1120
1121void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1122 CHECK(IsR6());
1123 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1124}
1125
1126void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1127 CHECK(!IsR6());
1128 CHECK(IsUint<3>(cc)) << cc;
1129 EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01);
1130}
1131
1132void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1133 CHECK(!IsR6());
1134 CHECK(IsUint<3>(cc)) << cc;
1135 EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01);
1136}
1137
Chris Larsenb74353a2015-11-20 09:07:09 -08001138void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1139 CHECK(!IsR6());
1140 CHECK(IsUint<3>(cc)) << cc;
1141 EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1142}
1143
1144void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1145 CHECK(!IsR6());
1146 CHECK(IsUint<3>(cc)) << cc;
1147 EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1148}
1149
1150void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1151 CHECK(!IsR6());
1152 CHECK(IsUint<3>(cc)) << cc;
1153 EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1154}
1155
1156void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1157 CHECK(!IsR6());
1158 CHECK(IsUint<3>(cc)) << cc;
1159 EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1160}
1161
1162void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1163 CHECK(IsR6());
1164 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
1165}
1166
1167void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1168 CHECK(IsR6());
1169 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1170}
1171
1172void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1173 CHECK(IsR6());
1174 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b);
1175}
1176
1177void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1178 CHECK(IsR6());
1179 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b);
1180}
1181
1182void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1183 CHECK(IsR6());
1184 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1185}
1186
1187void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1188 CHECK(IsR6());
1189 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1190}
1191
1192void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1193 CHECK(IsR6());
1194 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1195}
1196
1197void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1198 CHECK(IsR6());
1199 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1200}
1201
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001202void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1203 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1204}
1205
1206void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1207 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1208}
1209
1210void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1211 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1212}
1213
1214void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1215 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1216}
1217
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001218void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1219 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1220}
1221
1222void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1223 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1224}
1225
1226void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1227 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1228}
1229
1230void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1231 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
jeffhao7fbee072012-08-24 17:56:54 -07001232}
1233
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001234void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1235 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1236}
1237
1238void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1239 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1240}
1241
Chris Larsenb74353a2015-11-20 09:07:09 -08001242void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1243 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf);
1244}
1245
1246void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1247 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf);
1248}
1249
jeffhao7fbee072012-08-24 17:56:54 -07001250void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001251 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001252}
1253
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001254void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1255 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1256}
1257
1258void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1259 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1260}
1261
1262void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1263 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001264}
1265
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001266void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1267 if (Is32BitFPU()) {
1268 CHECK_EQ(fs % 2, 0) << fs;
1269 Mfc1(rt, static_cast<FRegister>(fs + 1));
1270 } else {
1271 Mfhc1(rt, fs);
1272 }
1273}
1274
1275void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1276 if (Is32BitFPU()) {
1277 CHECK_EQ(fs % 2, 0) << fs;
1278 Mtc1(rt, static_cast<FRegister>(fs + 1));
1279 } else {
1280 Mthc1(rt, fs);
1281 }
1282}
1283
jeffhao7fbee072012-08-24 17:56:54 -07001284void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001285 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001286}
1287
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001288void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1289 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001290}
1291
1292void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001293 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001294}
1295
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001296void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1297 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001298}
1299
1300void MipsAssembler::Break() {
1301 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1302 static_cast<Register>(0), 0, 0xD);
1303}
1304
jeffhao07030602012-09-26 14:33:14 -07001305void MipsAssembler::Nop() {
1306 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1307}
1308
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001309void MipsAssembler::Move(Register rd, Register rs) {
1310 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001311}
1312
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001313void MipsAssembler::Clear(Register rd) {
1314 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001315}
1316
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001317void MipsAssembler::Not(Register rd, Register rs) {
1318 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001319}
1320
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001321void MipsAssembler::Push(Register rs) {
1322 IncreaseFrameSize(kMipsWordSize);
1323 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001324}
1325
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001326void MipsAssembler::Pop(Register rd) {
1327 Lw(rd, SP, 0);
1328 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001329}
1330
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001331void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1332 Lw(rd, SP, 0);
1333 Jr(rt);
1334 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001335}
1336
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001337void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1338 if (IsUint<16>(value)) {
1339 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1340 Ori(rd, ZERO, value);
1341 } else if (IsInt<16>(value)) {
1342 // Use ADD with (signed) immediate to encode 16b signed int.
1343 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07001344 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001345 Lui(rd, High16Bits(value));
1346 if (value & 0xFFFF)
1347 Ori(rd, rd, Low16Bits(value));
1348 }
1349}
1350
1351void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001352 uint32_t low = Low32Bits(value);
1353 uint32_t high = High32Bits(value);
1354 LoadConst32(reg_lo, low);
1355 if (high != low) {
1356 LoadConst32(reg_hi, high);
1357 } else {
1358 Move(reg_hi, reg_lo);
1359 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001360}
1361
1362void MipsAssembler::StoreConst32ToOffset(int32_t value,
1363 Register base,
1364 int32_t offset,
1365 Register temp) {
1366 if (!IsInt<16>(offset)) {
1367 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1368 LoadConst32(AT, offset);
1369 Addu(AT, AT, base);
1370 base = AT;
1371 offset = 0;
1372 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001373 if (value == 0) {
1374 temp = ZERO;
1375 } else {
1376 LoadConst32(temp, value);
1377 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001378 Sw(temp, base, offset);
1379}
1380
1381void MipsAssembler::StoreConst64ToOffset(int64_t value,
1382 Register base,
1383 int32_t offset,
1384 Register temp) {
1385 // IsInt<16> must be passed a signed value.
1386 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
1387 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1388 LoadConst32(AT, offset);
1389 Addu(AT, AT, base);
1390 base = AT;
1391 offset = 0;
1392 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001393 uint32_t low = Low32Bits(value);
1394 uint32_t high = High32Bits(value);
1395 if (low == 0) {
1396 Sw(ZERO, base, offset);
1397 } else {
1398 LoadConst32(temp, low);
1399 Sw(temp, base, offset);
1400 }
1401 if (high == 0) {
1402 Sw(ZERO, base, offset + kMipsWordSize);
1403 } else {
1404 if (high != low) {
1405 LoadConst32(temp, high);
1406 }
1407 Sw(temp, base, offset + kMipsWordSize);
1408 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001409}
1410
1411void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001412 if (value == 0) {
1413 temp = ZERO;
1414 } else {
1415 LoadConst32(temp, value);
1416 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001417 Mtc1(temp, r);
1418}
1419
1420void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001421 uint32_t low = Low32Bits(value);
1422 uint32_t high = High32Bits(value);
1423 if (low == 0) {
1424 Mtc1(ZERO, rd);
1425 } else {
1426 LoadConst32(temp, low);
1427 Mtc1(temp, rd);
1428 }
1429 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001430 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001431 } else {
1432 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001433 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001434 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001435}
1436
1437void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1438 if (IsInt<16>(value)) {
1439 Addiu(rt, rs, value);
1440 } else {
1441 LoadConst32(temp, value);
1442 Addu(rt, rs, temp);
1443 }
1444}
1445
1446void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1447 MipsAssembler::Branch::Type short_type,
1448 MipsAssembler::Branch::Type long_type) {
1449 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1450}
1451
1452void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
1453 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1454 if (is_r6) {
1455 // R6
1456 if (is_call) {
1457 InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1458 } else if (condition_ == kUncond) {
1459 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1460 } else {
1461 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1462 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1463 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1464 } else {
1465 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1466 }
1467 }
1468 } else {
1469 // R2
1470 if (is_call) {
1471 InitShortOrLong(offset_size, kCall, kLongCall);
1472 } else if (condition_ == kUncond) {
1473 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1474 } else {
1475 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1476 }
1477 }
1478 old_type_ = type_;
1479}
1480
1481bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1482 switch (condition) {
1483 case kCondLT:
1484 case kCondGT:
1485 case kCondNE:
1486 case kCondLTU:
1487 return lhs == rhs;
1488 default:
1489 return false;
1490 }
1491}
1492
1493bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1494 switch (condition) {
1495 case kUncond:
1496 return true;
1497 case kCondGE:
1498 case kCondLE:
1499 case kCondEQ:
1500 case kCondGEU:
1501 return lhs == rhs;
1502 default:
1503 return false;
1504 }
1505}
1506
1507MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
1508 : old_location_(location),
1509 location_(location),
1510 target_(target),
1511 lhs_reg_(0),
1512 rhs_reg_(0),
1513 condition_(kUncond) {
1514 InitializeType(false, is_r6);
1515}
1516
1517MipsAssembler::Branch::Branch(bool is_r6,
1518 uint32_t location,
1519 uint32_t target,
1520 MipsAssembler::BranchCondition condition,
1521 Register lhs_reg,
1522 Register rhs_reg)
1523 : old_location_(location),
1524 location_(location),
1525 target_(target),
1526 lhs_reg_(lhs_reg),
1527 rhs_reg_(rhs_reg),
1528 condition_(condition) {
1529 CHECK_NE(condition, kUncond);
1530 switch (condition) {
1531 case kCondLT:
1532 case kCondGE:
1533 case kCondLE:
1534 case kCondGT:
1535 case kCondLTU:
1536 case kCondGEU:
1537 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1538 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1539 // We leave this up to the caller.
1540 CHECK(is_r6);
1541 FALLTHROUGH_INTENDED;
1542 case kCondEQ:
1543 case kCondNE:
1544 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1545 // To compare with 0, use dedicated kCond*Z conditions.
1546 CHECK_NE(lhs_reg, ZERO);
1547 CHECK_NE(rhs_reg, ZERO);
1548 break;
1549 case kCondLTZ:
1550 case kCondGEZ:
1551 case kCondLEZ:
1552 case kCondGTZ:
1553 case kCondEQZ:
1554 case kCondNEZ:
1555 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1556 CHECK_NE(lhs_reg, ZERO);
1557 CHECK_EQ(rhs_reg, ZERO);
1558 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001559 case kCondF:
1560 case kCondT:
1561 CHECK_EQ(rhs_reg, ZERO);
1562 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001563 case kUncond:
1564 UNREACHABLE();
1565 }
1566 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1567 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1568 // Branch condition is always true, make the branch unconditional.
1569 condition_ = kUncond;
1570 }
1571 InitializeType(false, is_r6);
1572}
1573
1574MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
1575 : old_location_(location),
1576 location_(location),
1577 target_(target),
1578 lhs_reg_(indirect_reg),
1579 rhs_reg_(0),
1580 condition_(kUncond) {
1581 CHECK_NE(indirect_reg, ZERO);
1582 CHECK_NE(indirect_reg, AT);
1583 InitializeType(true, is_r6);
1584}
1585
1586MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1587 MipsAssembler::BranchCondition cond) {
1588 switch (cond) {
1589 case kCondLT:
1590 return kCondGE;
1591 case kCondGE:
1592 return kCondLT;
1593 case kCondLE:
1594 return kCondGT;
1595 case kCondGT:
1596 return kCondLE;
1597 case kCondLTZ:
1598 return kCondGEZ;
1599 case kCondGEZ:
1600 return kCondLTZ;
1601 case kCondLEZ:
1602 return kCondGTZ;
1603 case kCondGTZ:
1604 return kCondLEZ;
1605 case kCondEQ:
1606 return kCondNE;
1607 case kCondNE:
1608 return kCondEQ;
1609 case kCondEQZ:
1610 return kCondNEZ;
1611 case kCondNEZ:
1612 return kCondEQZ;
1613 case kCondLTU:
1614 return kCondGEU;
1615 case kCondGEU:
1616 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001617 case kCondF:
1618 return kCondT;
1619 case kCondT:
1620 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001621 case kUncond:
1622 LOG(FATAL) << "Unexpected branch condition " << cond;
1623 }
1624 UNREACHABLE();
1625}
1626
1627MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1628 return type_;
1629}
1630
1631MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1632 return condition_;
1633}
1634
1635Register MipsAssembler::Branch::GetLeftRegister() const {
1636 return static_cast<Register>(lhs_reg_);
1637}
1638
1639Register MipsAssembler::Branch::GetRightRegister() const {
1640 return static_cast<Register>(rhs_reg_);
1641}
1642
1643uint32_t MipsAssembler::Branch::GetTarget() const {
1644 return target_;
1645}
1646
1647uint32_t MipsAssembler::Branch::GetLocation() const {
1648 return location_;
1649}
1650
1651uint32_t MipsAssembler::Branch::GetOldLocation() const {
1652 return old_location_;
1653}
1654
1655uint32_t MipsAssembler::Branch::GetLength() const {
1656 return branch_info_[type_].length;
1657}
1658
1659uint32_t MipsAssembler::Branch::GetOldLength() const {
1660 return branch_info_[old_type_].length;
1661}
1662
1663uint32_t MipsAssembler::Branch::GetSize() const {
1664 return GetLength() * sizeof(uint32_t);
1665}
1666
1667uint32_t MipsAssembler::Branch::GetOldSize() const {
1668 return GetOldLength() * sizeof(uint32_t);
1669}
1670
1671uint32_t MipsAssembler::Branch::GetEndLocation() const {
1672 return GetLocation() + GetSize();
1673}
1674
1675uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1676 return GetOldLocation() + GetOldSize();
1677}
1678
1679bool MipsAssembler::Branch::IsLong() const {
1680 switch (type_) {
1681 // R2 short branches.
1682 case kUncondBranch:
1683 case kCondBranch:
1684 case kCall:
1685 // R6 short branches.
1686 case kR6UncondBranch:
1687 case kR6CondBranch:
1688 case kR6Call:
1689 return false;
1690 // R2 long branches.
1691 case kLongUncondBranch:
1692 case kLongCondBranch:
1693 case kLongCall:
1694 // R6 long branches.
1695 case kR6LongUncondBranch:
1696 case kR6LongCondBranch:
1697 case kR6LongCall:
1698 return true;
1699 }
1700 UNREACHABLE();
1701}
1702
1703bool MipsAssembler::Branch::IsResolved() const {
1704 return target_ != kUnresolved;
1705}
1706
1707MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1708 OffsetBits offset_size =
1709 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1710 ? kOffset23
1711 : branch_info_[type_].offset_size;
1712 return offset_size;
1713}
1714
1715MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1716 uint32_t target) {
1717 // For unresolved targets assume the shortest encoding
1718 // (later it will be made longer if needed).
1719 if (target == kUnresolved)
1720 return kOffset16;
1721 int64_t distance = static_cast<int64_t>(target) - location;
1722 // To simplify calculations in composite branches consisting of multiple instructions
1723 // bump up the distance by a value larger than the max byte size of a composite branch.
1724 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1725 if (IsInt<kOffset16>(distance))
1726 return kOffset16;
1727 else if (IsInt<kOffset18>(distance))
1728 return kOffset18;
1729 else if (IsInt<kOffset21>(distance))
1730 return kOffset21;
1731 else if (IsInt<kOffset23>(distance))
1732 return kOffset23;
1733 else if (IsInt<kOffset28>(distance))
1734 return kOffset28;
1735 return kOffset32;
1736}
1737
1738void MipsAssembler::Branch::Resolve(uint32_t target) {
1739 target_ = target;
1740}
1741
1742void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1743 if (location_ > expand_location) {
1744 location_ += delta;
1745 }
1746 if (!IsResolved()) {
1747 return; // Don't know the target yet.
1748 }
1749 if (target_ > expand_location) {
1750 target_ += delta;
1751 }
1752}
1753
1754void MipsAssembler::Branch::PromoteToLong() {
1755 switch (type_) {
1756 // R2 short branches.
1757 case kUncondBranch:
1758 type_ = kLongUncondBranch;
1759 break;
1760 case kCondBranch:
1761 type_ = kLongCondBranch;
1762 break;
1763 case kCall:
1764 type_ = kLongCall;
1765 break;
1766 // R6 short branches.
1767 case kR6UncondBranch:
1768 type_ = kR6LongUncondBranch;
1769 break;
1770 case kR6CondBranch:
1771 type_ = kR6LongCondBranch;
1772 break;
1773 case kR6Call:
1774 type_ = kR6LongCall;
1775 break;
1776 default:
1777 // Note: 'type_' is already long.
1778 break;
1779 }
1780 CHECK(IsLong());
1781}
1782
1783uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1784 // If the branch is still unresolved or already long, nothing to do.
1785 if (IsLong() || !IsResolved()) {
1786 return 0;
1787 }
1788 // Promote the short branch to long if the offset size is too small
1789 // to hold the distance between location_ and target_.
1790 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1791 PromoteToLong();
1792 uint32_t old_size = GetOldSize();
1793 uint32_t new_size = GetSize();
1794 CHECK_GT(new_size, old_size);
1795 return new_size - old_size;
1796 }
1797 // The following logic is for debugging/testing purposes.
1798 // Promote some short branches to long when it's not really required.
1799 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1800 int64_t distance = static_cast<int64_t>(target_) - location_;
1801 distance = (distance >= 0) ? distance : -distance;
1802 if (distance >= max_short_distance) {
1803 PromoteToLong();
1804 uint32_t old_size = GetOldSize();
1805 uint32_t new_size = GetSize();
1806 CHECK_GT(new_size, old_size);
1807 return new_size - old_size;
1808 }
1809 }
1810 return 0;
1811}
1812
1813uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1814 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1815}
1816
1817uint32_t MipsAssembler::Branch::GetOffset() const {
1818 CHECK(IsResolved());
1819 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1820 // Calculate the byte distance between instructions and also account for
1821 // different PC-relative origins.
1822 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1823 // Prepare the offset for encoding into the instruction(s).
1824 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1825 return offset;
1826}
1827
1828MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1829 CHECK_LT(branch_id, branches_.size());
1830 return &branches_[branch_id];
1831}
1832
1833const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1834 CHECK_LT(branch_id, branches_.size());
1835 return &branches_[branch_id];
1836}
1837
1838void MipsAssembler::Bind(MipsLabel* label) {
1839 CHECK(!label->IsBound());
1840 uint32_t bound_pc = buffer_.Size();
1841
1842 // Walk the list of branches referring to and preceding this label.
1843 // Store the previously unknown target addresses in them.
1844 while (label->IsLinked()) {
1845 uint32_t branch_id = label->Position();
1846 Branch* branch = GetBranch(branch_id);
1847 branch->Resolve(bound_pc);
1848
1849 uint32_t branch_location = branch->GetLocation();
1850 // Extract the location of the previous branch in the list (walking the list backwards;
1851 // the previous branch ID was stored in the space reserved for this branch).
1852 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1853
1854 // On to the previous branch in the list...
1855 label->position_ = prev;
1856 }
1857
1858 // Now make the label object contain its own location (relative to the end of the preceding
1859 // branch, if any; it will be used by the branches referring to and following this label).
1860 label->prev_branch_id_plus_one_ = branches_.size();
1861 if (label->prev_branch_id_plus_one_) {
1862 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1863 const Branch* branch = GetBranch(branch_id);
1864 bound_pc -= branch->GetEndLocation();
1865 }
1866 label->BindTo(bound_pc);
1867}
1868
1869uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1870 CHECK(label->IsBound());
1871 uint32_t target = label->Position();
1872 if (label->prev_branch_id_plus_one_) {
1873 // Get label location based on the branch preceding it.
1874 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1875 const Branch* branch = GetBranch(branch_id);
1876 target += branch->GetEndLocation();
1877 }
1878 return target;
1879}
1880
1881uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1882 // We can reconstruct the adjustment by going through all the branches from the beginning
1883 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1884 // with increasing old_position, we can use the data from last AdjustedPosition() to
1885 // continue where we left off and the whole loop should be O(m+n) where m is the number
1886 // of positions to adjust and n is the number of branches.
1887 if (old_position < last_old_position_) {
1888 last_position_adjustment_ = 0;
1889 last_old_position_ = 0;
1890 last_branch_id_ = 0;
1891 }
1892 while (last_branch_id_ != branches_.size()) {
1893 const Branch* branch = GetBranch(last_branch_id_);
1894 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1895 break;
1896 }
1897 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1898 ++last_branch_id_;
1899 }
1900 last_old_position_ = old_position;
1901 return old_position + last_position_adjustment_;
1902}
1903
1904void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1905 uint32_t length = branches_.back().GetLength();
1906 if (!label->IsBound()) {
1907 // Branch forward (to a following label), distance is unknown.
1908 // The first branch forward will contain 0, serving as the terminator of
1909 // the list of forward-reaching branches.
1910 Emit(label->position_);
1911 length--;
1912 // Now make the label object point to this branch
1913 // (this forms a linked list of branches preceding this label).
1914 uint32_t branch_id = branches_.size() - 1;
1915 label->LinkTo(branch_id);
1916 }
1917 // Reserve space for the branch.
1918 while (length--) {
1919 Nop();
1920 }
1921}
1922
1923void MipsAssembler::Buncond(MipsLabel* label) {
1924 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1925 branches_.emplace_back(IsR6(), buffer_.Size(), target);
1926 FinalizeLabeledBranch(label);
1927}
1928
1929void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1930 // If lhs = rhs, this can be a NOP.
1931 if (Branch::IsNop(condition, lhs, rhs)) {
1932 return;
1933 }
1934 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1935 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1936 FinalizeLabeledBranch(label);
1937}
1938
1939void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1940 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1941 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1942 FinalizeLabeledBranch(label);
1943}
1944
1945void MipsAssembler::PromoteBranches() {
1946 // Promote short branches to long as necessary.
1947 bool changed;
1948 do {
1949 changed = false;
1950 for (auto& branch : branches_) {
1951 CHECK(branch.IsResolved());
1952 uint32_t delta = branch.PromoteIfNeeded();
1953 // If this branch has been promoted and needs to expand in size,
1954 // relocate all branches by the expansion size.
1955 if (delta) {
1956 changed = true;
1957 uint32_t expand_location = branch.GetLocation();
1958 for (auto& branch2 : branches_) {
1959 branch2.Relocate(expand_location, delta);
1960 }
1961 }
1962 }
1963 } while (changed);
1964
1965 // Account for branch expansion by resizing the code buffer
1966 // and moving the code in it to its final location.
1967 size_t branch_count = branches_.size();
1968 if (branch_count > 0) {
1969 // Resize.
1970 Branch& last_branch = branches_[branch_count - 1];
1971 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1972 uint32_t old_size = buffer_.Size();
1973 buffer_.Resize(old_size + size_delta);
1974 // Move the code residing between branch placeholders.
1975 uint32_t end = old_size;
1976 for (size_t i = branch_count; i > 0; ) {
1977 Branch& branch = branches_[--i];
1978 uint32_t size = end - branch.GetOldEndLocation();
1979 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1980 end = branch.GetOldLocation();
1981 }
1982 }
1983}
1984
1985// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1986const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
1987 // R2 short branches.
1988 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
1989 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
1990 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall
1991 // R2 long branches.
1992 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1993 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
1994 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
1995 // R6 short branches.
1996 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
1997 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
1998 // Exception: kOffset23 for beqzc/bnezc.
1999 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call
2000 // R6 long branches.
2001 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
2002 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
2003 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
2004};
2005
2006// Note: make sure branch_info_[] and mitBranch() are kept synchronized.
2007void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
2008 CHECK_EQ(overwriting_, true);
2009 overwrite_location_ = branch->GetLocation();
2010 uint32_t offset = branch->GetOffset();
2011 BranchCondition condition = branch->GetCondition();
2012 Register lhs = branch->GetLeftRegister();
2013 Register rhs = branch->GetRightRegister();
2014 switch (branch->GetType()) {
2015 // R2 short branches.
2016 case Branch::kUncondBranch:
2017 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2018 B(offset);
2019 Nop(); // TODO: improve by filling the delay slot.
2020 break;
2021 case Branch::kCondBranch:
2022 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002023 EmitBcondR2(condition, lhs, rhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002024 Nop(); // TODO: improve by filling the delay slot.
2025 break;
2026 case Branch::kCall:
2027 Nal();
2028 Nop(); // TODO: is this NOP really needed here?
2029 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2030 Addiu(lhs, RA, offset);
2031 Jalr(lhs);
2032 Nop();
2033 break;
2034
2035 // R2 long branches.
2036 case Branch::kLongUncondBranch:
2037 // To get the value of the PC register we need to use the NAL instruction.
2038 // NAL clobbers the RA register. However, RA must be preserved if the
2039 // method is compiled without the entry/exit sequences that would take care
2040 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
2041 // So, we need to preserve RA in some temporary storage ourselves. The AT
2042 // register can't be used for this because we need it to load a constant
2043 // which will be added to the value that NAL stores in RA. And we can't
2044 // use T9 for this in the context of the JNI compiler, which uses it
2045 // as a scratch register (see InterproceduralScratchRegister()).
2046 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
2047 // we'd also need to use the ROTR instruction, which requires no less than
2048 // MIPSR2.
2049 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
2050 // (LO or HI) or even a floating-point register, but that doesn't seem
2051 // like a nice solution. We may want this to work on both R6 and pre-R6.
2052 // For now simply use the stack for RA. This should be OK since for the
2053 // vast majority of code a short PC-relative branch is sufficient.
2054 // TODO: can this be improved?
2055 Push(RA);
2056 Nal();
2057 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2058 Lui(AT, High16Bits(offset));
2059 Ori(AT, AT, Low16Bits(offset));
2060 Addu(AT, AT, RA);
2061 Lw(RA, SP, 0);
2062 Jr(AT);
2063 DecreaseFrameSize(kMipsWordSize);
2064 break;
2065 case Branch::kLongCondBranch:
2066 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
2067 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
2068 // number of instructions skipped:
2069 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002070 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002071 Push(RA);
2072 Nal();
2073 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2074 Lui(AT, High16Bits(offset));
2075 Ori(AT, AT, Low16Bits(offset));
2076 Addu(AT, AT, RA);
2077 Lw(RA, SP, 0);
2078 Jr(AT);
2079 DecreaseFrameSize(kMipsWordSize);
2080 break;
2081 case Branch::kLongCall:
2082 Nal();
2083 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2084 Lui(AT, High16Bits(offset));
2085 Ori(AT, AT, Low16Bits(offset));
2086 Addu(lhs, AT, RA);
2087 Jalr(lhs);
2088 Nop();
2089 break;
2090
2091 // R6 short branches.
2092 case Branch::kR6UncondBranch:
2093 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2094 Bc(offset);
2095 break;
2096 case Branch::kR6CondBranch:
2097 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002098 EmitBcondR6(condition, lhs, rhs, offset);
2099 Nop(); // TODO: improve by filling the forbidden/delay slot.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002100 break;
2101 case Branch::kR6Call:
2102 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2103 Addiupc(lhs, offset);
2104 Jialc(lhs, 0);
2105 break;
2106
2107 // R6 long branches.
2108 case Branch::kR6LongUncondBranch:
2109 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2110 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2111 Auipc(AT, High16Bits(offset));
2112 Jic(AT, Low16Bits(offset));
2113 break;
2114 case Branch::kR6LongCondBranch:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002115 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002116 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2117 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2118 Auipc(AT, High16Bits(offset));
2119 Jic(AT, Low16Bits(offset));
2120 break;
2121 case Branch::kR6LongCall:
2122 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
2123 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2124 Auipc(lhs, High16Bits(offset));
2125 Addiu(lhs, lhs, Low16Bits(offset));
2126 Jialc(lhs, 0);
2127 break;
2128 }
2129 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2130 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
2131}
2132
2133void MipsAssembler::B(MipsLabel* label) {
2134 Buncond(label);
2135}
2136
2137void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
2138 Call(label, indirect_reg);
2139}
2140
2141void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
2142 Bcond(label, kCondEQ, rs, rt);
2143}
2144
2145void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
2146 Bcond(label, kCondNE, rs, rt);
2147}
2148
2149void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
2150 Bcond(label, kCondEQZ, rt);
2151}
2152
2153void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2154 Bcond(label, kCondNEZ, rt);
2155}
2156
2157void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2158 Bcond(label, kCondLTZ, rt);
2159}
2160
2161void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2162 Bcond(label, kCondGEZ, rt);
2163}
2164
2165void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2166 Bcond(label, kCondLEZ, rt);
2167}
2168
2169void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2170 Bcond(label, kCondGTZ, rt);
2171}
2172
2173void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
2174 if (IsR6()) {
2175 Bcond(label, kCondLT, rs, rt);
2176 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
2177 // Synthesize the instruction (not available on R2).
2178 Slt(AT, rs, rt);
2179 Bnez(AT, label);
2180 }
2181}
2182
2183void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
2184 if (IsR6()) {
2185 Bcond(label, kCondGE, rs, rt);
2186 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
2187 B(label);
2188 } else {
2189 // Synthesize the instruction (not available on R2).
2190 Slt(AT, rs, rt);
2191 Beqz(AT, label);
2192 }
2193}
2194
2195void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
2196 if (IsR6()) {
2197 Bcond(label, kCondLTU, rs, rt);
2198 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
2199 // Synthesize the instruction (not available on R2).
2200 Sltu(AT, rs, rt);
2201 Bnez(AT, label);
2202 }
2203}
2204
2205void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
2206 if (IsR6()) {
2207 Bcond(label, kCondGEU, rs, rt);
2208 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
2209 B(label);
2210 } else {
2211 // Synthesize the instruction (not available on R2).
2212 Sltu(AT, rs, rt);
2213 Beqz(AT, label);
jeffhao7fbee072012-08-24 17:56:54 -07002214 }
2215}
2216
Chris Larsenb74353a2015-11-20 09:07:09 -08002217void MipsAssembler::Bc1f(MipsLabel* label) {
2218 Bc1f(0, label);
2219}
2220
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002221void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2222 CHECK(IsUint<3>(cc)) << cc;
2223 Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2224}
2225
Chris Larsenb74353a2015-11-20 09:07:09 -08002226void MipsAssembler::Bc1t(MipsLabel* label) {
2227 Bc1t(0, label);
2228}
2229
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002230void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2231 CHECK(IsUint<3>(cc)) << cc;
2232 Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2233}
2234
2235void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2236 Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2237}
2238
2239void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2240 Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2241}
2242
jeffhao7fbee072012-08-24 17:56:54 -07002243void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
2244 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002245 // IsInt<16> must be passed a signed value.
2246 if (!IsInt<16>(offset) ||
2247 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2248 LoadConst32(AT, offset);
2249 Addu(AT, AT, base);
2250 base = AT;
2251 offset = 0;
2252 }
2253
jeffhao7fbee072012-08-24 17:56:54 -07002254 switch (type) {
2255 case kLoadSignedByte:
2256 Lb(reg, base, offset);
2257 break;
2258 case kLoadUnsignedByte:
2259 Lbu(reg, base, offset);
2260 break;
2261 case kLoadSignedHalfword:
2262 Lh(reg, base, offset);
2263 break;
2264 case kLoadUnsignedHalfword:
2265 Lhu(reg, base, offset);
2266 break;
2267 case kLoadWord:
2268 Lw(reg, base, offset);
2269 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002270 case kLoadDoubleword:
2271 if (reg == base) {
2272 // This will clobber the base when loading the lower register. Since we have to load the
2273 // higher register as well, this will fail. Solution: reverse the order.
2274 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2275 Lw(reg, base, offset);
2276 } else {
2277 Lw(reg, base, offset);
2278 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2279 }
jeffhao7fbee072012-08-24 17:56:54 -07002280 break;
2281 default:
2282 LOG(FATAL) << "UNREACHABLE";
2283 }
2284}
2285
2286void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002287 if (!IsInt<16>(offset)) {
2288 LoadConst32(AT, offset);
2289 Addu(AT, AT, base);
2290 base = AT;
2291 offset = 0;
2292 }
2293
jeffhao7fbee072012-08-24 17:56:54 -07002294 Lwc1(reg, base, offset);
2295}
2296
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002297void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
2298 // IsInt<16> must be passed a signed value.
2299 if (!IsInt<16>(offset) ||
2300 (!IsAligned<kMipsDoublewordSize>(offset) &&
2301 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2302 LoadConst32(AT, offset);
2303 Addu(AT, AT, base);
2304 base = AT;
2305 offset = 0;
2306 }
2307
2308 if (offset & 0x7) {
2309 if (Is32BitFPU()) {
2310 Lwc1(reg, base, offset);
2311 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2312 } else {
2313 // 64-bit FPU.
2314 Lwc1(reg, base, offset);
2315 Lw(T8, base, offset + kMipsWordSize);
2316 Mthc1(T8, reg);
2317 }
2318 } else {
2319 Ldc1(reg, base, offset);
2320 }
2321}
2322
2323void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
2324 size_t size) {
2325 MipsManagedRegister dst = m_dst.AsMips();
2326 if (dst.IsNoRegister()) {
2327 CHECK_EQ(0u, size) << dst;
2328 } else if (dst.IsCoreRegister()) {
2329 CHECK_EQ(kMipsWordSize, size) << dst;
2330 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
2331 } else if (dst.IsRegisterPair()) {
2332 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2333 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
2334 } else if (dst.IsFRegister()) {
2335 if (size == kMipsWordSize) {
2336 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
2337 } else {
2338 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2339 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
2340 }
2341 }
jeffhao7fbee072012-08-24 17:56:54 -07002342}
2343
2344void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
2345 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002346 // IsInt<16> must be passed a signed value.
2347 if (!IsInt<16>(offset) ||
2348 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2349 LoadConst32(AT, offset);
2350 Addu(AT, AT, base);
2351 base = AT;
2352 offset = 0;
2353 }
2354
jeffhao7fbee072012-08-24 17:56:54 -07002355 switch (type) {
2356 case kStoreByte:
2357 Sb(reg, base, offset);
2358 break;
2359 case kStoreHalfword:
2360 Sh(reg, base, offset);
2361 break;
2362 case kStoreWord:
2363 Sw(reg, base, offset);
2364 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002365 case kStoreDoubleword:
2366 CHECK_NE(reg, base);
2367 CHECK_NE(static_cast<Register>(reg + 1), base);
2368 Sw(reg, base, offset);
2369 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002370 break;
2371 default:
2372 LOG(FATAL) << "UNREACHABLE";
2373 }
2374}
2375
Goran Jakovljevicff734982015-08-24 12:58:55 +00002376void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002377 if (!IsInt<16>(offset)) {
2378 LoadConst32(AT, offset);
2379 Addu(AT, AT, base);
2380 base = AT;
2381 offset = 0;
2382 }
2383
jeffhao7fbee072012-08-24 17:56:54 -07002384 Swc1(reg, base, offset);
2385}
2386
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002387void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
2388 // IsInt<16> must be passed a signed value.
2389 if (!IsInt<16>(offset) ||
2390 (!IsAligned<kMipsDoublewordSize>(offset) &&
2391 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2392 LoadConst32(AT, offset);
2393 Addu(AT, AT, base);
2394 base = AT;
2395 offset = 0;
2396 }
2397
2398 if (offset & 0x7) {
2399 if (Is32BitFPU()) {
2400 Swc1(reg, base, offset);
2401 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2402 } else {
2403 // 64-bit FPU.
2404 Mfhc1(T8, reg);
2405 Swc1(reg, base, offset);
2406 Sw(T8, base, offset + kMipsWordSize);
2407 }
2408 } else {
2409 Sdc1(reg, base, offset);
2410 }
jeffhao7fbee072012-08-24 17:56:54 -07002411}
2412
David Srbeckydd973932015-04-07 20:29:48 +01002413static dwarf::Reg DWARFReg(Register reg) {
2414 return dwarf::Reg::MipsCore(static_cast<int>(reg));
2415}
2416
Ian Rogers790a6b72014-04-01 10:36:00 -07002417constexpr size_t kFramePointerSize = 4;
2418
jeffhao7fbee072012-08-24 17:56:54 -07002419void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
2420 const std::vector<ManagedRegister>& callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07002421 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07002422 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002423 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07002424
2425 // Increase frame to required size.
2426 IncreaseFrameSize(frame_size);
2427
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002428 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002429 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002430 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002431 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002432 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07002433 stack_offset -= kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002434 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2435 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002436 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002437 }
2438
2439 // Write out Method*.
2440 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
2441
2442 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00002443 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002444 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00002445 MipsManagedRegister reg = entry_spills.at(i).AsMips();
2446 if (reg.IsNoRegister()) {
2447 ManagedRegisterSpill spill = entry_spills.at(i);
2448 offset += spill.getSize();
2449 } else if (reg.IsCoreRegister()) {
2450 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002451 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002452 } else if (reg.IsFRegister()) {
2453 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002454 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002455 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002456 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
2457 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002458 }
jeffhao7fbee072012-08-24 17:56:54 -07002459 }
2460}
2461
2462void MipsAssembler::RemoveFrame(size_t frame_size,
2463 const std::vector<ManagedRegister>& callee_save_regs) {
2464 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002465 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002466 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07002467
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002468 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002469 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002470 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
2471 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2472 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002473 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07002474 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002475 }
2476 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002477 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07002478
2479 // Decrease frame to required size.
2480 DecreaseFrameSize(frame_size);
jeffhao07030602012-09-26 14:33:14 -07002481
2482 // Then jump to the return address.
2483 Jr(RA);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002484 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002485
2486 // The CFI should be restored for any code that follows the exit block.
2487 cfi_.RestoreState();
2488 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07002489}
2490
2491void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002492 CHECK_ALIGNED(adjust, kFramePointerSize);
2493 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002494 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002495 if (overwriting_) {
2496 cfi_.OverrideDelayedPC(overwrite_location_);
2497 }
jeffhao7fbee072012-08-24 17:56:54 -07002498}
2499
2500void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002501 CHECK_ALIGNED(adjust, kFramePointerSize);
2502 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002503 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002504 if (overwriting_) {
2505 cfi_.OverrideDelayedPC(overwrite_location_);
2506 }
jeffhao7fbee072012-08-24 17:56:54 -07002507}
2508
2509void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2510 MipsManagedRegister src = msrc.AsMips();
2511 if (src.IsNoRegister()) {
2512 CHECK_EQ(0u, size);
2513 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002514 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002515 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2516 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002517 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002518 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
2519 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002520 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002521 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002522 if (size == kMipsWordSize) {
2523 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
2524 } else {
2525 CHECK_EQ(kMipsDoublewordSize, size);
2526 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
2527 }
jeffhao7fbee072012-08-24 17:56:54 -07002528 }
2529}
2530
2531void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2532 MipsManagedRegister src = msrc.AsMips();
2533 CHECK(src.IsCoreRegister());
2534 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2535}
2536
2537void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2538 MipsManagedRegister src = msrc.AsMips();
2539 CHECK(src.IsCoreRegister());
2540 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2541}
2542
2543void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2544 ManagedRegister mscratch) {
2545 MipsManagedRegister scratch = mscratch.AsMips();
2546 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002547 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07002548 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2549}
2550
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002551void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
jeffhao7fbee072012-08-24 17:56:54 -07002552 ManagedRegister mscratch) {
2553 MipsManagedRegister scratch = mscratch.AsMips();
2554 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002555 // Is this function even referenced anywhere else in the code?
2556 LoadConst32(scratch.AsCoreRegister(), imm);
2557 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
2558}
2559
2560void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2561 FrameOffset fr_offs,
2562 ManagedRegister mscratch) {
2563 MipsManagedRegister scratch = mscratch.AsMips();
2564 CHECK(scratch.IsCoreRegister()) << scratch;
2565 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002566 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2567 S1, thr_offs.Int32Value());
2568}
2569
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002570void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002571 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2572}
2573
2574void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2575 FrameOffset in_off, ManagedRegister mscratch) {
2576 MipsManagedRegister src = msrc.AsMips();
2577 MipsManagedRegister scratch = mscratch.AsMips();
2578 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2579 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002580 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002581}
2582
2583void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2584 return EmitLoad(mdest, SP, src.Int32Value(), size);
2585}
2586
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002587void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2588 ThreadOffset<kMipsWordSize> src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002589 return EmitLoad(mdest, S1, src.Int32Value(), size);
2590}
2591
2592void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2593 MipsManagedRegister dest = mdest.AsMips();
2594 CHECK(dest.IsCoreRegister());
2595 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
2596}
2597
Mathieu Chartiere401d142015-04-22 13:56:20 -07002598void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002599 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07002600 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002601 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002602 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2603 base.AsMips().AsCoreRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002604 if (kPoisonHeapReferences && unpoison_reference) {
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08002605 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
2606 }
jeffhao7fbee072012-08-24 17:56:54 -07002607}
2608
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002609void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002610 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002611 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002612 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2613 base.AsMips().AsCoreRegister(), offs.Int32Value());
2614}
2615
Ian Rogersdd7624d2014-03-14 17:43:00 -07002616void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002617 ThreadOffset<kMipsWordSize> offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002618 MipsManagedRegister dest = mdest.AsMips();
2619 CHECK(dest.IsCoreRegister());
2620 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
2621}
2622
2623void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2624 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2625}
2626
2627void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2628 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2629}
2630
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002631void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002632 MipsManagedRegister dest = mdest.AsMips();
2633 MipsManagedRegister src = msrc.AsMips();
2634 if (!dest.Equals(src)) {
2635 if (dest.IsCoreRegister()) {
2636 CHECK(src.IsCoreRegister()) << src;
2637 Move(dest.AsCoreRegister(), src.AsCoreRegister());
2638 } else if (dest.IsFRegister()) {
2639 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002640 if (size == kMipsWordSize) {
2641 MovS(dest.AsFRegister(), src.AsFRegister());
2642 } else {
2643 CHECK_EQ(kMipsDoublewordSize, size);
2644 MovD(dest.AsFRegister(), src.AsFRegister());
2645 }
jeffhao7fbee072012-08-24 17:56:54 -07002646 } else if (dest.IsDRegister()) {
2647 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002648 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07002649 } else {
2650 CHECK(dest.IsRegisterPair()) << dest;
2651 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002652 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07002653 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
2654 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2655 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2656 } else {
2657 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2658 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2659 }
2660 }
2661 }
2662}
2663
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002664void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002665 MipsManagedRegister scratch = mscratch.AsMips();
2666 CHECK(scratch.IsCoreRegister()) << scratch;
2667 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2668 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2669}
2670
Ian Rogersdd7624d2014-03-14 17:43:00 -07002671void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002672 ThreadOffset<kMipsWordSize> thr_offs,
2673 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002674 MipsManagedRegister scratch = mscratch.AsMips();
2675 CHECK(scratch.IsCoreRegister()) << scratch;
2676 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2677 S1, thr_offs.Int32Value());
2678 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2679 SP, fr_offs.Int32Value());
2680}
2681
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002682void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2683 FrameOffset fr_offs,
2684 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002685 MipsManagedRegister scratch = mscratch.AsMips();
2686 CHECK(scratch.IsCoreRegister()) << scratch;
2687 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2688 SP, fr_offs.Int32Value());
2689 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2690 S1, thr_offs.Int32Value());
2691}
2692
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002693void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002694 MipsManagedRegister scratch = mscratch.AsMips();
2695 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002696 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2697 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002698 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2699 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002700 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002701 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2702 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002703 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2704 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002705 }
2706}
2707
2708void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2709 ManagedRegister mscratch, size_t size) {
2710 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002711 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002712 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2713 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2714}
2715
2716void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2717 ManagedRegister mscratch, size_t size) {
2718 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002719 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002720 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2721 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2722}
2723
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002724void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2725 FrameOffset src_base ATTRIBUTE_UNUSED,
2726 Offset src_offset ATTRIBUTE_UNUSED,
2727 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2728 size_t size ATTRIBUTE_UNUSED) {
2729 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002730}
2731
2732void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2733 ManagedRegister src, Offset src_offset,
2734 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002735 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002736 Register scratch = mscratch.AsMips().AsCoreRegister();
2737 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2738 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2739}
2740
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002741void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2742 Offset dest_offset ATTRIBUTE_UNUSED,
2743 FrameOffset src ATTRIBUTE_UNUSED,
2744 Offset src_offset ATTRIBUTE_UNUSED,
2745 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2746 size_t size ATTRIBUTE_UNUSED) {
2747 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002748}
2749
2750void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002751 // TODO: sync?
2752 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002753}
2754
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002755void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002756 FrameOffset handle_scope_offset,
2757 ManagedRegister min_reg,
2758 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002759 MipsManagedRegister out_reg = mout_reg.AsMips();
2760 MipsManagedRegister in_reg = min_reg.AsMips();
2761 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2762 CHECK(out_reg.IsCoreRegister()) << out_reg;
2763 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002764 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002765 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2766 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002767 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07002768 if (in_reg.IsNoRegister()) {
2769 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002770 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002771 in_reg = out_reg;
2772 }
2773 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002774 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002775 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002776 Beqz(in_reg.AsCoreRegister(), &null_arg);
2777 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2778 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002779 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002780 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002781 }
2782}
2783
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002784void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002785 FrameOffset handle_scope_offset,
2786 ManagedRegister mscratch,
2787 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002788 MipsManagedRegister scratch = mscratch.AsMips();
2789 CHECK(scratch.IsCoreRegister()) << scratch;
2790 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002791 MipsLabel null_arg;
2792 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002793 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2794 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002795 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2796 Beqz(scratch.AsCoreRegister(), &null_arg);
2797 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2798 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002799 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002800 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002801 }
2802 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2803}
2804
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002805// Given a handle scope entry, load the associated reference.
2806void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002807 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07002808 MipsManagedRegister out_reg = mout_reg.AsMips();
2809 MipsManagedRegister in_reg = min_reg.AsMips();
2810 CHECK(out_reg.IsCoreRegister()) << out_reg;
2811 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002812 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07002813 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002814 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002815 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002816 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002817 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2818 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002819 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002820}
2821
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002822void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2823 bool could_be_null ATTRIBUTE_UNUSED) {
2824 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002825}
2826
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002827void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2828 bool could_be_null ATTRIBUTE_UNUSED) {
2829 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002830}
2831
2832void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2833 MipsManagedRegister base = mbase.AsMips();
2834 MipsManagedRegister scratch = mscratch.AsMips();
2835 CHECK(base.IsCoreRegister()) << base;
2836 CHECK(scratch.IsCoreRegister()) << scratch;
2837 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2838 base.AsCoreRegister(), offset.Int32Value());
2839 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002840 Nop();
2841 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002842}
2843
2844void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2845 MipsManagedRegister scratch = mscratch.AsMips();
2846 CHECK(scratch.IsCoreRegister()) << scratch;
2847 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002848 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002849 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2850 scratch.AsCoreRegister(), offset.Int32Value());
2851 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002852 Nop();
2853 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002854}
2855
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002856void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2857 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07002858 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002859}
2860
2861void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2862 Move(tr.AsMips().AsCoreRegister(), S1);
2863}
2864
2865void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002866 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07002867 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2868}
2869
jeffhao7fbee072012-08-24 17:56:54 -07002870void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2871 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002872 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07002873 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002874 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2875 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2876 // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2877 // For now use common for R2 and R6 instructions as this code must execute on both.
2878 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07002879}
2880
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002881void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2882 Bind(exception->Entry());
2883 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2884 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07002885 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002886 // Pass exception object as argument.
2887 // Don't care about preserving A0 as this call won't return.
2888 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2889 Move(A0, exception->scratch_.AsCoreRegister());
2890 // Set up call to Thread::Current()->pDeliverException.
2891 LoadFromOffset(kLoadWord, T9, S1,
2892 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2893 Jr(T9);
2894 Nop();
2895
2896 // Call never returns.
2897 Break();
jeffhao7fbee072012-08-24 17:56:54 -07002898}
2899
2900} // namespace mips
2901} // namespace art