blob: 6fd65ee9a43efbec48739c59147c1fc7b19c42ad [file] [log] [blame]
jeffhao7fbee072012-08-24 17:56:54 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080020#include "base/casts.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "entrypoints/quick/quick_entrypoints.h"
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020022#include "entrypoints/quick/quick_entrypoints_enum.h"
jeffhao7fbee072012-08-24 17:56:54 -070023#include "memory_region.h"
jeffhao7fbee072012-08-24 17:56:54 -070024#include "thread.h"
25
26namespace art {
27namespace mips {
jeffhao7fbee072012-08-24 17:56:54 -070028
jeffhao7fbee072012-08-24 17:56:54 -070029std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
30 if (rhs >= D0 && rhs < kNumberOfDRegisters) {
31 os << "d" << static_cast<int>(rhs);
32 } else {
33 os << "DRegister[" << static_cast<int>(rhs) << "]";
34 }
35 return os;
36}
37
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020038void MipsAssembler::FinalizeCode() {
39 for (auto& exception_block : exception_blocks_) {
40 EmitExceptionPoll(&exception_block);
41 }
42 PromoteBranches();
43}
44
45void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
Vladimir Marko10ef6942015-10-22 15:25:54 +010046 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020047 EmitBranches();
48 Assembler::FinalizeInstructions(region);
Vladimir Marko10ef6942015-10-22 15:25:54 +010049 PatchCFI(number_of_delayed_adjust_pcs);
50}
51
52void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
53 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
54 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
55 return;
56 }
57
58 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
59 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
60 const std::vector<uint8_t>& old_stream = data.first;
61 const std::vector<DelayedAdvancePC>& advances = data.second;
62
63 // PCs recorded before EmitBranches() need to be adjusted.
64 // PCs recorded during EmitBranches() are already adjusted.
65 // Both ranges are separately sorted but they may overlap.
66 if (kIsDebugBuild) {
67 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
68 return lhs.pc < rhs.pc;
69 };
70 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
71 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
72 }
73
74 // Append initial CFI data if any.
75 size_t size = advances.size();
76 DCHECK_NE(size, 0u);
77 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
78 // Emit PC adjustments interleaved with the old CFI stream.
79 size_t adjust_pos = 0u;
80 size_t late_emit_pos = number_of_delayed_adjust_pcs;
81 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
82 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
83 ? GetAdjustedPosition(advances[adjust_pos].pc)
84 : static_cast<size_t>(-1);
85 size_t late_emit_pc = (late_emit_pos != size)
86 ? advances[late_emit_pos].pc
87 : static_cast<size_t>(-1);
88 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
89 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
90 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
91 if (adjusted_pc <= late_emit_pc) {
92 ++adjust_pos;
93 } else {
94 ++late_emit_pos;
95 }
96 cfi().AdvancePC(advance_pc);
97 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
98 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
99 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200100}
101
102void MipsAssembler::EmitBranches() {
103 CHECK(!overwriting_);
104 // Switch from appending instructions at the end of the buffer to overwriting
105 // existing instructions (branch placeholders) in the buffer.
106 overwriting_ = true;
107 for (auto& branch : branches_) {
108 EmitBranch(&branch);
109 }
110 overwriting_ = false;
111}
112
113void MipsAssembler::Emit(uint32_t value) {
114 if (overwriting_) {
115 // Branches to labels are emitted into their placeholders here.
116 buffer_.Store<uint32_t>(overwrite_location_, value);
117 overwrite_location_ += sizeof(uint32_t);
118 } else {
119 // Other instructions are simply appended at the end here.
120 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
121 buffer_.Emit<uint32_t>(value);
122 }
jeffhao7fbee072012-08-24 17:56:54 -0700123}
124
125void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
126 CHECK_NE(rs, kNoRegister);
127 CHECK_NE(rt, kNoRegister);
128 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200129 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
130 static_cast<uint32_t>(rs) << kRsShift |
131 static_cast<uint32_t>(rt) << kRtShift |
132 static_cast<uint32_t>(rd) << kRdShift |
133 shamt << kShamtShift |
134 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700135 Emit(encoding);
136}
137
138void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
139 CHECK_NE(rs, kNoRegister);
140 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200141 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
142 static_cast<uint32_t>(rs) << kRsShift |
143 static_cast<uint32_t>(rt) << kRtShift |
144 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700145 Emit(encoding);
146}
147
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200148void MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
149 CHECK_NE(rs, kNoRegister);
150 CHECK(IsUint<21>(imm21)) << imm21;
151 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
152 static_cast<uint32_t>(rs) << kRsShift |
153 imm21;
jeffhao7fbee072012-08-24 17:56:54 -0700154 Emit(encoding);
155}
156
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200157void MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
158 CHECK(IsUint<26>(imm26)) << imm26;
159 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
160 Emit(encoding);
161}
162
163void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd,
164 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700165 CHECK_NE(ft, kNoFRegister);
166 CHECK_NE(fs, kNoFRegister);
167 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200168 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
169 fmt << kFmtShift |
170 static_cast<uint32_t>(ft) << kFtShift |
171 static_cast<uint32_t>(fs) << kFsShift |
172 static_cast<uint32_t>(fd) << kFdShift |
173 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700174 Emit(encoding);
175}
176
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200177void MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
178 CHECK_NE(ft, kNoFRegister);
179 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
180 fmt << kFmtShift |
181 static_cast<uint32_t>(ft) << kFtShift |
182 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700183 Emit(encoding);
184}
185
jeffhao7fbee072012-08-24 17:56:54 -0700186void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
187 EmitR(0, rs, rt, rd, 0, 0x21);
188}
189
jeffhao7fbee072012-08-24 17:56:54 -0700190void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
191 EmitI(0x9, rs, rt, imm16);
192}
193
jeffhao7fbee072012-08-24 17:56:54 -0700194void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
195 EmitR(0, rs, rt, rd, 0, 0x23);
196}
197
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200198void MipsAssembler::MultR2(Register rs, Register rt) {
199 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700200 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
201}
202
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200203void MipsAssembler::MultuR2(Register rs, Register rt) {
204 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700205 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
206}
207
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200208void MipsAssembler::DivR2(Register rs, Register rt) {
209 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700210 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
211}
212
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200213void MipsAssembler::DivuR2(Register rs, Register rt) {
214 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700215 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
216}
217
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200218void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
219 CHECK(!IsR6());
220 EmitR(0x1c, rs, rt, rd, 0, 2);
221}
222
223void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
224 CHECK(!IsR6());
225 DivR2(rs, rt);
226 Mflo(rd);
227}
228
229void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
230 CHECK(!IsR6());
231 DivR2(rs, rt);
232 Mfhi(rd);
233}
234
235void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
236 CHECK(!IsR6());
237 DivuR2(rs, rt);
238 Mflo(rd);
239}
240
241void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
242 CHECK(!IsR6());
243 DivuR2(rs, rt);
244 Mfhi(rd);
245}
246
247void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
248 CHECK(IsR6());
249 EmitR(0, rs, rt, rd, 2, 0x18);
250}
251
Alexey Frunze7e99e052015-11-24 19:28:01 -0800252void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
253 CHECK(IsR6());
254 EmitR(0, rs, rt, rd, 3, 0x18);
255}
256
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200257void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
258 CHECK(IsR6());
259 EmitR(0, rs, rt, rd, 3, 0x19);
260}
261
262void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
263 CHECK(IsR6());
264 EmitR(0, rs, rt, rd, 2, 0x1a);
265}
266
267void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
268 CHECK(IsR6());
269 EmitR(0, rs, rt, rd, 3, 0x1a);
270}
271
272void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
273 CHECK(IsR6());
274 EmitR(0, rs, rt, rd, 2, 0x1b);
275}
276
277void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
278 CHECK(IsR6());
279 EmitR(0, rs, rt, rd, 3, 0x1b);
280}
281
jeffhao7fbee072012-08-24 17:56:54 -0700282void MipsAssembler::And(Register rd, Register rs, Register rt) {
283 EmitR(0, rs, rt, rd, 0, 0x24);
284}
285
286void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
287 EmitI(0xc, rs, rt, imm16);
288}
289
290void MipsAssembler::Or(Register rd, Register rs, Register rt) {
291 EmitR(0, rs, rt, rd, 0, 0x25);
292}
293
294void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
295 EmitI(0xd, rs, rt, imm16);
296}
297
298void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
299 EmitR(0, rs, rt, rd, 0, 0x26);
300}
301
302void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
303 EmitI(0xe, rs, rt, imm16);
304}
305
306void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
307 EmitR(0, rs, rt, rd, 0, 0x27);
308}
309
Chris Larsene3845472015-11-18 12:27:15 -0800310void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
311 CHECK(!IsR6());
312 EmitR(0, rs, rt, rd, 0, 0x0A);
313}
314
315void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
316 CHECK(!IsR6());
317 EmitR(0, rs, rt, rd, 0, 0x0B);
318}
319
320void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
321 CHECK(IsR6());
322 EmitR(0, rs, rt, rd, 0, 0x35);
323}
324
325void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
326 CHECK(IsR6());
327 EmitR(0, rs, rt, rd, 0, 0x37);
328}
329
330void MipsAssembler::ClzR6(Register rd, Register rs) {
331 CHECK(IsR6());
332 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10);
333}
334
335void MipsAssembler::ClzR2(Register rd, Register rs) {
336 CHECK(!IsR6());
337 EmitR(0x1C, rs, rd, rd, 0, 0x20);
338}
339
340void MipsAssembler::CloR6(Register rd, Register rs) {
341 CHECK(IsR6());
342 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11);
343}
344
345void MipsAssembler::CloR2(Register rd, Register rs) {
346 CHECK(!IsR6());
347 EmitR(0x1C, rs, rd, rd, 0, 0x21);
348}
349
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200350void MipsAssembler::Seb(Register rd, Register rt) {
351 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700352}
353
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200354void MipsAssembler::Seh(Register rd, Register rt) {
355 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20);
jeffhao7fbee072012-08-24 17:56:54 -0700356}
357
Chris Larsen3f8bf652015-10-28 10:08:56 -0700358void MipsAssembler::Wsbh(Register rd, Register rt) {
359 EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20);
360}
361
Chris Larsen70014c82015-11-18 12:26:08 -0800362void MipsAssembler::Bitswap(Register rd, Register rt) {
363 CHECK(IsR6());
364 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20);
365}
366
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200367void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700368 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200369 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00);
jeffhao7fbee072012-08-24 17:56:54 -0700370}
371
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700373 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200374 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02);
375}
376
Chris Larsen3f8bf652015-10-28 10:08:56 -0700377void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
378 CHECK(IsUint<5>(shamt)) << shamt;
379 EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02);
380}
381
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200382void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700383 CHECK(IsUint<5>(shamt)) << shamt;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200384 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03);
385}
386
387void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700388 EmitR(0, rs, rt, rd, 0, 0x04);
389}
390
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200391void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700392 EmitR(0, rs, rt, rd, 0, 0x06);
393}
394
Chris Larsene16ce5a2015-11-18 12:30:20 -0800395void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
396 EmitR(0, rs, rt, rd, 1, 0x06);
397}
398
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200399void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
jeffhao7fbee072012-08-24 17:56:54 -0700400 EmitR(0, rs, rt, rd, 0, 0x07);
401}
402
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800403void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
404 CHECK(IsUint<5>(pos)) << pos;
405 CHECK(0 < size && size <= 32) << size;
406 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
407 EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00);
408}
409
410void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
411 CHECK(IsUint<5>(pos)) << pos;
412 CHECK(0 < size && size <= 32) << size;
413 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
414 EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04);
415}
416
jeffhao7fbee072012-08-24 17:56:54 -0700417void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
418 EmitI(0x20, rs, rt, imm16);
419}
420
421void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
422 EmitI(0x21, rs, rt, imm16);
423}
424
425void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
426 EmitI(0x23, rs, rt, imm16);
427}
428
Chris Larsen3acee732015-11-18 13:31:08 -0800429void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
430 CHECK(!IsR6());
431 EmitI(0x22, rs, rt, imm16);
432}
433
434void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
435 CHECK(!IsR6());
436 EmitI(0x26, rs, rt, imm16);
437}
438
jeffhao7fbee072012-08-24 17:56:54 -0700439void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
440 EmitI(0x24, rs, rt, imm16);
441}
442
443void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
444 EmitI(0x25, rs, rt, imm16);
445}
446
447void MipsAssembler::Lui(Register rt, uint16_t imm16) {
448 EmitI(0xf, static_cast<Register>(0), rt, imm16);
449}
450
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200451void MipsAssembler::Sync(uint32_t stype) {
452 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0),
453 stype & 0x1f, 0xf);
454}
455
jeffhao7fbee072012-08-24 17:56:54 -0700456void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200457 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700458 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
459}
460
461void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200462 CHECK(!IsR6());
jeffhao7fbee072012-08-24 17:56:54 -0700463 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
464}
465
466void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
467 EmitI(0x28, rs, rt, imm16);
468}
469
470void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
471 EmitI(0x29, rs, rt, imm16);
472}
473
474void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
475 EmitI(0x2b, rs, rt, imm16);
476}
477
Chris Larsen3acee732015-11-18 13:31:08 -0800478void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
479 CHECK(!IsR6());
480 EmitI(0x2a, rs, rt, imm16);
481}
482
483void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
484 CHECK(!IsR6());
485 EmitI(0x2e, rs, rt, imm16);
486}
487
jeffhao7fbee072012-08-24 17:56:54 -0700488void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
489 EmitR(0, rs, rt, rd, 0, 0x2a);
490}
491
492void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
493 EmitR(0, rs, rt, rd, 0, 0x2b);
494}
495
496void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
497 EmitI(0xa, rs, rt, imm16);
498}
499
500void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
501 EmitI(0xb, rs, rt, imm16);
502}
503
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200504void MipsAssembler::B(uint16_t imm16) {
505 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16);
506}
507
508void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700509 EmitI(0x4, rs, rt, imm16);
510}
511
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200512void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
jeffhao7fbee072012-08-24 17:56:54 -0700513 EmitI(0x5, rs, rt, imm16);
514}
515
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200516void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
517 Beq(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700518}
519
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200520void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
521 Bne(ZERO, rt, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700522}
523
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200524void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
525 EmitI(0x1, rt, static_cast<Register>(0), imm16);
526}
527
528void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
529 EmitI(0x1, rt, static_cast<Register>(0x1), imm16);
530}
531
532void MipsAssembler::Blez(Register rt, uint16_t imm16) {
533 EmitI(0x6, rt, static_cast<Register>(0), imm16);
534}
535
536void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
537 EmitI(0x7, rt, static_cast<Register>(0), imm16);
538}
539
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800540void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
541 CHECK(!IsR6());
542 CHECK(IsUint<3>(cc)) << cc;
543 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16);
544}
545
546void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
547 CHECK(!IsR6());
548 CHECK(IsUint<3>(cc)) << cc;
549 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16);
550}
551
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200552void MipsAssembler::J(uint32_t addr26) {
553 EmitI26(0x2, addr26);
554}
555
556void MipsAssembler::Jal(uint32_t addr26) {
557 EmitI26(0x3, addr26);
558}
559
560void MipsAssembler::Jalr(Register rd, Register rs) {
561 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09);
jeffhao7fbee072012-08-24 17:56:54 -0700562}
563
564void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200565 Jalr(RA, rs);
566}
567
568void MipsAssembler::Jr(Register rs) {
569 Jalr(ZERO, rs);
570}
571
572void MipsAssembler::Nal() {
573 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0);
574}
575
576void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
577 CHECK(IsR6());
578 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16);
579}
580
581void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
582 CHECK(IsR6());
583 CHECK(IsUint<19>(imm19)) << imm19;
584 EmitI21(0x3B, rs, imm19);
585}
586
587void MipsAssembler::Bc(uint32_t imm26) {
588 CHECK(IsR6());
589 EmitI26(0x32, imm26);
590}
591
592void MipsAssembler::Jic(Register rt, uint16_t imm16) {
593 CHECK(IsR6());
594 EmitI(0x36, static_cast<Register>(0), rt, imm16);
595}
596
597void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
598 CHECK(IsR6());
599 EmitI(0x3E, static_cast<Register>(0), rt, imm16);
600}
601
602void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
603 CHECK(IsR6());
604 CHECK_NE(rs, ZERO);
605 CHECK_NE(rt, ZERO);
606 CHECK_NE(rs, rt);
607 EmitI(0x17, rs, rt, imm16);
608}
609
610void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
611 CHECK(IsR6());
612 CHECK_NE(rt, ZERO);
613 EmitI(0x17, rt, rt, imm16);
614}
615
616void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
617 CHECK(IsR6());
618 CHECK_NE(rt, ZERO);
619 EmitI(0x17, static_cast<Register>(0), rt, imm16);
620}
621
622void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
623 CHECK(IsR6());
624 CHECK_NE(rs, ZERO);
625 CHECK_NE(rt, ZERO);
626 CHECK_NE(rs, rt);
627 EmitI(0x16, rs, rt, imm16);
628}
629
630void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
631 CHECK(IsR6());
632 CHECK_NE(rt, ZERO);
633 EmitI(0x16, rt, rt, imm16);
634}
635
636void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
637 CHECK(IsR6());
638 CHECK_NE(rt, ZERO);
639 EmitI(0x16, static_cast<Register>(0), rt, imm16);
640}
641
642void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
643 CHECK(IsR6());
644 CHECK_NE(rs, ZERO);
645 CHECK_NE(rt, ZERO);
646 CHECK_NE(rs, rt);
647 EmitI(0x7, rs, rt, imm16);
648}
649
650void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
651 CHECK(IsR6());
652 CHECK_NE(rs, ZERO);
653 CHECK_NE(rt, ZERO);
654 CHECK_NE(rs, rt);
655 EmitI(0x6, rs, rt, imm16);
656}
657
658void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
659 CHECK(IsR6());
660 CHECK_NE(rs, ZERO);
661 CHECK_NE(rt, ZERO);
662 CHECK_NE(rs, rt);
663 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
664}
665
666void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
667 CHECK(IsR6());
668 CHECK_NE(rs, ZERO);
669 CHECK_NE(rt, ZERO);
670 CHECK_NE(rs, rt);
671 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
672}
673
674void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
675 CHECK(IsR6());
676 CHECK_NE(rs, ZERO);
677 EmitI21(0x36, rs, imm21);
678}
679
680void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
681 CHECK(IsR6());
682 CHECK_NE(rs, ZERO);
683 EmitI21(0x3E, rs, imm21);
684}
685
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800686void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
687 CHECK(IsR6());
688 EmitFI(0x11, 0x9, ft, imm16);
689}
690
691void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
692 CHECK(IsR6());
693 EmitFI(0x11, 0xD, ft, imm16);
694}
695
696void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200697 switch (cond) {
698 case kCondLTZ:
699 CHECK_EQ(rt, ZERO);
700 Bltz(rs, imm16);
701 break;
702 case kCondGEZ:
703 CHECK_EQ(rt, ZERO);
704 Bgez(rs, imm16);
705 break;
706 case kCondLEZ:
707 CHECK_EQ(rt, ZERO);
708 Blez(rs, imm16);
709 break;
710 case kCondGTZ:
711 CHECK_EQ(rt, ZERO);
712 Bgtz(rs, imm16);
713 break;
714 case kCondEQ:
715 Beq(rs, rt, imm16);
716 break;
717 case kCondNE:
718 Bne(rs, rt, imm16);
719 break;
720 case kCondEQZ:
721 CHECK_EQ(rt, ZERO);
722 Beqz(rs, imm16);
723 break;
724 case kCondNEZ:
725 CHECK_EQ(rt, ZERO);
726 Bnez(rs, imm16);
727 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800728 case kCondF:
729 CHECK_EQ(rt, ZERO);
730 Bc1f(static_cast<int>(rs), imm16);
731 break;
732 case kCondT:
733 CHECK_EQ(rt, ZERO);
734 Bc1t(static_cast<int>(rs), imm16);
735 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200736 case kCondLT:
737 case kCondGE:
738 case kCondLE:
739 case kCondGT:
740 case kCondLTU:
741 case kCondGEU:
742 case kUncond:
743 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
744 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
745 LOG(FATAL) << "Unexpected branch condition " << cond;
746 UNREACHABLE();
747 }
748}
749
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800750void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200751 switch (cond) {
752 case kCondLT:
753 Bltc(rs, rt, imm16_21);
754 break;
755 case kCondGE:
756 Bgec(rs, rt, imm16_21);
757 break;
758 case kCondLE:
759 Bgec(rt, rs, imm16_21);
760 break;
761 case kCondGT:
762 Bltc(rt, rs, imm16_21);
763 break;
764 case kCondLTZ:
765 CHECK_EQ(rt, ZERO);
766 Bltzc(rs, imm16_21);
767 break;
768 case kCondGEZ:
769 CHECK_EQ(rt, ZERO);
770 Bgezc(rs, imm16_21);
771 break;
772 case kCondLEZ:
773 CHECK_EQ(rt, ZERO);
774 Blezc(rs, imm16_21);
775 break;
776 case kCondGTZ:
777 CHECK_EQ(rt, ZERO);
778 Bgtzc(rs, imm16_21);
779 break;
780 case kCondEQ:
781 Beqc(rs, rt, imm16_21);
782 break;
783 case kCondNE:
784 Bnec(rs, rt, imm16_21);
785 break;
786 case kCondEQZ:
787 CHECK_EQ(rt, ZERO);
788 Beqzc(rs, imm16_21);
789 break;
790 case kCondNEZ:
791 CHECK_EQ(rt, ZERO);
792 Bnezc(rs, imm16_21);
793 break;
794 case kCondLTU:
795 Bltuc(rs, rt, imm16_21);
796 break;
797 case kCondGEU:
798 Bgeuc(rs, rt, imm16_21);
799 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800800 case kCondF:
801 CHECK_EQ(rt, ZERO);
802 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
803 break;
804 case kCondT:
805 CHECK_EQ(rt, ZERO);
806 Bc1nez(static_cast<FRegister>(rs), imm16_21);
807 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200808 case kUncond:
809 LOG(FATAL) << "Unexpected branch condition " << cond;
810 UNREACHABLE();
811 }
jeffhao7fbee072012-08-24 17:56:54 -0700812}
813
814void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
815 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
816}
817
818void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
819 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
820}
821
822void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
823 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
824}
825
826void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
827 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
828}
829
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200830void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
831 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
jeffhao7fbee072012-08-24 17:56:54 -0700832}
833
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200834void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
835 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
jeffhao7fbee072012-08-24 17:56:54 -0700836}
837
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200838void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
839 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
jeffhao7fbee072012-08-24 17:56:54 -0700840}
841
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200842void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
843 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
jeffhao7fbee072012-08-24 17:56:54 -0700844}
845
846void MipsAssembler::MovS(FRegister fd, FRegister fs) {
847 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
848}
849
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200850void MipsAssembler::MovD(FRegister fd, FRegister fs) {
851 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6);
852}
853
854void MipsAssembler::NegS(FRegister fd, FRegister fs) {
855 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7);
856}
857
858void MipsAssembler::NegD(FRegister fd, FRegister fs) {
859 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7);
860}
861
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800862void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
863 CHECK(!IsR6());
864 CHECK(IsUint<3>(cc)) << cc;
865 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
866}
867
868void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
869 CHECK(!IsR6());
870 CHECK(IsUint<3>(cc)) << cc;
871 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
872}
873
874void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
875 CHECK(!IsR6());
876 CHECK(IsUint<3>(cc)) << cc;
877 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
878}
879
880void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
881 CHECK(!IsR6());
882 CHECK(IsUint<3>(cc)) << cc;
883 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
884}
885
886void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
887 CHECK(!IsR6());
888 CHECK(IsUint<3>(cc)) << cc;
889 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
890}
891
892void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
893 CHECK(!IsR6());
894 CHECK(IsUint<3>(cc)) << cc;
895 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
896}
897
898void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
899 CHECK(!IsR6());
900 CHECK(IsUint<3>(cc)) << cc;
901 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
902}
903
904void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
905 CHECK(!IsR6());
906 CHECK(IsUint<3>(cc)) << cc;
907 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31);
908}
909
910void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
911 CHECK(!IsR6());
912 CHECK(IsUint<3>(cc)) << cc;
913 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32);
914}
915
916void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
917 CHECK(!IsR6());
918 CHECK(IsUint<3>(cc)) << cc;
919 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33);
920}
921
922void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
923 CHECK(!IsR6());
924 CHECK(IsUint<3>(cc)) << cc;
925 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34);
926}
927
928void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
929 CHECK(!IsR6());
930 CHECK(IsUint<3>(cc)) << cc;
931 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35);
932}
933
934void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
935 CHECK(!IsR6());
936 CHECK(IsUint<3>(cc)) << cc;
937 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36);
938}
939
940void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
941 CHECK(!IsR6());
942 CHECK(IsUint<3>(cc)) << cc;
943 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37);
944}
945
946void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
947 CHECK(IsR6());
948 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
949}
950
951void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
952 CHECK(IsR6());
953 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
954}
955
956void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
957 CHECK(IsR6());
958 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
959}
960
961void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
962 CHECK(IsR6());
963 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
964}
965
966void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
967 CHECK(IsR6());
968 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
969}
970
971void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
972 CHECK(IsR6());
973 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
974}
975
976void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
977 CHECK(IsR6());
978 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
979}
980
981void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
982 CHECK(IsR6());
983 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
984}
985
986void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
987 CHECK(IsR6());
988 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
989}
990
991void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
992 CHECK(IsR6());
993 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
994}
995
996void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
997 CHECK(IsR6());
998 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
999}
1000
1001void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1002 CHECK(IsR6());
1003 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1004}
1005
1006void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1007 CHECK(IsR6());
1008 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1009}
1010
1011void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1012 CHECK(IsR6());
1013 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1014}
1015
1016void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1017 CHECK(IsR6());
1018 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1019}
1020
1021void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1022 CHECK(IsR6());
1023 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1024}
1025
1026void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1027 CHECK(IsR6());
1028 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1029}
1030
1031void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1032 CHECK(IsR6());
1033 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1034}
1035
1036void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1037 CHECK(IsR6());
1038 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1039}
1040
1041void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1042 CHECK(IsR6());
1043 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1044}
1045
1046void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1047 CHECK(!IsR6());
1048 CHECK(IsUint<3>(cc)) << cc;
1049 EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01);
1050}
1051
1052void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1053 CHECK(!IsR6());
1054 CHECK(IsUint<3>(cc)) << cc;
1055 EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01);
1056}
1057
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001058void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1059 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09);
1060}
1061
1062void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1063 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09);
1064}
1065
1066void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1067 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D);
1068}
1069
1070void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1071 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D);
1072}
1073
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001074void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1075 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20);
1076}
1077
1078void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1079 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21);
1080}
1081
1082void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1083 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20);
1084}
1085
1086void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1087 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21);
jeffhao7fbee072012-08-24 17:56:54 -07001088}
1089
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001090void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1091 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20);
1092}
1093
1094void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1095 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21);
1096}
1097
jeffhao7fbee072012-08-24 17:56:54 -07001098void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001099 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001100}
1101
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001102void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1103 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1104}
1105
1106void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1107 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1108}
1109
1110void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1111 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
jeffhao7fbee072012-08-24 17:56:54 -07001112}
1113
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001114void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1115 if (Is32BitFPU()) {
1116 CHECK_EQ(fs % 2, 0) << fs;
1117 Mfc1(rt, static_cast<FRegister>(fs + 1));
1118 } else {
1119 Mfhc1(rt, fs);
1120 }
1121}
1122
1123void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1124 if (Is32BitFPU()) {
1125 CHECK_EQ(fs % 2, 0) << fs;
1126 Mtc1(rt, static_cast<FRegister>(fs + 1));
1127 } else {
1128 Mthc1(rt, fs);
1129 }
1130}
1131
jeffhao7fbee072012-08-24 17:56:54 -07001132void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001133 EmitI(0x31, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001134}
1135
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001136void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1137 EmitI(0x35, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001138}
1139
1140void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001141 EmitI(0x39, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001142}
1143
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001144void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1145 EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
jeffhao7fbee072012-08-24 17:56:54 -07001146}
1147
1148void MipsAssembler::Break() {
1149 EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
1150 static_cast<Register>(0), 0, 0xD);
1151}
1152
jeffhao07030602012-09-26 14:33:14 -07001153void MipsAssembler::Nop() {
1154 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
1155}
1156
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001157void MipsAssembler::Move(Register rd, Register rs) {
1158 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001159}
1160
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001161void MipsAssembler::Clear(Register rd) {
1162 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001163}
1164
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001165void MipsAssembler::Not(Register rd, Register rs) {
1166 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001167}
1168
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001169void MipsAssembler::Push(Register rs) {
1170 IncreaseFrameSize(kMipsWordSize);
1171 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001172}
1173
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001174void MipsAssembler::Pop(Register rd) {
1175 Lw(rd, SP, 0);
1176 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001177}
1178
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001179void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1180 Lw(rd, SP, 0);
1181 Jr(rt);
1182 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001183}
1184
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001185void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1186 if (IsUint<16>(value)) {
1187 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1188 Ori(rd, ZERO, value);
1189 } else if (IsInt<16>(value)) {
1190 // Use ADD with (signed) immediate to encode 16b signed int.
1191 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07001192 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001193 Lui(rd, High16Bits(value));
1194 if (value & 0xFFFF)
1195 Ori(rd, rd, Low16Bits(value));
1196 }
1197}
1198
1199void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001200 uint32_t low = Low32Bits(value);
1201 uint32_t high = High32Bits(value);
1202 LoadConst32(reg_lo, low);
1203 if (high != low) {
1204 LoadConst32(reg_hi, high);
1205 } else {
1206 Move(reg_hi, reg_lo);
1207 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001208}
1209
1210void MipsAssembler::StoreConst32ToOffset(int32_t value,
1211 Register base,
1212 int32_t offset,
1213 Register temp) {
1214 if (!IsInt<16>(offset)) {
1215 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1216 LoadConst32(AT, offset);
1217 Addu(AT, AT, base);
1218 base = AT;
1219 offset = 0;
1220 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001221 if (value == 0) {
1222 temp = ZERO;
1223 } else {
1224 LoadConst32(temp, value);
1225 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001226 Sw(temp, base, offset);
1227}
1228
1229void MipsAssembler::StoreConst64ToOffset(int64_t value,
1230 Register base,
1231 int32_t offset,
1232 Register temp) {
1233 // IsInt<16> must be passed a signed value.
1234 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
1235 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value.
1236 LoadConst32(AT, offset);
1237 Addu(AT, AT, base);
1238 base = AT;
1239 offset = 0;
1240 }
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001241 uint32_t low = Low32Bits(value);
1242 uint32_t high = High32Bits(value);
1243 if (low == 0) {
1244 Sw(ZERO, base, offset);
1245 } else {
1246 LoadConst32(temp, low);
1247 Sw(temp, base, offset);
1248 }
1249 if (high == 0) {
1250 Sw(ZERO, base, offset + kMipsWordSize);
1251 } else {
1252 if (high != low) {
1253 LoadConst32(temp, high);
1254 }
1255 Sw(temp, base, offset + kMipsWordSize);
1256 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001257}
1258
1259void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001260 if (value == 0) {
1261 temp = ZERO;
1262 } else {
1263 LoadConst32(temp, value);
1264 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001265 Mtc1(temp, r);
1266}
1267
1268void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001269 uint32_t low = Low32Bits(value);
1270 uint32_t high = High32Bits(value);
1271 if (low == 0) {
1272 Mtc1(ZERO, rd);
1273 } else {
1274 LoadConst32(temp, low);
1275 Mtc1(temp, rd);
1276 }
1277 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001278 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001279 } else {
1280 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001281 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001282 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001283}
1284
1285void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1286 if (IsInt<16>(value)) {
1287 Addiu(rt, rs, value);
1288 } else {
1289 LoadConst32(temp, value);
1290 Addu(rt, rs, temp);
1291 }
1292}
1293
1294void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1295 MipsAssembler::Branch::Type short_type,
1296 MipsAssembler::Branch::Type long_type) {
1297 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1298}
1299
1300void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) {
1301 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1302 if (is_r6) {
1303 // R6
1304 if (is_call) {
1305 InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1306 } else if (condition_ == kUncond) {
1307 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1308 } else {
1309 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1310 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1311 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1312 } else {
1313 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1314 }
1315 }
1316 } else {
1317 // R2
1318 if (is_call) {
1319 InitShortOrLong(offset_size, kCall, kLongCall);
1320 } else if (condition_ == kUncond) {
1321 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1322 } else {
1323 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1324 }
1325 }
1326 old_type_ = type_;
1327}
1328
1329bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1330 switch (condition) {
1331 case kCondLT:
1332 case kCondGT:
1333 case kCondNE:
1334 case kCondLTU:
1335 return lhs == rhs;
1336 default:
1337 return false;
1338 }
1339}
1340
1341bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1342 switch (condition) {
1343 case kUncond:
1344 return true;
1345 case kCondGE:
1346 case kCondLE:
1347 case kCondEQ:
1348 case kCondGEU:
1349 return lhs == rhs;
1350 default:
1351 return false;
1352 }
1353}
1354
1355MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target)
1356 : old_location_(location),
1357 location_(location),
1358 target_(target),
1359 lhs_reg_(0),
1360 rhs_reg_(0),
1361 condition_(kUncond) {
1362 InitializeType(false, is_r6);
1363}
1364
1365MipsAssembler::Branch::Branch(bool is_r6,
1366 uint32_t location,
1367 uint32_t target,
1368 MipsAssembler::BranchCondition condition,
1369 Register lhs_reg,
1370 Register rhs_reg)
1371 : old_location_(location),
1372 location_(location),
1373 target_(target),
1374 lhs_reg_(lhs_reg),
1375 rhs_reg_(rhs_reg),
1376 condition_(condition) {
1377 CHECK_NE(condition, kUncond);
1378 switch (condition) {
1379 case kCondLT:
1380 case kCondGE:
1381 case kCondLE:
1382 case kCondGT:
1383 case kCondLTU:
1384 case kCondGEU:
1385 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1386 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1387 // We leave this up to the caller.
1388 CHECK(is_r6);
1389 FALLTHROUGH_INTENDED;
1390 case kCondEQ:
1391 case kCondNE:
1392 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1393 // To compare with 0, use dedicated kCond*Z conditions.
1394 CHECK_NE(lhs_reg, ZERO);
1395 CHECK_NE(rhs_reg, ZERO);
1396 break;
1397 case kCondLTZ:
1398 case kCondGEZ:
1399 case kCondLEZ:
1400 case kCondGTZ:
1401 case kCondEQZ:
1402 case kCondNEZ:
1403 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1404 CHECK_NE(lhs_reg, ZERO);
1405 CHECK_EQ(rhs_reg, ZERO);
1406 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001407 case kCondF:
1408 case kCondT:
1409 CHECK_EQ(rhs_reg, ZERO);
1410 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001411 case kUncond:
1412 UNREACHABLE();
1413 }
1414 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1415 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1416 // Branch condition is always true, make the branch unconditional.
1417 condition_ = kUncond;
1418 }
1419 InitializeType(false, is_r6);
1420}
1421
1422MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg)
1423 : old_location_(location),
1424 location_(location),
1425 target_(target),
1426 lhs_reg_(indirect_reg),
1427 rhs_reg_(0),
1428 condition_(kUncond) {
1429 CHECK_NE(indirect_reg, ZERO);
1430 CHECK_NE(indirect_reg, AT);
1431 InitializeType(true, is_r6);
1432}
1433
1434MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1435 MipsAssembler::BranchCondition cond) {
1436 switch (cond) {
1437 case kCondLT:
1438 return kCondGE;
1439 case kCondGE:
1440 return kCondLT;
1441 case kCondLE:
1442 return kCondGT;
1443 case kCondGT:
1444 return kCondLE;
1445 case kCondLTZ:
1446 return kCondGEZ;
1447 case kCondGEZ:
1448 return kCondLTZ;
1449 case kCondLEZ:
1450 return kCondGTZ;
1451 case kCondGTZ:
1452 return kCondLEZ;
1453 case kCondEQ:
1454 return kCondNE;
1455 case kCondNE:
1456 return kCondEQ;
1457 case kCondEQZ:
1458 return kCondNEZ;
1459 case kCondNEZ:
1460 return kCondEQZ;
1461 case kCondLTU:
1462 return kCondGEU;
1463 case kCondGEU:
1464 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001465 case kCondF:
1466 return kCondT;
1467 case kCondT:
1468 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001469 case kUncond:
1470 LOG(FATAL) << "Unexpected branch condition " << cond;
1471 }
1472 UNREACHABLE();
1473}
1474
1475MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
1476 return type_;
1477}
1478
1479MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
1480 return condition_;
1481}
1482
1483Register MipsAssembler::Branch::GetLeftRegister() const {
1484 return static_cast<Register>(lhs_reg_);
1485}
1486
1487Register MipsAssembler::Branch::GetRightRegister() const {
1488 return static_cast<Register>(rhs_reg_);
1489}
1490
1491uint32_t MipsAssembler::Branch::GetTarget() const {
1492 return target_;
1493}
1494
1495uint32_t MipsAssembler::Branch::GetLocation() const {
1496 return location_;
1497}
1498
1499uint32_t MipsAssembler::Branch::GetOldLocation() const {
1500 return old_location_;
1501}
1502
1503uint32_t MipsAssembler::Branch::GetLength() const {
1504 return branch_info_[type_].length;
1505}
1506
1507uint32_t MipsAssembler::Branch::GetOldLength() const {
1508 return branch_info_[old_type_].length;
1509}
1510
1511uint32_t MipsAssembler::Branch::GetSize() const {
1512 return GetLength() * sizeof(uint32_t);
1513}
1514
1515uint32_t MipsAssembler::Branch::GetOldSize() const {
1516 return GetOldLength() * sizeof(uint32_t);
1517}
1518
1519uint32_t MipsAssembler::Branch::GetEndLocation() const {
1520 return GetLocation() + GetSize();
1521}
1522
1523uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
1524 return GetOldLocation() + GetOldSize();
1525}
1526
1527bool MipsAssembler::Branch::IsLong() const {
1528 switch (type_) {
1529 // R2 short branches.
1530 case kUncondBranch:
1531 case kCondBranch:
1532 case kCall:
1533 // R6 short branches.
1534 case kR6UncondBranch:
1535 case kR6CondBranch:
1536 case kR6Call:
1537 return false;
1538 // R2 long branches.
1539 case kLongUncondBranch:
1540 case kLongCondBranch:
1541 case kLongCall:
1542 // R6 long branches.
1543 case kR6LongUncondBranch:
1544 case kR6LongCondBranch:
1545 case kR6LongCall:
1546 return true;
1547 }
1548 UNREACHABLE();
1549}
1550
1551bool MipsAssembler::Branch::IsResolved() const {
1552 return target_ != kUnresolved;
1553}
1554
1555MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
1556 OffsetBits offset_size =
1557 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1558 ? kOffset23
1559 : branch_info_[type_].offset_size;
1560 return offset_size;
1561}
1562
1563MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1564 uint32_t target) {
1565 // For unresolved targets assume the shortest encoding
1566 // (later it will be made longer if needed).
1567 if (target == kUnresolved)
1568 return kOffset16;
1569 int64_t distance = static_cast<int64_t>(target) - location;
1570 // To simplify calculations in composite branches consisting of multiple instructions
1571 // bump up the distance by a value larger than the max byte size of a composite branch.
1572 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1573 if (IsInt<kOffset16>(distance))
1574 return kOffset16;
1575 else if (IsInt<kOffset18>(distance))
1576 return kOffset18;
1577 else if (IsInt<kOffset21>(distance))
1578 return kOffset21;
1579 else if (IsInt<kOffset23>(distance))
1580 return kOffset23;
1581 else if (IsInt<kOffset28>(distance))
1582 return kOffset28;
1583 return kOffset32;
1584}
1585
1586void MipsAssembler::Branch::Resolve(uint32_t target) {
1587 target_ = target;
1588}
1589
1590void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1591 if (location_ > expand_location) {
1592 location_ += delta;
1593 }
1594 if (!IsResolved()) {
1595 return; // Don't know the target yet.
1596 }
1597 if (target_ > expand_location) {
1598 target_ += delta;
1599 }
1600}
1601
1602void MipsAssembler::Branch::PromoteToLong() {
1603 switch (type_) {
1604 // R2 short branches.
1605 case kUncondBranch:
1606 type_ = kLongUncondBranch;
1607 break;
1608 case kCondBranch:
1609 type_ = kLongCondBranch;
1610 break;
1611 case kCall:
1612 type_ = kLongCall;
1613 break;
1614 // R6 short branches.
1615 case kR6UncondBranch:
1616 type_ = kR6LongUncondBranch;
1617 break;
1618 case kR6CondBranch:
1619 type_ = kR6LongCondBranch;
1620 break;
1621 case kR6Call:
1622 type_ = kR6LongCall;
1623 break;
1624 default:
1625 // Note: 'type_' is already long.
1626 break;
1627 }
1628 CHECK(IsLong());
1629}
1630
1631uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1632 // If the branch is still unresolved or already long, nothing to do.
1633 if (IsLong() || !IsResolved()) {
1634 return 0;
1635 }
1636 // Promote the short branch to long if the offset size is too small
1637 // to hold the distance between location_ and target_.
1638 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1639 PromoteToLong();
1640 uint32_t old_size = GetOldSize();
1641 uint32_t new_size = GetSize();
1642 CHECK_GT(new_size, old_size);
1643 return new_size - old_size;
1644 }
1645 // The following logic is for debugging/testing purposes.
1646 // Promote some short branches to long when it's not really required.
1647 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1648 int64_t distance = static_cast<int64_t>(target_) - location_;
1649 distance = (distance >= 0) ? distance : -distance;
1650 if (distance >= max_short_distance) {
1651 PromoteToLong();
1652 uint32_t old_size = GetOldSize();
1653 uint32_t new_size = GetSize();
1654 CHECK_GT(new_size, old_size);
1655 return new_size - old_size;
1656 }
1657 }
1658 return 0;
1659}
1660
1661uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
1662 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1663}
1664
1665uint32_t MipsAssembler::Branch::GetOffset() const {
1666 CHECK(IsResolved());
1667 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1668 // Calculate the byte distance between instructions and also account for
1669 // different PC-relative origins.
1670 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1671 // Prepare the offset for encoding into the instruction(s).
1672 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1673 return offset;
1674}
1675
1676MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
1677 CHECK_LT(branch_id, branches_.size());
1678 return &branches_[branch_id];
1679}
1680
1681const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
1682 CHECK_LT(branch_id, branches_.size());
1683 return &branches_[branch_id];
1684}
1685
1686void MipsAssembler::Bind(MipsLabel* label) {
1687 CHECK(!label->IsBound());
1688 uint32_t bound_pc = buffer_.Size();
1689
1690 // Walk the list of branches referring to and preceding this label.
1691 // Store the previously unknown target addresses in them.
1692 while (label->IsLinked()) {
1693 uint32_t branch_id = label->Position();
1694 Branch* branch = GetBranch(branch_id);
1695 branch->Resolve(bound_pc);
1696
1697 uint32_t branch_location = branch->GetLocation();
1698 // Extract the location of the previous branch in the list (walking the list backwards;
1699 // the previous branch ID was stored in the space reserved for this branch).
1700 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
1701
1702 // On to the previous branch in the list...
1703 label->position_ = prev;
1704 }
1705
1706 // Now make the label object contain its own location (relative to the end of the preceding
1707 // branch, if any; it will be used by the branches referring to and following this label).
1708 label->prev_branch_id_plus_one_ = branches_.size();
1709 if (label->prev_branch_id_plus_one_) {
1710 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1711 const Branch* branch = GetBranch(branch_id);
1712 bound_pc -= branch->GetEndLocation();
1713 }
1714 label->BindTo(bound_pc);
1715}
1716
1717uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const {
1718 CHECK(label->IsBound());
1719 uint32_t target = label->Position();
1720 if (label->prev_branch_id_plus_one_) {
1721 // Get label location based on the branch preceding it.
1722 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1723 const Branch* branch = GetBranch(branch_id);
1724 target += branch->GetEndLocation();
1725 }
1726 return target;
1727}
1728
1729uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
1730 // We can reconstruct the adjustment by going through all the branches from the beginning
1731 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1732 // with increasing old_position, we can use the data from last AdjustedPosition() to
1733 // continue where we left off and the whole loop should be O(m+n) where m is the number
1734 // of positions to adjust and n is the number of branches.
1735 if (old_position < last_old_position_) {
1736 last_position_adjustment_ = 0;
1737 last_old_position_ = 0;
1738 last_branch_id_ = 0;
1739 }
1740 while (last_branch_id_ != branches_.size()) {
1741 const Branch* branch = GetBranch(last_branch_id_);
1742 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1743 break;
1744 }
1745 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1746 ++last_branch_id_;
1747 }
1748 last_old_position_ = old_position;
1749 return old_position + last_position_adjustment_;
1750}
1751
1752void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
1753 uint32_t length = branches_.back().GetLength();
1754 if (!label->IsBound()) {
1755 // Branch forward (to a following label), distance is unknown.
1756 // The first branch forward will contain 0, serving as the terminator of
1757 // the list of forward-reaching branches.
1758 Emit(label->position_);
1759 length--;
1760 // Now make the label object point to this branch
1761 // (this forms a linked list of branches preceding this label).
1762 uint32_t branch_id = branches_.size() - 1;
1763 label->LinkTo(branch_id);
1764 }
1765 // Reserve space for the branch.
1766 while (length--) {
1767 Nop();
1768 }
1769}
1770
1771void MipsAssembler::Buncond(MipsLabel* label) {
1772 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1773 branches_.emplace_back(IsR6(), buffer_.Size(), target);
1774 FinalizeLabeledBranch(label);
1775}
1776
1777void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
1778 // If lhs = rhs, this can be a NOP.
1779 if (Branch::IsNop(condition, lhs, rhs)) {
1780 return;
1781 }
1782 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1783 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
1784 FinalizeLabeledBranch(label);
1785}
1786
1787void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) {
1788 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1789 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg);
1790 FinalizeLabeledBranch(label);
1791}
1792
1793void MipsAssembler::PromoteBranches() {
1794 // Promote short branches to long as necessary.
1795 bool changed;
1796 do {
1797 changed = false;
1798 for (auto& branch : branches_) {
1799 CHECK(branch.IsResolved());
1800 uint32_t delta = branch.PromoteIfNeeded();
1801 // If this branch has been promoted and needs to expand in size,
1802 // relocate all branches by the expansion size.
1803 if (delta) {
1804 changed = true;
1805 uint32_t expand_location = branch.GetLocation();
1806 for (auto& branch2 : branches_) {
1807 branch2.Relocate(expand_location, delta);
1808 }
1809 }
1810 }
1811 } while (changed);
1812
1813 // Account for branch expansion by resizing the code buffer
1814 // and moving the code in it to its final location.
1815 size_t branch_count = branches_.size();
1816 if (branch_count > 0) {
1817 // Resize.
1818 Branch& last_branch = branches_[branch_count - 1];
1819 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1820 uint32_t old_size = buffer_.Size();
1821 buffer_.Resize(old_size + size_delta);
1822 // Move the code residing between branch placeholders.
1823 uint32_t end = old_size;
1824 for (size_t i = branch_count; i > 0; ) {
1825 Branch& branch = branches_[--i];
1826 uint32_t size = end - branch.GetOldEndLocation();
1827 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1828 end = branch.GetOldLocation();
1829 }
1830 }
1831}
1832
1833// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1834const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
1835 // R2 short branches.
1836 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
1837 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
1838 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall
1839 // R2 long branches.
1840 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1841 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
1842 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
1843 // R6 short branches.
1844 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
1845 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
1846 // Exception: kOffset23 for beqzc/bnezc.
1847 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call
1848 // R6 long branches.
1849 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
1850 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
1851 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
1852};
1853
1854// Note: make sure branch_info_[] and mitBranch() are kept synchronized.
1855void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
1856 CHECK_EQ(overwriting_, true);
1857 overwrite_location_ = branch->GetLocation();
1858 uint32_t offset = branch->GetOffset();
1859 BranchCondition condition = branch->GetCondition();
1860 Register lhs = branch->GetLeftRegister();
1861 Register rhs = branch->GetRightRegister();
1862 switch (branch->GetType()) {
1863 // R2 short branches.
1864 case Branch::kUncondBranch:
1865 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1866 B(offset);
1867 Nop(); // TODO: improve by filling the delay slot.
1868 break;
1869 case Branch::kCondBranch:
1870 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001871 EmitBcondR2(condition, lhs, rhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001872 Nop(); // TODO: improve by filling the delay slot.
1873 break;
1874 case Branch::kCall:
1875 Nal();
1876 Nop(); // TODO: is this NOP really needed here?
1877 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1878 Addiu(lhs, RA, offset);
1879 Jalr(lhs);
1880 Nop();
1881 break;
1882
1883 // R2 long branches.
1884 case Branch::kLongUncondBranch:
1885 // To get the value of the PC register we need to use the NAL instruction.
1886 // NAL clobbers the RA register. However, RA must be preserved if the
1887 // method is compiled without the entry/exit sequences that would take care
1888 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
1889 // So, we need to preserve RA in some temporary storage ourselves. The AT
1890 // register can't be used for this because we need it to load a constant
1891 // which will be added to the value that NAL stores in RA. And we can't
1892 // use T9 for this in the context of the JNI compiler, which uses it
1893 // as a scratch register (see InterproceduralScratchRegister()).
1894 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
1895 // we'd also need to use the ROTR instruction, which requires no less than
1896 // MIPSR2.
1897 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
1898 // (LO or HI) or even a floating-point register, but that doesn't seem
1899 // like a nice solution. We may want this to work on both R6 and pre-R6.
1900 // For now simply use the stack for RA. This should be OK since for the
1901 // vast majority of code a short PC-relative branch is sufficient.
1902 // TODO: can this be improved?
1903 Push(RA);
1904 Nal();
1905 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1906 Lui(AT, High16Bits(offset));
1907 Ori(AT, AT, Low16Bits(offset));
1908 Addu(AT, AT, RA);
1909 Lw(RA, SP, 0);
1910 Jr(AT);
1911 DecreaseFrameSize(kMipsWordSize);
1912 break;
1913 case Branch::kLongCondBranch:
1914 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
1915 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
1916 // number of instructions skipped:
1917 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001918 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001919 Push(RA);
1920 Nal();
1921 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1922 Lui(AT, High16Bits(offset));
1923 Ori(AT, AT, Low16Bits(offset));
1924 Addu(AT, AT, RA);
1925 Lw(RA, SP, 0);
1926 Jr(AT);
1927 DecreaseFrameSize(kMipsWordSize);
1928 break;
1929 case Branch::kLongCall:
1930 Nal();
1931 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1932 Lui(AT, High16Bits(offset));
1933 Ori(AT, AT, Low16Bits(offset));
1934 Addu(lhs, AT, RA);
1935 Jalr(lhs);
1936 Nop();
1937 break;
1938
1939 // R6 short branches.
1940 case Branch::kR6UncondBranch:
1941 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1942 Bc(offset);
1943 break;
1944 case Branch::kR6CondBranch:
1945 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001946 EmitBcondR6(condition, lhs, rhs, offset);
1947 Nop(); // TODO: improve by filling the forbidden/delay slot.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001948 break;
1949 case Branch::kR6Call:
1950 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1951 Addiupc(lhs, offset);
1952 Jialc(lhs, 0);
1953 break;
1954
1955 // R6 long branches.
1956 case Branch::kR6LongUncondBranch:
1957 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1958 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1959 Auipc(AT, High16Bits(offset));
1960 Jic(AT, Low16Bits(offset));
1961 break;
1962 case Branch::kR6LongCondBranch:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001963 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001964 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1965 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1966 Auipc(AT, High16Bits(offset));
1967 Jic(AT, Low16Bits(offset));
1968 break;
1969 case Branch::kR6LongCall:
1970 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
1971 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1972 Auipc(lhs, High16Bits(offset));
1973 Addiu(lhs, lhs, Low16Bits(offset));
1974 Jialc(lhs, 0);
1975 break;
1976 }
1977 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1978 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
1979}
1980
1981void MipsAssembler::B(MipsLabel* label) {
1982 Buncond(label);
1983}
1984
1985void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) {
1986 Call(label, indirect_reg);
1987}
1988
1989void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
1990 Bcond(label, kCondEQ, rs, rt);
1991}
1992
1993void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
1994 Bcond(label, kCondNE, rs, rt);
1995}
1996
1997void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
1998 Bcond(label, kCondEQZ, rt);
1999}
2000
2001void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
2002 Bcond(label, kCondNEZ, rt);
2003}
2004
2005void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
2006 Bcond(label, kCondLTZ, rt);
2007}
2008
2009void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
2010 Bcond(label, kCondGEZ, rt);
2011}
2012
2013void MipsAssembler::Blez(Register rt, MipsLabel* label) {
2014 Bcond(label, kCondLEZ, rt);
2015}
2016
2017void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
2018 Bcond(label, kCondGTZ, rt);
2019}
2020
2021void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
2022 if (IsR6()) {
2023 Bcond(label, kCondLT, rs, rt);
2024 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
2025 // Synthesize the instruction (not available on R2).
2026 Slt(AT, rs, rt);
2027 Bnez(AT, label);
2028 }
2029}
2030
2031void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
2032 if (IsR6()) {
2033 Bcond(label, kCondGE, rs, rt);
2034 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
2035 B(label);
2036 } else {
2037 // Synthesize the instruction (not available on R2).
2038 Slt(AT, rs, rt);
2039 Beqz(AT, label);
2040 }
2041}
2042
2043void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
2044 if (IsR6()) {
2045 Bcond(label, kCondLTU, rs, rt);
2046 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
2047 // Synthesize the instruction (not available on R2).
2048 Sltu(AT, rs, rt);
2049 Bnez(AT, label);
2050 }
2051}
2052
2053void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
2054 if (IsR6()) {
2055 Bcond(label, kCondGEU, rs, rt);
2056 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
2057 B(label);
2058 } else {
2059 // Synthesize the instruction (not available on R2).
2060 Sltu(AT, rs, rt);
2061 Beqz(AT, label);
jeffhao7fbee072012-08-24 17:56:54 -07002062 }
2063}
2064
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002065void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
2066 CHECK(IsUint<3>(cc)) << cc;
2067 Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
2068}
2069
2070void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
2071 CHECK(IsUint<3>(cc)) << cc;
2072 Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
2073}
2074
2075void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
2076 Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
2077}
2078
2079void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
2080 Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
2081}
2082
jeffhao7fbee072012-08-24 17:56:54 -07002083void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
2084 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002085 // IsInt<16> must be passed a signed value.
2086 if (!IsInt<16>(offset) ||
2087 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2088 LoadConst32(AT, offset);
2089 Addu(AT, AT, base);
2090 base = AT;
2091 offset = 0;
2092 }
2093
jeffhao7fbee072012-08-24 17:56:54 -07002094 switch (type) {
2095 case kLoadSignedByte:
2096 Lb(reg, base, offset);
2097 break;
2098 case kLoadUnsignedByte:
2099 Lbu(reg, base, offset);
2100 break;
2101 case kLoadSignedHalfword:
2102 Lh(reg, base, offset);
2103 break;
2104 case kLoadUnsignedHalfword:
2105 Lhu(reg, base, offset);
2106 break;
2107 case kLoadWord:
2108 Lw(reg, base, offset);
2109 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002110 case kLoadDoubleword:
2111 if (reg == base) {
2112 // This will clobber the base when loading the lower register. Since we have to load the
2113 // higher register as well, this will fail. Solution: reverse the order.
2114 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2115 Lw(reg, base, offset);
2116 } else {
2117 Lw(reg, base, offset);
2118 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
2119 }
jeffhao7fbee072012-08-24 17:56:54 -07002120 break;
2121 default:
2122 LOG(FATAL) << "UNREACHABLE";
2123 }
2124}
2125
2126void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002127 if (!IsInt<16>(offset)) {
2128 LoadConst32(AT, offset);
2129 Addu(AT, AT, base);
2130 base = AT;
2131 offset = 0;
2132 }
2133
jeffhao7fbee072012-08-24 17:56:54 -07002134 Lwc1(reg, base, offset);
2135}
2136
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002137void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
2138 // IsInt<16> must be passed a signed value.
2139 if (!IsInt<16>(offset) ||
2140 (!IsAligned<kMipsDoublewordSize>(offset) &&
2141 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2142 LoadConst32(AT, offset);
2143 Addu(AT, AT, base);
2144 base = AT;
2145 offset = 0;
2146 }
2147
2148 if (offset & 0x7) {
2149 if (Is32BitFPU()) {
2150 Lwc1(reg, base, offset);
2151 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2152 } else {
2153 // 64-bit FPU.
2154 Lwc1(reg, base, offset);
2155 Lw(T8, base, offset + kMipsWordSize);
2156 Mthc1(T8, reg);
2157 }
2158 } else {
2159 Ldc1(reg, base, offset);
2160 }
2161}
2162
2163void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
2164 size_t size) {
2165 MipsManagedRegister dst = m_dst.AsMips();
2166 if (dst.IsNoRegister()) {
2167 CHECK_EQ(0u, size) << dst;
2168 } else if (dst.IsCoreRegister()) {
2169 CHECK_EQ(kMipsWordSize, size) << dst;
2170 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
2171 } else if (dst.IsRegisterPair()) {
2172 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2173 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
2174 } else if (dst.IsFRegister()) {
2175 if (size == kMipsWordSize) {
2176 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
2177 } else {
2178 CHECK_EQ(kMipsDoublewordSize, size) << dst;
2179 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
2180 }
2181 }
jeffhao7fbee072012-08-24 17:56:54 -07002182}
2183
2184void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
2185 int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002186 // IsInt<16> must be passed a signed value.
2187 if (!IsInt<16>(offset) ||
2188 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2189 LoadConst32(AT, offset);
2190 Addu(AT, AT, base);
2191 base = AT;
2192 offset = 0;
2193 }
2194
jeffhao7fbee072012-08-24 17:56:54 -07002195 switch (type) {
2196 case kStoreByte:
2197 Sb(reg, base, offset);
2198 break;
2199 case kStoreHalfword:
2200 Sh(reg, base, offset);
2201 break;
2202 case kStoreWord:
2203 Sw(reg, base, offset);
2204 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002205 case kStoreDoubleword:
2206 CHECK_NE(reg, base);
2207 CHECK_NE(static_cast<Register>(reg + 1), base);
2208 Sw(reg, base, offset);
2209 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002210 break;
2211 default:
2212 LOG(FATAL) << "UNREACHABLE";
2213 }
2214}
2215
Goran Jakovljevicff734982015-08-24 12:58:55 +00002216void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002217 if (!IsInt<16>(offset)) {
2218 LoadConst32(AT, offset);
2219 Addu(AT, AT, base);
2220 base = AT;
2221 offset = 0;
2222 }
2223
jeffhao7fbee072012-08-24 17:56:54 -07002224 Swc1(reg, base, offset);
2225}
2226
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002227void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
2228 // IsInt<16> must be passed a signed value.
2229 if (!IsInt<16>(offset) ||
2230 (!IsAligned<kMipsDoublewordSize>(offset) &&
2231 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
2232 LoadConst32(AT, offset);
2233 Addu(AT, AT, base);
2234 base = AT;
2235 offset = 0;
2236 }
2237
2238 if (offset & 0x7) {
2239 if (Is32BitFPU()) {
2240 Swc1(reg, base, offset);
2241 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
2242 } else {
2243 // 64-bit FPU.
2244 Mfhc1(T8, reg);
2245 Swc1(reg, base, offset);
2246 Sw(T8, base, offset + kMipsWordSize);
2247 }
2248 } else {
2249 Sdc1(reg, base, offset);
2250 }
jeffhao7fbee072012-08-24 17:56:54 -07002251}
2252
David Srbeckydd973932015-04-07 20:29:48 +01002253static dwarf::Reg DWARFReg(Register reg) {
2254 return dwarf::Reg::MipsCore(static_cast<int>(reg));
2255}
2256
Ian Rogers790a6b72014-04-01 10:36:00 -07002257constexpr size_t kFramePointerSize = 4;
2258
jeffhao7fbee072012-08-24 17:56:54 -07002259void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
2260 const std::vector<ManagedRegister>& callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07002261 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07002262 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002263 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07002264
2265 // Increase frame to required size.
2266 IncreaseFrameSize(frame_size);
2267
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002268 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002269 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002270 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002271 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002272 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07002273 stack_offset -= kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002274 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2275 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002276 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07002277 }
2278
2279 // Write out Method*.
2280 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
2281
2282 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00002283 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002284 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00002285 MipsManagedRegister reg = entry_spills.at(i).AsMips();
2286 if (reg.IsNoRegister()) {
2287 ManagedRegisterSpill spill = entry_spills.at(i);
2288 offset += spill.getSize();
2289 } else if (reg.IsCoreRegister()) {
2290 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002291 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002292 } else if (reg.IsFRegister()) {
2293 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002294 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002295 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002296 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
2297 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00002298 }
jeffhao7fbee072012-08-24 17:56:54 -07002299 }
2300}
2301
2302void MipsAssembler::RemoveFrame(size_t frame_size,
2303 const std::vector<ManagedRegister>& callee_save_regs) {
2304 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002305 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002306 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07002307
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002308 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07002309 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002310 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
2311 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
2312 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002313 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07002314 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07002315 }
2316 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002317 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07002318
2319 // Decrease frame to required size.
2320 DecreaseFrameSize(frame_size);
jeffhao07030602012-09-26 14:33:14 -07002321
2322 // Then jump to the return address.
2323 Jr(RA);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002324 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002325
2326 // The CFI should be restored for any code that follows the exit block.
2327 cfi_.RestoreState();
2328 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07002329}
2330
2331void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002332 CHECK_ALIGNED(adjust, kFramePointerSize);
2333 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002334 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002335 if (overwriting_) {
2336 cfi_.OverrideDelayedPC(overwrite_location_);
2337 }
jeffhao7fbee072012-08-24 17:56:54 -07002338}
2339
2340void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002341 CHECK_ALIGNED(adjust, kFramePointerSize);
2342 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01002343 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01002344 if (overwriting_) {
2345 cfi_.OverrideDelayedPC(overwrite_location_);
2346 }
jeffhao7fbee072012-08-24 17:56:54 -07002347}
2348
2349void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2350 MipsManagedRegister src = msrc.AsMips();
2351 if (src.IsNoRegister()) {
2352 CHECK_EQ(0u, size);
2353 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002354 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002355 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2356 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002357 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07002358 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
2359 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002360 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002361 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002362 if (size == kMipsWordSize) {
2363 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
2364 } else {
2365 CHECK_EQ(kMipsDoublewordSize, size);
2366 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
2367 }
jeffhao7fbee072012-08-24 17:56:54 -07002368 }
2369}
2370
2371void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2372 MipsManagedRegister src = msrc.AsMips();
2373 CHECK(src.IsCoreRegister());
2374 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2375}
2376
2377void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2378 MipsManagedRegister src = msrc.AsMips();
2379 CHECK(src.IsCoreRegister());
2380 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2381}
2382
2383void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2384 ManagedRegister mscratch) {
2385 MipsManagedRegister scratch = mscratch.AsMips();
2386 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002387 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07002388 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2389}
2390
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002391void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm,
jeffhao7fbee072012-08-24 17:56:54 -07002392 ManagedRegister mscratch) {
2393 MipsManagedRegister scratch = mscratch.AsMips();
2394 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002395 // Is this function even referenced anywhere else in the code?
2396 LoadConst32(scratch.AsCoreRegister(), imm);
2397 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
2398}
2399
2400void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2401 FrameOffset fr_offs,
2402 ManagedRegister mscratch) {
2403 MipsManagedRegister scratch = mscratch.AsMips();
2404 CHECK(scratch.IsCoreRegister()) << scratch;
2405 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002406 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2407 S1, thr_offs.Int32Value());
2408}
2409
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002410void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002411 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
2412}
2413
2414void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2415 FrameOffset in_off, ManagedRegister mscratch) {
2416 MipsManagedRegister src = msrc.AsMips();
2417 MipsManagedRegister scratch = mscratch.AsMips();
2418 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
2419 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002420 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002421}
2422
2423void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2424 return EmitLoad(mdest, SP, src.Int32Value(), size);
2425}
2426
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002427void MipsAssembler::LoadFromThread32(ManagedRegister mdest,
2428 ThreadOffset<kMipsWordSize> src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002429 return EmitLoad(mdest, S1, src.Int32Value(), size);
2430}
2431
2432void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2433 MipsManagedRegister dest = mdest.AsMips();
2434 CHECK(dest.IsCoreRegister());
2435 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
2436}
2437
Mathieu Chartiere401d142015-04-22 13:56:20 -07002438void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002439 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07002440 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002441 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002442 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2443 base.AsMips().AsCoreRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002444 if (kPoisonHeapReferences && unpoison_reference) {
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08002445 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
2446 }
jeffhao7fbee072012-08-24 17:56:54 -07002447}
2448
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002449void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002450 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002451 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07002452 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
2453 base.AsMips().AsCoreRegister(), offs.Int32Value());
2454}
2455
Ian Rogersdd7624d2014-03-14 17:43:00 -07002456void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002457 ThreadOffset<kMipsWordSize> offs) {
jeffhao7fbee072012-08-24 17:56:54 -07002458 MipsManagedRegister dest = mdest.AsMips();
2459 CHECK(dest.IsCoreRegister());
2460 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
2461}
2462
2463void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2464 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
2465}
2466
2467void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
2468 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
2469}
2470
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002471void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002472 MipsManagedRegister dest = mdest.AsMips();
2473 MipsManagedRegister src = msrc.AsMips();
2474 if (!dest.Equals(src)) {
2475 if (dest.IsCoreRegister()) {
2476 CHECK(src.IsCoreRegister()) << src;
2477 Move(dest.AsCoreRegister(), src.AsCoreRegister());
2478 } else if (dest.IsFRegister()) {
2479 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002480 if (size == kMipsWordSize) {
2481 MovS(dest.AsFRegister(), src.AsFRegister());
2482 } else {
2483 CHECK_EQ(kMipsDoublewordSize, size);
2484 MovD(dest.AsFRegister(), src.AsFRegister());
2485 }
jeffhao7fbee072012-08-24 17:56:54 -07002486 } else if (dest.IsDRegister()) {
2487 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002488 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07002489 } else {
2490 CHECK(dest.IsRegisterPair()) << dest;
2491 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002492 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07002493 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
2494 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2495 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2496 } else {
2497 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
2498 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
2499 }
2500 }
2501 }
2502}
2503
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002504void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002505 MipsManagedRegister scratch = mscratch.AsMips();
2506 CHECK(scratch.IsCoreRegister()) << scratch;
2507 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2508 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
2509}
2510
Ian Rogersdd7624d2014-03-14 17:43:00 -07002511void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002512 ThreadOffset<kMipsWordSize> thr_offs,
2513 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002514 MipsManagedRegister scratch = mscratch.AsMips();
2515 CHECK(scratch.IsCoreRegister()) << scratch;
2516 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2517 S1, thr_offs.Int32Value());
2518 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2519 SP, fr_offs.Int32Value());
2520}
2521
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002522void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
2523 FrameOffset fr_offs,
2524 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07002525 MipsManagedRegister scratch = mscratch.AsMips();
2526 CHECK(scratch.IsCoreRegister()) << scratch;
2527 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2528 SP, fr_offs.Int32Value());
2529 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
2530 S1, thr_offs.Int32Value());
2531}
2532
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002533void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07002534 MipsManagedRegister scratch = mscratch.AsMips();
2535 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002536 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
2537 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002538 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2539 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002540 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07002541 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
2542 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002543 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
2544 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002545 }
2546}
2547
2548void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
2549 ManagedRegister mscratch, size_t size) {
2550 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002551 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002552 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
2553 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
2554}
2555
2556void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
2557 ManagedRegister mscratch, size_t size) {
2558 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002559 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002560 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
2561 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2562}
2563
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002564void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2565 FrameOffset src_base ATTRIBUTE_UNUSED,
2566 Offset src_offset ATTRIBUTE_UNUSED,
2567 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2568 size_t size ATTRIBUTE_UNUSED) {
2569 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002570}
2571
2572void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
2573 ManagedRegister src, Offset src_offset,
2574 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002575 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07002576 Register scratch = mscratch.AsMips().AsCoreRegister();
2577 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
2578 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
2579}
2580
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002581void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2582 Offset dest_offset ATTRIBUTE_UNUSED,
2583 FrameOffset src ATTRIBUTE_UNUSED,
2584 Offset src_offset ATTRIBUTE_UNUSED,
2585 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2586 size_t size ATTRIBUTE_UNUSED) {
2587 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002588}
2589
2590void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002591 // TODO: sync?
2592 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002593}
2594
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002595void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002596 FrameOffset handle_scope_offset,
2597 ManagedRegister min_reg,
2598 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002599 MipsManagedRegister out_reg = mout_reg.AsMips();
2600 MipsManagedRegister in_reg = min_reg.AsMips();
2601 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
2602 CHECK(out_reg.IsCoreRegister()) << out_reg;
2603 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002604 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002605 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2606 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002607 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07002608 if (in_reg.IsNoRegister()) {
2609 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002610 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002611 in_reg = out_reg;
2612 }
2613 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002614 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002615 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002616 Beqz(in_reg.AsCoreRegister(), &null_arg);
2617 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2618 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002619 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002620 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002621 }
2622}
2623
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002624void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002625 FrameOffset handle_scope_offset,
2626 ManagedRegister mscratch,
2627 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07002628 MipsManagedRegister scratch = mscratch.AsMips();
2629 CHECK(scratch.IsCoreRegister()) << scratch;
2630 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002631 MipsLabel null_arg;
2632 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002633 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2634 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002635 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
2636 Beqz(scratch.AsCoreRegister(), &null_arg);
2637 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
2638 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002639 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002640 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002641 }
2642 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
2643}
2644
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07002645// Given a handle scope entry, load the associated reference.
2646void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002647 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07002648 MipsManagedRegister out_reg = mout_reg.AsMips();
2649 MipsManagedRegister in_reg = min_reg.AsMips();
2650 CHECK(out_reg.IsCoreRegister()) << out_reg;
2651 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002652 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07002653 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002654 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07002655 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002656 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002657 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
2658 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002659 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07002660}
2661
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002662void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2663 bool could_be_null ATTRIBUTE_UNUSED) {
2664 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002665}
2666
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002667void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2668 bool could_be_null ATTRIBUTE_UNUSED) {
2669 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07002670}
2671
2672void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2673 MipsManagedRegister base = mbase.AsMips();
2674 MipsManagedRegister scratch = mscratch.AsMips();
2675 CHECK(base.IsCoreRegister()) << base;
2676 CHECK(scratch.IsCoreRegister()) << scratch;
2677 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2678 base.AsCoreRegister(), offset.Int32Value());
2679 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002680 Nop();
2681 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002682}
2683
2684void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2685 MipsManagedRegister scratch = mscratch.AsMips();
2686 CHECK(scratch.IsCoreRegister()) << scratch;
2687 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002688 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07002689 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
2690 scratch.AsCoreRegister(), offset.Int32Value());
2691 Jalr(scratch.AsCoreRegister());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002692 Nop();
2693 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07002694}
2695
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002696void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED,
2697 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07002698 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07002699}
2700
2701void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
2702 Move(tr.AsMips().AsCoreRegister(), S1);
2703}
2704
2705void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002706 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07002707 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
2708}
2709
jeffhao7fbee072012-08-24 17:56:54 -07002710void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2711 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002712 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07002713 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002714 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value());
2715 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry());
2716 // as the NAL instruction (occurring in long R2 branches) may become deprecated.
2717 // For now use common for R2 and R6 instructions as this code must execute on both.
2718 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07002719}
2720
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002721void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
2722 Bind(exception->Entry());
2723 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2724 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07002725 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002726 // Pass exception object as argument.
2727 // Don't care about preserving A0 as this call won't return.
2728 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2729 Move(A0, exception->scratch_.AsCoreRegister());
2730 // Set up call to Thread::Current()->pDeliverException.
2731 LoadFromOffset(kLoadWord, T9, S1,
2732 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value());
2733 Jr(T9);
2734 Nop();
2735
2736 // Call never returns.
2737 Break();
jeffhao7fbee072012-08-24 17:56:54 -07002738}
2739
2740} // namespace mips
2741} // namespace art