blob: 9368301d07821e4d14f97181680102fc7c6faa44 [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
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700488void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
489 CHECK(!IsR6());
490 EmitI(0x30, base, rt, imm16);
491}
492
493void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
494 CHECK(!IsR6());
495 EmitI(0x38, base, rt, imm16);
496}
497
498void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
499 CHECK(IsR6());
500 CHECK(IsInt<9>(imm9));
501 EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36);
502}
503
504void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
505 CHECK(IsR6());
506 CHECK(IsInt<9>(imm9));
507 EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26);
508}
509
jeffhao7fbee072012-08-24 17:56:54 -0700510void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
511 EmitR(0, rs, rt, rd, 0, 0x2a);
512}
513
514void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
515 EmitR(0, rs, rt, rd, 0, 0x2b);
516}
517
518void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
519 EmitI(0xa, rs, rt, imm16);
520}
521
522void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
523 EmitI(0xb, rs, rt, imm16);
524}
525
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200526void MipsAssembler::B(uint16_t imm16) {
527 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
528}
529
530void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700531 EmitI(0x4, rs, rt, imm16);
532}
533
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200534void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700535 EmitI(0x5, rs, rt, imm16);
536}
537
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200538void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
539 Beq(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700540}
541
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200542void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
543 Bne(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700544}
545
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200546void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
547 EmitI(0x1, rt, static_cast<Register>(0), imm16);
548}
549
550void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
551 EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
552}
553
554void MipsAssembler::Blez(Register rt, uint16_t imm16) {
555 EmitI(0x6, rt, static_cast<Register>(0), imm16);
556}
557
558void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
559 EmitI(0x7, rt, static_cast<Register>(0), imm16);
560}
561
Chris Larsenb74353a2015-11-20 09:07:09 -0800562void MipsAssembler::Bc1f(uint16_t imm16) {
563 Bc1f(0, imm16);
564}
565
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800566void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
567 CHECK(!IsR6());
568 CHECK(IsUint<3>(cc)) << cc;
569 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16);
570}
571
Chris Larsenb74353a2015-11-20 09:07:09 -0800572void MipsAssembler::Bc1t(uint16_t imm16) {
573 Bc1t(0, imm16);
574}
575
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800576void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
577 CHECK(!IsR6());
578 CHECK(IsUint<3>(cc)) << cc;
579 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16);
580}
581
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200582void MipsAssembler::J(uint32_t addr26) {
583 EmitI26(0x2, addr26);
584}
585
586void MipsAssembler::Jal(uint32_t addr26) {
587 EmitI26(0x3, addr26);
588}
589
590void MipsAssembler::Jalr(Register rd, Register rs) {
591 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
jeffhao7fbee072012-08-24 17:56:54 -0700592}
593
594void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200595 Jalr(RA, rs);
596}
597
598void MipsAssembler::Jr(Register rs) {
599 Jalr(ZERO, rs);
600}
601
602void MipsAssembler::Nal() {
603 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
604}
605
606void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
607 CHECK(IsR6());
608 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
609}
610
611void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
612 CHECK(IsR6());
613 CHECK(IsUint<19>(imm19)) << imm19;
614 EmitI21(0x3B, rs, imm19);
615}
616
617void MipsAssembler::Bc(uint32_t imm26) {
618 CHECK(IsR6());
619 EmitI26(0x32, imm26);
620}
621
622void MipsAssembler::Jic(Register rt, uint16_t imm16) {
623 CHECK(IsR6());
624 EmitI(0x36, static_cast<Register>(0), rt, imm16);
625}
626
627void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
628 CHECK(IsR6());
629 EmitI(0x3E, static_cast<Register>(0), rt, imm16);
630}
631
632void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
633 CHECK(IsR6());
634 CHECK_NE(rs, ZERO);
635 CHECK_NE(rt, ZERO);
636 CHECK_NE(rs, rt);
637 EmitI(0x17, rs, rt, imm16);
638}
639
640void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
641 CHECK(IsR6());
642 CHECK_NE(rt, ZERO);
643 EmitI(0x17, rt, rt, imm16);
644}
645
646void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
647 CHECK(IsR6());
648 CHECK_NE(rt, ZERO);
649 EmitI(0x17, static_cast<Register>(0), rt, imm16);
650}
651
652void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
653 CHECK(IsR6());
654 CHECK_NE(rs, ZERO);
655 CHECK_NE(rt, ZERO);
656 CHECK_NE(rs, rt);
657 EmitI(0x16, rs, rt, imm16);
658}
659
660void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
661 CHECK(IsR6());
662 CHECK_NE(rt, ZERO);
663 EmitI(0x16, rt, rt, imm16);
664}
665
666void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
667 CHECK(IsR6());
668 CHECK_NE(rt, ZERO);
669 EmitI(0x16, static_cast<Register>(0), rt, imm16);
670}
671
672void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
673 CHECK(IsR6());
674 CHECK_NE(rs, ZERO);
675 CHECK_NE(rt, ZERO);
676 CHECK_NE(rs, rt);
677 EmitI(0x7, rs, rt, imm16);
678}
679
680void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
681 CHECK(IsR6());
682 CHECK_NE(rs, ZERO);
683 CHECK_NE(rt, ZERO);
684 CHECK_NE(rs, rt);
685 EmitI(0x6, rs, rt, imm16);
686}
687
688void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
689 CHECK(IsR6());
690 CHECK_NE(rs, ZERO);
691 CHECK_NE(rt, ZERO);
692 CHECK_NE(rs, rt);
693 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
694}
695
696void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
697 CHECK(IsR6());
698 CHECK_NE(rs, ZERO);
699 CHECK_NE(rt, ZERO);
700 CHECK_NE(rs, rt);
701 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
702}
703
704void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
705 CHECK(IsR6());
706 CHECK_NE(rs, ZERO);
707 EmitI21(0x36, rs, imm21);
708}
709
710void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
711 CHECK(IsR6());
712 CHECK_NE(rs, ZERO);
713 EmitI21(0x3E, rs, imm21);
714}
715
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800716void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
717 CHECK(IsR6());
718 EmitFI(0x11, 0x9, ft, imm16);
719}
720
721void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
722 CHECK(IsR6());
723 EmitFI(0x11, 0xD, ft, imm16);
724}
725
726void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200727 switch (cond) {
728 case kCondLTZ:
729 CHECK_EQ(rt, ZERO);
730 Bltz(rs, imm16);
731 break;
732 case kCondGEZ:
733 CHECK_EQ(rt, ZERO);
734 Bgez(rs, imm16);
735 break;
736 case kCondLEZ:
737 CHECK_EQ(rt, ZERO);
738 Blez(rs, imm16);
739 break;
740 case kCondGTZ:
741 CHECK_EQ(rt, ZERO);
742 Bgtz(rs, imm16);
743 break;
744 case kCondEQ:
745 Beq(rs, rt, imm16);
746 break;
747 case kCondNE:
748 Bne(rs, rt, imm16);
749 break;
750 case kCondEQZ:
751 CHECK_EQ(rt, ZERO);
752 Beqz(rs, imm16);
753 break;
754 case kCondNEZ:
755 CHECK_EQ(rt, ZERO);
756 Bnez(rs, imm16);
757 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800758 case kCondF:
759 CHECK_EQ(rt, ZERO);
760 Bc1f(static_cast<int>(rs), imm16);
761 break;
762 case kCondT:
763 CHECK_EQ(rt, ZERO);
764 Bc1t(static_cast<int>(rs), imm16);
765 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200766 case kCondLT:
767 case kCondGE:
768 case kCondLE:
769 case kCondGT:
770 case kCondLTU:
771 case kCondGEU:
772 case kUncond:
773 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
774 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
775 LOG(FATAL) << "Unexpected branch condition " << cond;
776 UNREACHABLE();
777 }
778}
779
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800780void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200781 switch (cond) {
782 case kCondLT:
783 Bltc(rs, rt, imm16_21);
784 break;
785 case kCondGE:
786 Bgec(rs, rt, imm16_21);
787 break;
788 case kCondLE:
789 Bgec(rt, rs, imm16_21);
790 break;
791 case kCondGT:
792 Bltc(rt, rs, imm16_21);
793 break;
794 case kCondLTZ:
795 CHECK_EQ(rt, ZERO);
796 Bltzc(rs, imm16_21);
797 break;
798 case kCondGEZ:
799 CHECK_EQ(rt, ZERO);
800 Bgezc(rs, imm16_21);
801 break;
802 case kCondLEZ:
803 CHECK_EQ(rt, ZERO);
804 Blezc(rs, imm16_21);
805 break;
806 case kCondGTZ:
807 CHECK_EQ(rt, ZERO);
808 Bgtzc(rs, imm16_21);
809 break;
810 case kCondEQ:
811 Beqc(rs, rt, imm16_21);
812 break;
813 case kCondNE:
814 Bnec(rs, rt, imm16_21);
815 break;
816 case kCondEQZ:
817 CHECK_EQ(rt, ZERO);
818 Beqzc(rs, imm16_21);
819 break;
820 case kCondNEZ:
821 CHECK_EQ(rt, ZERO);
822 Bnezc(rs, imm16_21);
823 break;
824 case kCondLTU:
825 Bltuc(rs, rt, imm16_21);
826 break;
827 case kCondGEU:
828 Bgeuc(rs, rt, imm16_21);
829 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800830 case kCondF:
831 CHECK_EQ(rt, ZERO);
832 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
833 break;
834 case kCondT:
835 CHECK_EQ(rt, ZERO);
836 Bc1nez(static_cast<FRegister>(rs), imm16_21);
837 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200838 case kUncond:
839 LOG(FATAL) << "Unexpected branch condition " << cond;
840 UNREACHABLE();
841 }
jeffhao7fbee072012-08-24 17:56:54 -0700842}
843
844void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
845 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
846}
847
848void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
849 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
850}
851
852void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
853 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
854}
855
856void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
857 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
858}
859
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200860void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
861 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700862}
863
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200864void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
865 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
jeffhao7fbee072012-08-24 17:56:54 -0700866}
867
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200868void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
869 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
jeffhao7fbee072012-08-24 17:56:54 -0700870}
871
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200872void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
873 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
jeffhao7fbee072012-08-24 17:56:54 -0700874}
875
Chris Larsenb74353a2015-11-20 09:07:09 -0800876void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
877 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4);
878}
879
880void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
881 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4);
882}
883
884void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
885 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5);
886}
887
888void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
889 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5);
890}
891
jeffhao7fbee072012-08-24 17:56:54 -0700892void MipsAssembler::MovS(FRegister fd, FRegister fs) {
893 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
894}
895
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200896void MipsAssembler::MovD(FRegister fd, FRegister fs) {
897 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
898}
899
900void MipsAssembler::NegS(FRegister fd, FRegister fs) {
901 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
902}
903
904void MipsAssembler::NegD(FRegister fd, FRegister fs) {
905 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
906}
907
Chris Larsenb74353a2015-11-20 09:07:09 -0800908void MipsAssembler::CunS(FRegister fs, FRegister ft) {
909 CunS(0, fs, ft);
910}
911
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800912void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
913 CHECK(!IsR6());
914 CHECK(IsUint<3>(cc)) << cc;
915 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
916}
917
Chris Larsenb74353a2015-11-20 09:07:09 -0800918void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
919 CeqS(0, fs, ft);
920}
921
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800922void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
923 CHECK(!IsR6());
924 CHECK(IsUint<3>(cc)) << cc;
925 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
926}
927
Chris Larsenb74353a2015-11-20 09:07:09 -0800928void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
929 CueqS(0, fs, ft);
930}
931
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800932void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
933 CHECK(!IsR6());
934 CHECK(IsUint<3>(cc)) << cc;
935 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
936}
937
Chris Larsenb74353a2015-11-20 09:07:09 -0800938void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
939 ColtS(0, fs, ft);
940}
941
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800942void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
943 CHECK(!IsR6());
944 CHECK(IsUint<3>(cc)) << cc;
945 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
946}
947
Chris Larsenb74353a2015-11-20 09:07:09 -0800948void MipsAssembler::CultS(FRegister fs, FRegister ft) {
949 CultS(0, fs, ft);
950}
951
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800952void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
953 CHECK(!IsR6());
954 CHECK(IsUint<3>(cc)) << cc;
955 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
956}
957
Chris Larsenb74353a2015-11-20 09:07:09 -0800958void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
959 ColeS(0, fs, ft);
960}
961
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800962void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
963 CHECK(!IsR6());
964 CHECK(IsUint<3>(cc)) << cc;
965 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
966}
967
Chris Larsenb74353a2015-11-20 09:07:09 -0800968void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
969 CuleS(0, fs, ft);
970}
971
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800972void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
973 CHECK(!IsR6());
974 CHECK(IsUint<3>(cc)) << cc;
975 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
976}
977
Chris Larsenb74353a2015-11-20 09:07:09 -0800978void MipsAssembler::CunD(FRegister fs, FRegister ft) {
979 CunD(0, fs, ft);
980}
981
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800982void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
983 CHECK(!IsR6());
984 CHECK(IsUint<3>(cc)) << cc;
985 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
986}
987
Chris Larsenb74353a2015-11-20 09:07:09 -0800988void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
989 CeqD(0, fs, ft);
990}
991
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800992void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
993 CHECK(!IsR6());
994 CHECK(IsUint<3>(cc)) << cc;
995 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
996}
997
Chris Larsenb74353a2015-11-20 09:07:09 -0800998void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
999 CueqD(0, fs, ft);
1000}
1001
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001002void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1003 CHECK(!IsR6());
1004 CHECK(IsUint<3>(cc)) << cc;
1005 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
1006}
1007
Chris Larsenb74353a2015-11-20 09:07:09 -08001008void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1009 ColtD(0, fs, ft);
1010}
1011
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001012void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1013 CHECK(!IsR6());
1014 CHECK(IsUint<3>(cc)) << cc;
1015 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
1016}
1017
Chris Larsenb74353a2015-11-20 09:07:09 -08001018void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1019 CultD(0, fs, ft);
1020}
1021
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001022void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1023 CHECK(!IsR6());
1024 CHECK(IsUint<3>(cc)) << cc;
1025 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
1026}
1027
Chris Larsenb74353a2015-11-20 09:07:09 -08001028void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1029 ColeD(0, fs, ft);
1030}
1031
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001032void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1033 CHECK(!IsR6());
1034 CHECK(IsUint<3>(cc)) << cc;
1035 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
1036}
1037
Chris Larsenb74353a2015-11-20 09:07:09 -08001038void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1039 CuleD(0, fs, ft);
1040}
1041
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001042void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1043 CHECK(!IsR6());
1044 CHECK(IsUint<3>(cc)) << cc;
1045 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
1046}
1047
1048void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1049 CHECK(IsR6());
1050 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1051}
1052
1053void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1054 CHECK(IsR6());
1055 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1056}
1057
1058void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1059 CHECK(IsR6());
1060 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1061}
1062
1063void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1064 CHECK(IsR6());
1065 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1066}
1067
1068void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1069 CHECK(IsR6());
1070 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1071}
1072
1073void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1074 CHECK(IsR6());
1075 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1076}
1077
1078void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1079 CHECK(IsR6());
1080 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1081}
1082
1083void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1084 CHECK(IsR6());
1085 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1086}
1087
1088void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1089 CHECK(IsR6());
1090 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1091}
1092
1093void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1094 CHECK(IsR6());
1095 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1096}
1097
1098void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1099 CHECK(IsR6());
1100 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1101}
1102
1103void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1104 CHECK(IsR6());
1105 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1106}
1107
1108void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1109 CHECK(IsR6());
1110 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1111}
1112
1113void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1114 CHECK(IsR6());
1115 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1116}
1117
1118void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1119 CHECK(IsR6());
1120 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1121}
1122
1123void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1124 CHECK(IsR6());
1125 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1126}
1127
1128void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1129 CHECK(IsR6());
1130 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1131}
1132
1133void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1134 CHECK(IsR6());
1135 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1136}
1137
1138void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1139 CHECK(IsR6());
1140 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1141}
1142
1143void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1144 CHECK(IsR6());
1145 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1146}
1147
1148void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1149 CHECK(!IsR6());
1150 CHECK(IsUint<3>(cc)) << cc;
1151 EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01);
1152}
1153
1154void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1155 CHECK(!IsR6());
1156 CHECK(IsUint<3>(cc)) << cc;
1157 EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01);
1158}
1159
Chris Larsenb74353a2015-11-20 09:07:09 -08001160void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1161 CHECK(!IsR6());
1162 CHECK(IsUint<3>(cc)) << cc;
1163 EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1164}
1165
1166void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1167 CHECK(!IsR6());
1168 CHECK(IsUint<3>(cc)) << cc;
1169 EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11);
1170}
1171
1172void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1173 CHECK(!IsR6());
1174 CHECK(IsUint<3>(cc)) << cc;
1175 EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1176}
1177
1178void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1179 CHECK(!IsR6());
1180 CHECK(IsUint<3>(cc)) << cc;
1181 EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11);
1182}
1183
1184void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1185 CHECK(IsR6());
1186 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
1187}
1188
1189void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1190 CHECK(IsR6());
1191 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1192}
1193
1194void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1195 CHECK(IsR6());
1196 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b);
1197}
1198
1199void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1200 CHECK(IsR6());
1201 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b);
1202}
1203
1204void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1205 CHECK(IsR6());
1206 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1207}
1208
1209void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1210 CHECK(IsR6());
1211 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1212}
1213
1214void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1215 CHECK(IsR6());
1216 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1217}
1218
1219void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1220 CHECK(IsR6());
1221 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1222}
1223
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001224void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1225 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1226}
1227
1228void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1229 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1230}
1231
1232void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1233 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1234}
1235
1236void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1237 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1238}
1239
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001240void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1241 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1242}
1243
1244void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1245 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1246}
1247
1248void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1249 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1250}
1251
1252void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1253 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
jeffhao7fbee072012-08-24 17:56:54 -07001254}
1255
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001256void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1257 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1258}
1259
1260void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1261 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1262}
1263
Chris Larsenb74353a2015-11-20 09:07:09 -08001264void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1265 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf);
1266}
1267
1268void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1269 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf);
1270}
1271
jeffhao7fbee072012-08-24 17:56:54 -07001272void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001273 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001274}
1275
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001276void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1277 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1278}
1279
1280void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1281 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1282}
1283
1284void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1285 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001286}
1287
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001288void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1289 if (Is32BitFPU()) {
1290 CHECK_EQ(fs % 2, 0) << fs;
1291 Mfc1(rt, static_cast<FRegister>(fs + 1));
1292 } else {
1293 Mfhc1(rt, fs);
1294 }
1295}
1296
1297void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1298 if (Is32BitFPU()) {
1299 CHECK_EQ(fs % 2, 0) << fs;
1300 Mtc1(rt, static_cast<FRegister>(fs + 1));
1301 } else {
1302 Mthc1(rt, fs);
1303 }
1304}
1305
jeffhao7fbee072012-08-24 17:56:54 -07001306void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001307 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001308}
1309
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001310void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1311 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001312}
1313
1314void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001315 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001316}
1317
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001318void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1319 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001320}
1321
1322void MipsAssembler::Break() {
1323 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1324 static_cast<Register>(0), 0, 0xD);
1325}
1326
jeffhao07030602012-09-26 14:33:14 -07001327void MipsAssembler::Nop() {
1328 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1329}
1330
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001331void MipsAssembler::Move(Register rd, Register rs) {
1332 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001333}
1334
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001335void MipsAssembler::Clear(Register rd) {
1336 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001337}
1338
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001339void MipsAssembler::Not(Register rd, Register rs) {
1340 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001341}
1342
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001343void MipsAssembler::Push(Register rs) {
1344 IncreaseFrameSize(kMipsWordSize);
1345 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001346}
1347
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001348void MipsAssembler::Pop(Register rd) {
1349 Lw(rd, SP, 0);
1350 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001351}
1352
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001353void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1354 Lw(rd, SP, 0);
1355 Jr(rt);
1356 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001357}
1358
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001359void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1360 if (IsUint<16>(value)) {
1361 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1362 Ori(rd, ZERO, value);
1363 } else if (IsInt<16>(value)) {
1364 // Use ADD with (signed) immediate to encode 16b signed int.
1365 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07001366 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001367 Lui(rd, High16Bits(value));
1368 if (value & 0xFFFF)
1369 Ori(rd, rd, Low16Bits(value));
1370 }
1371}
1372
1373void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001374 uint32_t low = Low32Bits(value);
1375 uint32_t high = High32Bits(value);
1376 LoadConst32(reg_lo, low);
1377 if (high != low) {
1378 LoadConst32(reg_hi, high);
1379 } else {
1380 Move(reg_hi, reg_lo);
1381 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001382}
1383
1384void MipsAssembler::StoreConst32ToOffset(int32_t value,
1385 Register base,
1386 int32_t offset,
1387 Register temp) {
1388 if (!IsInt<16>(offset)) {
1389 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1390 LoadConst32(AT, offset);
1391 Addu(AT, AT, base);
1392 base = AT;
1393 offset = 0;
1394 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001395 if (value == 0) {
1396 temp = ZERO;
1397 } else {
1398 LoadConst32(temp, value);
1399 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001400 Sw(temp, base, offset);
1401}
1402
1403void MipsAssembler::StoreConst64ToOffset(int64_t value,
1404 Register base,
1405 int32_t offset,
1406 Register temp) {
1407 // IsInt<16> must be passed a signed value.
1408 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
1409 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1410 LoadConst32(AT, offset);
1411 Addu(AT, AT, base);
1412 base = AT;
1413 offset = 0;
1414 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001415 uint32_t low = Low32Bits(value);
1416 uint32_t high = High32Bits(value);
1417 if (low == 0) {
1418 Sw(ZERO, base, offset);
1419 } else {
1420 LoadConst32(temp, low);
1421 Sw(temp, base, offset);
1422 }
1423 if (high == 0) {
1424 Sw(ZERO, base, offset + kMipsWordSize);
1425 } else {
1426 if (high != low) {
1427 LoadConst32(temp, high);
1428 }
1429 Sw(temp, base, offset + kMipsWordSize);
1430 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001431}
1432
1433void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001434 if (value == 0) {
1435 temp = ZERO;
1436 } else {
1437 LoadConst32(temp, value);
1438 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001439 Mtc1(temp, r);
1440}
1441
1442void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001443 uint32_t low = Low32Bits(value);
1444 uint32_t high = High32Bits(value);
1445 if (low == 0) {
1446 Mtc1(ZERO, rd);
1447 } else {
1448 LoadConst32(temp, low);
1449 Mtc1(temp, rd);
1450 }
1451 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001452 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001453 } else {
1454 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001455 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001456 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001457}
1458
1459void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1460 if (IsInt<16>(value)) {
1461 Addiu(rt, rs, value);
1462 } else {
1463 LoadConst32(temp, value);
1464 Addu(rt, rs, temp);
1465 }
1466}
1467
1468void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1469 MipsAssembler::Branch::Type short_type,
1470 MipsAssembler::Branch::Type long_type) {
1471 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1472}
1473
1474void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
1475 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1476 if (is_r6) {
1477 // R6
1478 if (is_call) {
1479 InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1480 } else if (condition_ == kUncond) {
1481 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1482 } else {
1483 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1484 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1485 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1486 } else {
1487 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1488 }
1489 }
1490 } else {
1491 // R2
1492 if (is_call) {
1493 InitShortOrLong(offset_size, kCall, kLongCall);
1494 } else if (condition_ == kUncond) {
1495 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1496 } else {
1497 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1498 }
1499 }
1500 old_type_ = type_;
1501}
1502
1503bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1504 switch (condition) {
1505 case kCondLT:
1506 case kCondGT:
1507 case kCondNE:
1508 case kCondLTU:
1509 return lhs == rhs;
1510 default:
1511 return false;
1512 }
1513}
1514
1515bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1516 switch (condition) {
1517 case kUncond:
1518 return true;
1519 case kCondGE:
1520 case kCondLE:
1521 case kCondEQ:
1522 case kCondGEU:
1523 return lhs == rhs;
1524 default:
1525 return false;
1526 }
1527}
1528
1529MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
1530 : old_location_(location),
1531 location_(location),
1532 target_(target),
1533 lhs_reg_(0),
1534 rhs_reg_(0),
1535 condition_(kUncond) {
1536 InitializeType(false, is_r6);
1537}
1538
1539MipsAssembler::Branch::Branch(bool is_r6,
1540 uint32_t location,
1541 uint32_t target,
1542 MipsAssembler::BranchCondition condition,
1543 Register lhs_reg,
1544 Register rhs_reg)
1545 : old_location_(location),
1546 location_(location),
1547 target_(target),
1548 lhs_reg_(lhs_reg),
1549 rhs_reg_(rhs_reg),
1550 condition_(condition) {
1551 CHECK_NE(condition, kUncond);
1552 switch (condition) {
1553 case kCondLT:
1554 case kCondGE:
1555 case kCondLE:
1556 case kCondGT:
1557 case kCondLTU:
1558 case kCondGEU:
1559 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1560 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1561 // We leave this up to the caller.
1562 CHECK(is_r6);
1563 FALLTHROUGH_INTENDED;
1564 case kCondEQ:
1565 case kCondNE:
1566 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1567 // To compare with 0, use dedicated kCond*Z conditions.
1568 CHECK_NE(lhs_reg, ZERO);
1569 CHECK_NE(rhs_reg, ZERO);
1570 break;
1571 case kCondLTZ:
1572 case kCondGEZ:
1573 case kCondLEZ:
1574 case kCondGTZ:
1575 case kCondEQZ:
1576 case kCondNEZ:
1577 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1578 CHECK_NE(lhs_reg, ZERO);
1579 CHECK_EQ(rhs_reg, ZERO);
1580 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001581 case kCondF:
1582 case kCondT:
1583 CHECK_EQ(rhs_reg, ZERO);
1584 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001585 case kUncond:
1586 UNREACHABLE();
1587 }
1588 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1589 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1590 // Branch condition is always true, make the branch unconditional.
1591 condition_ = kUncond;
1592 }
1593 InitializeType(false, is_r6);
1594}
1595
1596MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
1597 : old_location_(location),
1598 location_(location),
1599 target_(target),
1600 lhs_reg_(indirect_reg),
1601 rhs_reg_(0),
1602 condition_(kUncond) {
1603 CHECK_NE(indirect_reg, ZERO);
1604 CHECK_NE(indirect_reg, AT);
1605 InitializeType(true, is_r6);
1606}
1607
1608MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1609 MipsAssembler::BranchCondition cond) {
1610 switch (cond) {
1611 case kCondLT:
1612 return kCondGE;
1613 case kCondGE:
1614 return kCondLT;
1615 case kCondLE:
1616 return kCondGT;
1617 case kCondGT:
1618 return kCondLE;
1619 case kCondLTZ:
1620 return kCondGEZ;
1621 case kCondGEZ:
1622 return kCondLTZ;
1623 case kCondLEZ:
1624 return kCondGTZ;
1625 case kCondGTZ:
1626 return kCondLEZ;
1627 case kCondEQ:
1628 return kCondNE;
1629 case kCondNE:
1630 return kCondEQ;
1631 case kCondEQZ:
1632 return kCondNEZ;
1633 case kCondNEZ:
1634 return kCondEQZ;
1635 case kCondLTU:
1636 return kCondGEU;
1637 case kCondGEU:
1638 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001639 case kCondF:
1640 return kCondT;
1641 case kCondT:
1642 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001643 case kUncond:
1644 LOG(FATAL) << "Unexpected branch condition " << cond;
1645 }
1646 UNREACHABLE();
1647}
1648
1649MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1650 return type_;
1651}
1652
1653MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1654 return condition_;
1655}
1656
1657Register MipsAssembler::Branch::GetLeftRegister() const {
1658 return static_cast<Register>(lhs_reg_);
1659}
1660
1661Register MipsAssembler::Branch::GetRightRegister() const {
1662 return static_cast<Register>(rhs_reg_);
1663}
1664
1665uint32_t MipsAssembler::Branch::GetTarget() const {
1666 return target_;
1667}
1668
1669uint32_t MipsAssembler::Branch::GetLocation() const {
1670 return location_;
1671}
1672
1673uint32_t MipsAssembler::Branch::GetOldLocation() const {
1674 return old_location_;
1675}
1676
1677uint32_t MipsAssembler::Branch::GetLength() const {
1678 return branch_info_[type_].length;
1679}
1680
1681uint32_t MipsAssembler::Branch::GetOldLength() const {
1682 return branch_info_[old_type_].length;
1683}
1684
1685uint32_t MipsAssembler::Branch::GetSize() const {
1686 return GetLength() * sizeof(uint32_t);
1687}
1688
1689uint32_t MipsAssembler::Branch::GetOldSize() const {
1690 return GetOldLength() * sizeof(uint32_t);
1691}
1692
1693uint32_t MipsAssembler::Branch::GetEndLocation() const {
1694 return GetLocation() + GetSize();
1695}
1696
1697uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1698 return GetOldLocation() + GetOldSize();
1699}
1700
1701bool MipsAssembler::Branch::IsLong() const {
1702 switch (type_) {
1703 // R2 short branches.
1704 case kUncondBranch:
1705 case kCondBranch:
1706 case kCall:
1707 // R6 short branches.
1708 case kR6UncondBranch:
1709 case kR6CondBranch:
1710 case kR6Call:
1711 return false;
1712 // R2 long branches.
1713 case kLongUncondBranch:
1714 case kLongCondBranch:
1715 case kLongCall:
1716 // R6 long branches.
1717 case kR6LongUncondBranch:
1718 case kR6LongCondBranch:
1719 case kR6LongCall:
1720 return true;
1721 }
1722 UNREACHABLE();
1723}
1724
1725bool MipsAssembler::Branch::IsResolved() const {
1726 return target_ != kUnresolved;
1727}
1728
1729MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1730 OffsetBits offset_size =
1731 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1732 ? kOffset23
1733 : branch_info_[type_].offset_size;
1734 return offset_size;
1735}
1736
1737MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1738 uint32_t target) {
1739 // For unresolved targets assume the shortest encoding
1740 // (later it will be made longer if needed).
1741 if (target == kUnresolved)
1742 return kOffset16;
1743 int64_t distance = static_cast<int64_t>(target) - location;
1744 // To simplify calculations in composite branches consisting of multiple instructions
1745 // bump up the distance by a value larger than the max byte size of a composite branch.
1746 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1747 if (IsInt<kOffset16>(distance))
1748 return kOffset16;
1749 else if (IsInt<kOffset18>(distance))
1750 return kOffset18;
1751 else if (IsInt<kOffset21>(distance))
1752 return kOffset21;
1753 else if (IsInt<kOffset23>(distance))
1754 return kOffset23;
1755 else if (IsInt<kOffset28>(distance))
1756 return kOffset28;
1757 return kOffset32;
1758}
1759
1760void MipsAssembler::Branch::Resolve(uint32_t target) {
1761 target_ = target;
1762}
1763
1764void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1765 if (location_ > expand_location) {
1766 location_ += delta;
1767 }
1768 if (!IsResolved()) {
1769 return; // Don't know the target yet.
1770 }
1771 if (target_ > expand_location) {
1772 target_ += delta;
1773 }
1774}
1775
1776void MipsAssembler::Branch::PromoteToLong() {
1777 switch (type_) {
1778 // R2 short branches.
1779 case kUncondBranch:
1780 type_ = kLongUncondBranch;
1781 break;
1782 case kCondBranch:
1783 type_ = kLongCondBranch;
1784 break;
1785 case kCall:
1786 type_ = kLongCall;
1787 break;
1788 // R6 short branches.
1789 case kR6UncondBranch:
1790 type_ = kR6LongUncondBranch;
1791 break;
1792 case kR6CondBranch:
1793 type_ = kR6LongCondBranch;
1794 break;
1795 case kR6Call:
1796 type_ = kR6LongCall;
1797 break;
1798 default:
1799 // Note: 'type_' is already long.
1800 break;
1801 }
1802 CHECK(IsLong());
1803}
1804
1805uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1806 // If the branch is still unresolved or already long, nothing to do.
1807 if (IsLong() || !IsResolved()) {
1808 return 0;
1809 }
1810 // Promote the short branch to long if the offset size is too small
1811 // to hold the distance between location_ and target_.
1812 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1813 PromoteToLong();
1814 uint32_t old_size = GetOldSize();
1815 uint32_t new_size = GetSize();
1816 CHECK_GT(new_size, old_size);
1817 return new_size - old_size;
1818 }
1819 // The following logic is for debugging/testing purposes.
1820 // Promote some short branches to long when it's not really required.
1821 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1822 int64_t distance = static_cast<int64_t>(target_) - location_;
1823 distance = (distance >= 0) ? distance : -distance;
1824 if (distance >= max_short_distance) {
1825 PromoteToLong();
1826 uint32_t old_size = GetOldSize();
1827 uint32_t new_size = GetSize();
1828 CHECK_GT(new_size, old_size);
1829 return new_size - old_size;
1830 }
1831 }
1832 return 0;
1833}
1834
1835uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1836 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1837}
1838
1839uint32_t MipsAssembler::Branch::GetOffset() const {
1840 CHECK(IsResolved());
1841 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1842 // Calculate the byte distance between instructions and also account for
1843 // different PC-relative origins.
1844 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1845 // Prepare the offset for encoding into the instruction(s).
1846 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1847 return offset;
1848}
1849
1850MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1851 CHECK_LT(branch_id, branches_.size());
1852 return &branches_[branch_id];
1853}
1854
1855const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1856 CHECK_LT(branch_id, branches_.size());
1857 return &branches_[branch_id];
1858}
1859
1860void MipsAssembler::Bind(MipsLabel* label) {
1861 CHECK(!label->IsBound());
1862 uint32_t bound_pc = buffer_.Size();
1863
1864 // Walk the list of branches referring to and preceding this label.
1865 // Store the previously unknown target addresses in them.
1866 while (label->IsLinked()) {
1867 uint32_t branch_id = label->Position();
1868 Branch* branch = GetBranch(branch_id);
1869 branch->Resolve(bound_pc);
1870
1871 uint32_t branch_location = branch->GetLocation();
1872 // Extract the location of the previous branch in the list (walking the list backwards;
1873 // the previous branch ID was stored in the space reserved for this branch).
1874 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1875
1876 // On to the previous branch in the list...
1877 label->position_ = prev;
1878 }
1879
1880 // Now make the label object contain its own location (relative to the end of the preceding
1881 // branch, if any; it will be used by the branches referring to and following this label).
1882 label->prev_branch_id_plus_one_ = branches_.size();
1883 if (label->prev_branch_id_plus_one_) {
1884 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1885 const Branch* branch = GetBranch(branch_id);
1886 bound_pc -= branch->GetEndLocation();
1887 }
1888 label->BindTo(bound_pc);
1889}
1890
1891uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1892 CHECK(label->IsBound());
1893 uint32_t target = label->Position();
1894 if (label->prev_branch_id_plus_one_) {
1895 // Get label location based on the branch preceding it.
1896 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1897 const Branch* branch = GetBranch(branch_id);
1898 target += branch->GetEndLocation();
1899 }
1900 return target;
1901}
1902
1903uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1904 // We can reconstruct the adjustment by going through all the branches from the beginning
1905 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1906 // with increasing old_position, we can use the data from last AdjustedPosition() to
1907 // continue where we left off and the whole loop should be O(m+n) where m is the number
1908 // of positions to adjust and n is the number of branches.
1909 if (old_position < last_old_position_) {
1910 last_position_adjustment_ = 0;
1911 last_old_position_ = 0;
1912 last_branch_id_ = 0;
1913 }
1914 while (last_branch_id_ != branches_.size()) {
1915 const Branch* branch = GetBranch(last_branch_id_);
1916 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1917 break;
1918 }
1919 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1920 ++last_branch_id_;
1921 }
1922 last_old_position_ = old_position;
1923 return old_position + last_position_adjustment_;
1924}
1925
1926void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1927 uint32_t length = branches_.back().GetLength();
1928 if (!label->IsBound()) {
1929 // Branch forward (to a following label), distance is unknown.
1930 // The first branch forward will contain 0, serving as the terminator of
1931 // the list of forward-reaching branches.
1932 Emit(label->position_);
1933 length--;
1934 // Now make the label object point to this branch
1935 // (this forms a linked list of branches preceding this label).
1936 uint32_t branch_id = branches_.size() - 1;
1937 label->LinkTo(branch_id);
1938 }
1939 // Reserve space for the branch.
1940 while (length--) {
1941 Nop();
1942 }
1943}
1944
1945void MipsAssembler::Buncond(MipsLabel* label) {
1946 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1947 branches_.emplace_back(IsR6(), buffer_.Size(), target);
1948 FinalizeLabeledBranch(label);
1949}
1950
1951void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1952 // If lhs = rhs, this can be a NOP.
1953 if (Branch::IsNop(condition, lhs, rhs)) {
1954 return;
1955 }
1956 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1957 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1958 FinalizeLabeledBranch(label);
1959}
1960
1961void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1962 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1963 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1964 FinalizeLabeledBranch(label);
1965}
1966
1967void MipsAssembler::PromoteBranches() {
1968 // Promote short branches to long as necessary.
1969 bool changed;
1970 do {
1971 changed = false;
1972 for (auto& branch : branches_) {
1973 CHECK(branch.IsResolved());
1974 uint32_t delta = branch.PromoteIfNeeded();
1975 // If this branch has been promoted and needs to expand in size,
1976 // relocate all branches by the expansion size.
1977 if (delta) {
1978 changed = true;
1979 uint32_t expand_location = branch.GetLocation();
1980 for (auto& branch2 : branches_) {
1981 branch2.Relocate(expand_location, delta);
1982 }
1983 }
1984 }
1985 } while (changed);
1986
1987 // Account for branch expansion by resizing the code buffer
1988 // and moving the code in it to its final location.
1989 size_t branch_count = branches_.size();
1990 if (branch_count > 0) {
1991 // Resize.
1992 Branch& last_branch = branches_[branch_count - 1];
1993 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1994 uint32_t old_size = buffer_.Size();
1995 buffer_.Resize(old_size + size_delta);
1996 // Move the code residing between branch placeholders.
1997 uint32_t end = old_size;
1998 for (size_t i = branch_count; i > 0; ) {
1999 Branch& branch = branches_[--i];
2000 uint32_t size = end - branch.GetOldEndLocation();
2001 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
2002 end = branch.GetOldLocation();
2003 }
2004 }
2005}
2006
2007// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2008const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
2009 // R2 short branches.
2010 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
2011 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
2012 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall
2013 // R2 long branches.
2014 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
2015 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
2016 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
2017 // R6 short branches.
2018 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
2019 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
2020 // Exception: kOffset23 for beqzc/bnezc.
2021 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call
2022 // R6 long branches.
2023 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
2024 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
2025 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
2026};
2027
2028// Note: make sure branch_info_[] and mitBranch() are kept synchronized.
2029void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
2030 CHECK_EQ(overwriting_, true);
2031 overwrite_location_ = branch->GetLocation();
2032 uint32_t offset = branch->GetOffset();
2033 BranchCondition condition = branch->GetCondition();
2034 Register lhs = branch->GetLeftRegister();
2035 Register rhs = branch->GetRightRegister();
2036 switch (branch->GetType()) {
2037 // R2 short branches.
2038 case Branch::kUncondBranch:
2039 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2040 B(offset);
2041 Nop(); // TODO: improve by filling the delay slot.
2042 break;
2043 case Branch::kCondBranch:
2044 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002045 EmitBcondR2(condition, lhs, rhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002046 Nop(); // TODO: improve by filling the delay slot.
2047 break;
2048 case Branch::kCall:
2049 Nal();
2050 Nop(); // TODO: is this NOP really needed here?
2051 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2052 Addiu(lhs, RA, offset);
2053 Jalr(lhs);
2054 Nop();
2055 break;
2056
2057 // R2 long branches.
2058 case Branch::kLongUncondBranch:
2059 // To get the value of the PC register we need to use the NAL instruction.
2060 // NAL clobbers the RA register. However, RA must be preserved if the
2061 // method is compiled without the entry/exit sequences that would take care
2062 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
2063 // So, we need to preserve RA in some temporary storage ourselves. The AT
2064 // register can't be used for this because we need it to load a constant
2065 // which will be added to the value that NAL stores in RA. And we can't
2066 // use T9 for this in the context of the JNI compiler, which uses it
2067 // as a scratch register (see InterproceduralScratchRegister()).
2068 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
2069 // we'd also need to use the ROTR instruction, which requires no less than
2070 // MIPSR2.
2071 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
2072 // (LO or HI) or even a floating-point register, but that doesn't seem
2073 // like a nice solution. We may want this to work on both R6 and pre-R6.
2074 // For now simply use the stack for RA. This should be OK since for the
2075 // vast majority of code a short PC-relative branch is sufficient.
2076 // TODO: can this be improved?
2077 Push(RA);
2078 Nal();
2079 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2080 Lui(AT, High16Bits(offset));
2081 Ori(AT, AT, Low16Bits(offset));
2082 Addu(AT, AT, RA);
2083 Lw(RA, SP, 0);
2084 Jr(AT);
2085 DecreaseFrameSize(kMipsWordSize);
2086 break;
2087 case Branch::kLongCondBranch:
2088 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
2089 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
2090 // number of instructions skipped:
2091 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002092 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002093 Push(RA);
2094 Nal();
2095 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2096 Lui(AT, High16Bits(offset));
2097 Ori(AT, AT, Low16Bits(offset));
2098 Addu(AT, AT, RA);
2099 Lw(RA, SP, 0);
2100 Jr(AT);
2101 DecreaseFrameSize(kMipsWordSize);
2102 break;
2103 case Branch::kLongCall:
2104 Nal();
2105 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2106 Lui(AT, High16Bits(offset));
2107 Ori(AT, AT, Low16Bits(offset));
2108 Addu(lhs, AT, RA);
2109 Jalr(lhs);
2110 Nop();
2111 break;
2112
2113 // R6 short branches.
2114 case Branch::kR6UncondBranch:
2115 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2116 Bc(offset);
2117 break;
2118 case Branch::kR6CondBranch:
2119 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002120 EmitBcondR6(condition, lhs, rhs, offset);
2121 Nop(); // TODO: improve by filling the forbidden/delay slot.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002122 break;
2123 case Branch::kR6Call:
2124 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2125 Addiupc(lhs, offset);
2126 Jialc(lhs, 0);
2127 break;
2128
2129 // R6 long branches.
2130 case Branch::kR6LongUncondBranch:
2131 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2132 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2133 Auipc(AT, High16Bits(offset));
2134 Jic(AT, Low16Bits(offset));
2135 break;
2136 case Branch::kR6LongCondBranch:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002137 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002138 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2139 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2140 Auipc(AT, High16Bits(offset));
2141 Jic(AT, Low16Bits(offset));
2142 break;
2143 case Branch::kR6LongCall:
2144 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
2145 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2146 Auipc(lhs, High16Bits(offset));
2147 Addiu(lhs, lhs, Low16Bits(offset));
2148 Jialc(lhs, 0);
2149 break;
2150 }
2151 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2152 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
2153}
2154
2155void MipsAssembler::B(MipsLabel* label) {
2156 Buncond(label);
2157}
2158
2159void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
2160 Call(label, indirect_reg);
2161}
2162
2163void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
2164 Bcond(label, kCondEQ, rs, rt);
2165}
2166
2167void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
2168 Bcond(label, kCondNE, rs, rt);
2169}
2170
2171void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
2172 Bcond(label, kCondEQZ, rt);
2173}
2174
2175void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2176 Bcond(label, kCondNEZ, rt);
2177}
2178
2179void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2180 Bcond(label, kCondLTZ, rt);
2181}
2182
2183void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2184 Bcond(label, kCondGEZ, rt);
2185}
2186
2187void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2188 Bcond(label, kCondLEZ, rt);
2189}
2190
2191void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2192 Bcond(label, kCondGTZ, rt);
2193}
2194
2195void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
2196 if (IsR6()) {
2197 Bcond(label, kCondLT, rs, rt);
2198 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
2199 // Synthesize the instruction (not available on R2).
2200 Slt(AT, rs, rt);
2201 Bnez(AT, label);
2202 }
2203}
2204
2205void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
2206 if (IsR6()) {
2207 Bcond(label, kCondGE, rs, rt);
2208 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
2209 B(label);
2210 } else {
2211 // Synthesize the instruction (not available on R2).
2212 Slt(AT, rs, rt);
2213 Beqz(AT, label);
2214 }
2215}
2216
2217void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
2218 if (IsR6()) {
2219 Bcond(label, kCondLTU, rs, rt);
2220 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
2221 // Synthesize the instruction (not available on R2).
2222 Sltu(AT, rs, rt);
2223 Bnez(AT, label);
2224 }
2225}
2226
2227void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
2228 if (IsR6()) {
2229 Bcond(label, kCondGEU, rs, rt);
2230 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
2231 B(label);
2232 } else {
2233 // Synthesize the instruction (not available on R2).
2234 Sltu(AT, rs, rt);
2235 Beqz(AT, label);
jeffhao7fbee072012-08-24 17:56:54 -07002236 }
2237}
2238
Chris Larsenb74353a2015-11-20 09:07:09 -08002239void MipsAssembler::Bc1f(MipsLabel* label) {
2240 Bc1f(0, label);
2241}
2242
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002243void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2244 CHECK(IsUint<3>(cc)) << cc;
2245 Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2246}
2247
Chris Larsenb74353a2015-11-20 09:07:09 -08002248void MipsAssembler::Bc1t(MipsLabel* label) {
2249 Bc1t(0, label);
2250}
2251
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002252void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2253 CHECK(IsUint<3>(cc)) << cc;
2254 Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2255}
2256
2257void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2258 Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2259}
2260
2261void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2262 Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2263}
2264
jeffhao7fbee072012-08-24 17:56:54 -07002265void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
2266 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002267 // IsInt<16> must be passed a signed value.
2268 if (!IsInt<16>(offset) ||
2269 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2270 LoadConst32(AT, offset);
2271 Addu(AT, AT, base);
2272 base = AT;
2273 offset = 0;
2274 }
2275
jeffhao7fbee072012-08-24 17:56:54 -07002276 switch (type) {
2277 case kLoadSignedByte:
2278 Lb(reg, base, offset);
2279 break;
2280 case kLoadUnsignedByte:
2281 Lbu(reg, base, offset);
2282 break;
2283 case kLoadSignedHalfword:
2284 Lh(reg, base, offset);
2285 break;
2286 case kLoadUnsignedHalfword:
2287 Lhu(reg, base, offset);
2288 break;
2289 case kLoadWord:
2290 Lw(reg, base, offset);
2291 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002292 case kLoadDoubleword:
2293 if (reg == base) {
2294 // This will clobber the base when loading the lower register. Since we have to load the
2295 // higher register as well, this will fail. Solution: reverse the order.
2296 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2297 Lw(reg, base, offset);
2298 } else {
2299 Lw(reg, base, offset);
2300 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2301 }
jeffhao7fbee072012-08-24 17:56:54 -07002302 break;
2303 default:
2304 LOG(FATAL) << "UNREACHABLE";
2305 }
2306}
2307
2308void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002309 if (!IsInt<16>(offset)) {
2310 LoadConst32(AT, offset);
2311 Addu(AT, AT, base);
2312 base = AT;
2313 offset = 0;
2314 }
2315
jeffhao7fbee072012-08-24 17:56:54 -07002316 Lwc1(reg, base, offset);
2317}
2318
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002319void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
2320 // IsInt<16> must be passed a signed value.
2321 if (!IsInt<16>(offset) ||
2322 (!IsAligned<kMipsDoublewordSize>(offset) &&
2323 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2324 LoadConst32(AT, offset);
2325 Addu(AT, AT, base);
2326 base = AT;
2327 offset = 0;
2328 }
2329
2330 if (offset & 0x7) {
2331 if (Is32BitFPU()) {
2332 Lwc1(reg, base, offset);
2333 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2334 } else {
2335 // 64-bit FPU.
2336 Lwc1(reg, base, offset);
2337 Lw(T8, base, offset + kMipsWordSize);
2338 Mthc1(T8, reg);
2339 }
2340 } else {
2341 Ldc1(reg, base, offset);
2342 }
2343}
2344
2345void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
2346 size_t size) {
2347 MipsManagedRegister dst = m_dst.AsMips();
2348 if (dst.IsNoRegister()) {
2349 CHECK_EQ(0u, size) << dst;
2350 } else if (dst.IsCoreRegister()) {
2351 CHECK_EQ(kMipsWordSize, size) << dst;
2352 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
2353 } else if (dst.IsRegisterPair()) {
2354 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2355 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
2356 } else if (dst.IsFRegister()) {
2357 if (size == kMipsWordSize) {
2358 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
2359 } else {
2360 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2361 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
2362 }
2363 }
jeffhao7fbee072012-08-24 17:56:54 -07002364}
2365
2366void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
2367 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002368 // IsInt<16> must be passed a signed value.
2369 if (!IsInt<16>(offset) ||
2370 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2371 LoadConst32(AT, offset);
2372 Addu(AT, AT, base);
2373 base = AT;
2374 offset = 0;
2375 }
2376
jeffhao7fbee072012-08-24 17:56:54 -07002377 switch (type) {
2378 case kStoreByte:
2379 Sb(reg, base, offset);
2380 break;
2381 case kStoreHalfword:
2382 Sh(reg, base, offset);
2383 break;
2384 case kStoreWord:
2385 Sw(reg, base, offset);
2386 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002387 case kStoreDoubleword:
2388 CHECK_NE(reg, base);
2389 CHECK_NE(static_cast<Register>(reg + 1), base);
2390 Sw(reg, base, offset);
2391 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002392 break;
2393 default:
2394 LOG(FATAL) << "UNREACHABLE";
2395 }
2396}
2397
Goran Jakovljevicff734982015-08-24 12:58:55 +00002398void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002399 if (!IsInt<16>(offset)) {
2400 LoadConst32(AT, offset);
2401 Addu(AT, AT, base);
2402 base = AT;
2403 offset = 0;
2404 }
2405
jeffhao7fbee072012-08-24 17:56:54 -07002406 Swc1(reg, base, offset);
2407}
2408
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002409void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
2410 // IsInt<16> must be passed a signed value.
2411 if (!IsInt<16>(offset) ||
2412 (!IsAligned<kMipsDoublewordSize>(offset) &&
2413 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2414 LoadConst32(AT, offset);
2415 Addu(AT, AT, base);
2416 base = AT;
2417 offset = 0;
2418 }
2419
2420 if (offset & 0x7) {
2421 if (Is32BitFPU()) {
2422 Swc1(reg, base, offset);
2423 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2424 } else {
2425 // 64-bit FPU.
2426 Mfhc1(T8, reg);
2427 Swc1(reg, base, offset);
2428 Sw(T8, base, offset + kMipsWordSize);
2429 }
2430 } else {
2431 Sdc1(reg, base, offset);
2432 }
jeffhao7fbee072012-08-24 17:56:54 -07002433}
2434
David Srbeckydd973932015-04-07 20:29:48 +01002435static dwarf::Reg DWARFReg(Register reg) {
2436 return dwarf::Reg::MipsCore(static_cast<int>(reg));
2437}
2438
Ian Rogers790a6b72014-04-01 10:36:00 -07002439constexpr size_t kFramePointerSize = 4;
2440
Vladimir Marko32248382016-05-19 10:37:24 +01002441void MipsAssembler::BuildFrame(size_t frame_size,
2442 ManagedRegister method_reg,
2443 ArrayRef<const ManagedRegister> callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07002444 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07002445 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002446 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07002447
2448 // Increase frame to required size.
2449 IncreaseFrameSize(frame_size);
2450
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002451 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002452 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002453 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002454 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002455 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07002456 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002457 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07002458 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002459 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002460 }
2461
2462 // Write out Method*.
2463 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
2464
2465 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00002466 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002467 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00002468 MipsManagedRegister reg = entry_spills.at(i).AsMips();
2469 if (reg.IsNoRegister()) {
2470 ManagedRegisterSpill spill = entry_spills.at(i);
2471 offset += spill.getSize();
2472 } else if (reg.IsCoreRegister()) {
2473 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002474 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002475 } else if (reg.IsFRegister()) {
2476 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002477 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002478 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002479 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
2480 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002481 }
jeffhao7fbee072012-08-24 17:56:54 -07002482 }
2483}
2484
2485void MipsAssembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002486 ArrayRef<const ManagedRegister> callee_save_regs) {
jeffhao7fbee072012-08-24 17:56:54 -07002487 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002488 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002489 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07002490
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002491 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002492 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002493 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002494 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07002495 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002496 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07002497 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002498 }
2499 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002500 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07002501
2502 // Decrease frame to required size.
2503 DecreaseFrameSize(frame_size);
jeffhao07030602012-09-26 14:33:14 -07002504
2505 // Then jump to the return address.
2506 Jr(RA);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002507 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002508
2509 // The CFI should be restored for any code that follows the exit block.
2510 cfi_.RestoreState();
2511 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07002512}
2513
2514void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002515 CHECK_ALIGNED(adjust, kFramePointerSize);
2516 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002517 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002518 if (overwriting_) {
2519 cfi_.OverrideDelayedPC(overwrite_location_);
2520 }
jeffhao7fbee072012-08-24 17:56:54 -07002521}
2522
2523void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002524 CHECK_ALIGNED(adjust, kFramePointerSize);
2525 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002526 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002527 if (overwriting_) {
2528 cfi_.OverrideDelayedPC(overwrite_location_);
2529 }
jeffhao7fbee072012-08-24 17:56:54 -07002530}
2531
2532void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2533 MipsManagedRegister src = msrc.AsMips();
2534 if (src.IsNoRegister()) {
2535 CHECK_EQ(0u, size);
2536 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002537 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002538 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2539 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002540 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002541 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
2542 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002543 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002544 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002545 if (size == kMipsWordSize) {
2546 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
2547 } else {
2548 CHECK_EQ(kMipsDoublewordSize, size);
2549 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
2550 }
jeffhao7fbee072012-08-24 17:56:54 -07002551 }
2552}
2553
2554void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2555 MipsManagedRegister src = msrc.AsMips();
2556 CHECK(src.IsCoreRegister());
2557 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2558}
2559
2560void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2561 MipsManagedRegister src = msrc.AsMips();
2562 CHECK(src.IsCoreRegister());
2563 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2564}
2565
2566void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2567 ManagedRegister mscratch) {
2568 MipsManagedRegister scratch = mscratch.AsMips();
2569 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002570 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07002571 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2572}
2573
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002574void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
jeffhao7fbee072012-08-24 17:56:54 -07002575 ManagedRegister mscratch) {
2576 MipsManagedRegister scratch = mscratch.AsMips();
2577 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002578 // Is this function even referenced anywhere else in the code?
2579 LoadConst32(scratch.AsCoreRegister(), imm);
2580 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
2581}
2582
2583void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2584 FrameOffset fr_offs,
2585 ManagedRegister mscratch) {
2586 MipsManagedRegister scratch = mscratch.AsMips();
2587 CHECK(scratch.IsCoreRegister()) << scratch;
2588 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002589 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2590 S1, thr_offs.Int32Value());
2591}
2592
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002593void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002594 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2595}
2596
2597void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2598 FrameOffset in_off, ManagedRegister mscratch) {
2599 MipsManagedRegister src = msrc.AsMips();
2600 MipsManagedRegister scratch = mscratch.AsMips();
2601 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2602 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002603 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002604}
2605
2606void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2607 return EmitLoad(mdest, SP, src.Int32Value(), size);
2608}
2609
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002610void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2611 ThreadOffset<kMipsWordSize> src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002612 return EmitLoad(mdest, S1, src.Int32Value(), size);
2613}
2614
2615void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2616 MipsManagedRegister dest = mdest.AsMips();
2617 CHECK(dest.IsCoreRegister());
2618 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
2619}
2620
Mathieu Chartiere401d142015-04-22 13:56:20 -07002621void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002622 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07002623 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002624 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002625 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2626 base.AsMips().AsCoreRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002627 if (kPoisonHeapReferences && unpoison_reference) {
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08002628 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
2629 }
jeffhao7fbee072012-08-24 17:56:54 -07002630}
2631
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002632void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002633 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002634 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002635 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2636 base.AsMips().AsCoreRegister(), offs.Int32Value());
2637}
2638
Ian Rogersdd7624d2014-03-14 17:43:00 -07002639void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002640 ThreadOffset<kMipsWordSize> offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002641 MipsManagedRegister dest = mdest.AsMips();
2642 CHECK(dest.IsCoreRegister());
2643 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
2644}
2645
2646void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2647 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2648}
2649
2650void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2651 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2652}
2653
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002654void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002655 MipsManagedRegister dest = mdest.AsMips();
2656 MipsManagedRegister src = msrc.AsMips();
2657 if (!dest.Equals(src)) {
2658 if (dest.IsCoreRegister()) {
2659 CHECK(src.IsCoreRegister()) << src;
2660 Move(dest.AsCoreRegister(), src.AsCoreRegister());
2661 } else if (dest.IsFRegister()) {
2662 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002663 if (size == kMipsWordSize) {
2664 MovS(dest.AsFRegister(), src.AsFRegister());
2665 } else {
2666 CHECK_EQ(kMipsDoublewordSize, size);
2667 MovD(dest.AsFRegister(), src.AsFRegister());
2668 }
jeffhao7fbee072012-08-24 17:56:54 -07002669 } else if (dest.IsDRegister()) {
2670 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002671 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07002672 } else {
2673 CHECK(dest.IsRegisterPair()) << dest;
2674 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002675 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07002676 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
2677 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2678 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2679 } else {
2680 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2681 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2682 }
2683 }
2684 }
2685}
2686
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002687void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002688 MipsManagedRegister scratch = mscratch.AsMips();
2689 CHECK(scratch.IsCoreRegister()) << scratch;
2690 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2691 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2692}
2693
Ian Rogersdd7624d2014-03-14 17:43:00 -07002694void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002695 ThreadOffset<kMipsWordSize> thr_offs,
2696 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002697 MipsManagedRegister scratch = mscratch.AsMips();
2698 CHECK(scratch.IsCoreRegister()) << scratch;
2699 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2700 S1, thr_offs.Int32Value());
2701 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2702 SP, fr_offs.Int32Value());
2703}
2704
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002705void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2706 FrameOffset fr_offs,
2707 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002708 MipsManagedRegister scratch = mscratch.AsMips();
2709 CHECK(scratch.IsCoreRegister()) << scratch;
2710 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2711 SP, fr_offs.Int32Value());
2712 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2713 S1, thr_offs.Int32Value());
2714}
2715
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002716void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002717 MipsManagedRegister scratch = mscratch.AsMips();
2718 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002719 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2720 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002721 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2722 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002723 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002724 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2725 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002726 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2727 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002728 }
2729}
2730
2731void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2732 ManagedRegister mscratch, size_t size) {
2733 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002734 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002735 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2736 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2737}
2738
2739void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2740 ManagedRegister mscratch, size_t size) {
2741 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002742 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002743 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2744 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2745}
2746
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002747void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2748 FrameOffset src_base ATTRIBUTE_UNUSED,
2749 Offset src_offset ATTRIBUTE_UNUSED,
2750 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2751 size_t size ATTRIBUTE_UNUSED) {
2752 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002753}
2754
2755void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2756 ManagedRegister src, Offset src_offset,
2757 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002758 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002759 Register scratch = mscratch.AsMips().AsCoreRegister();
2760 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2761 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2762}
2763
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002764void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2765 Offset dest_offset ATTRIBUTE_UNUSED,
2766 FrameOffset src ATTRIBUTE_UNUSED,
2767 Offset src_offset ATTRIBUTE_UNUSED,
2768 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2769 size_t size ATTRIBUTE_UNUSED) {
2770 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002771}
2772
2773void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002774 // TODO: sync?
2775 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002776}
2777
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002778void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002779 FrameOffset handle_scope_offset,
2780 ManagedRegister min_reg,
2781 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002782 MipsManagedRegister out_reg = mout_reg.AsMips();
2783 MipsManagedRegister in_reg = min_reg.AsMips();
2784 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2785 CHECK(out_reg.IsCoreRegister()) << out_reg;
2786 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002787 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002788 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2789 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002790 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07002791 if (in_reg.IsNoRegister()) {
2792 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002793 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002794 in_reg = out_reg;
2795 }
2796 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002797 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002798 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002799 Beqz(in_reg.AsCoreRegister(), &null_arg);
2800 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2801 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002802 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002803 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002804 }
2805}
2806
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002807void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002808 FrameOffset handle_scope_offset,
2809 ManagedRegister mscratch,
2810 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002811 MipsManagedRegister scratch = mscratch.AsMips();
2812 CHECK(scratch.IsCoreRegister()) << scratch;
2813 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002814 MipsLabel null_arg;
2815 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002816 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2817 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002818 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2819 Beqz(scratch.AsCoreRegister(), &null_arg);
2820 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2821 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002822 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002823 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002824 }
2825 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2826}
2827
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002828// Given a handle scope entry, load the associated reference.
2829void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002830 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07002831 MipsManagedRegister out_reg = mout_reg.AsMips();
2832 MipsManagedRegister in_reg = min_reg.AsMips();
2833 CHECK(out_reg.IsCoreRegister()) << out_reg;
2834 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002835 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07002836 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002837 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002838 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002839 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002840 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2841 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002842 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002843}
2844
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002845void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2846 bool could_be_null ATTRIBUTE_UNUSED) {
2847 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002848}
2849
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002850void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2851 bool could_be_null ATTRIBUTE_UNUSED) {
2852 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002853}
2854
2855void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2856 MipsManagedRegister base = mbase.AsMips();
2857 MipsManagedRegister scratch = mscratch.AsMips();
2858 CHECK(base.IsCoreRegister()) << base;
2859 CHECK(scratch.IsCoreRegister()) << scratch;
2860 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2861 base.AsCoreRegister(), offset.Int32Value());
2862 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002863 Nop();
2864 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002865}
2866
2867void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2868 MipsManagedRegister scratch = mscratch.AsMips();
2869 CHECK(scratch.IsCoreRegister()) << scratch;
2870 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002871 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002872 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2873 scratch.AsCoreRegister(), offset.Int32Value());
2874 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002875 Nop();
2876 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002877}
2878
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002879void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2880 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07002881 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002882}
2883
2884void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2885 Move(tr.AsMips().AsCoreRegister(), S1);
2886}
2887
2888void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002889 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07002890 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2891}
2892
jeffhao7fbee072012-08-24 17:56:54 -07002893void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2894 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002895 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07002896 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002897 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2898 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2899 // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2900 // For now use common for R2 and R6 instructions as this code must execute on both.
2901 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07002902}
2903
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002904void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2905 Bind(exception->Entry());
2906 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2907 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07002908 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002909 // Pass exception object as argument.
2910 // Don't care about preserving A0 as this call won't return.
2911 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2912 Move(A0, exception->scratch_.AsCoreRegister());
2913 // Set up call to Thread::Current()->pDeliverException.
2914 LoadFromOffset(kLoadWord, T9, S1,
2915 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2916 Jr(T9);
2917 Nop();
2918
2919 // Call never returns.
2920 Break();
jeffhao7fbee072012-08-24 17:56:54 -07002921}
2922
2923} // namespace mips
2924} // namespace art