blob: a35b71fe315935f21ca80423a9518d6800e61174 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 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_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
38 PromoteBranches();
39}
40
41void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
42 EmitBranches();
43 Assembler::FinalizeInstructions(region);
44 PatchCFI();
45}
46
47void Mips64Assembler::PatchCFI() {
48 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
49 return;
50 }
51
52 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
53 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
54 const std::vector<uint8_t>& old_stream = data.first;
55 const std::vector<DelayedAdvancePC>& advances = data.second;
56
57 // Refill our data buffer with patched opcodes.
58 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
59 size_t stream_pos = 0;
60 for (const DelayedAdvancePC& advance : advances) {
61 DCHECK_GE(advance.stream_pos, stream_pos);
62 // Copy old data up to the point where advance was issued.
63 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
64 stream_pos = advance.stream_pos;
65 // Insert the advance command with its final offset.
66 size_t final_pc = GetAdjustedPosition(advance.pc);
67 cfi().AdvancePC(final_pc);
68 }
69 // Copy the final segment if any.
70 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
71}
72
73void Mips64Assembler::EmitBranches() {
74 CHECK(!overwriting_);
75 // Switch from appending instructions at the end of the buffer to overwriting
76 // existing instructions (branch placeholders) in the buffer.
77 overwriting_ = true;
78 for (auto& branch : branches_) {
79 EmitBranch(&branch);
80 }
81 overwriting_ = false;
82}
83
Alexey Frunze4dda3372015-06-01 18:31:49 -070084void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070085 if (overwriting_) {
86 // Branches to labels are emitted into their placeholders here.
87 buffer_.Store<uint32_t>(overwrite_location_, value);
88 overwrite_location_ += sizeof(uint32_t);
89 } else {
90 // Other instructions are simply appended at the end here.
91 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
92 buffer_.Emit<uint32_t>(value);
93 }
Andreas Gampe57b34292015-01-14 15:45:59 -080094}
95
96void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
97 int shamt, int funct) {
98 CHECK_NE(rs, kNoGpuRegister);
99 CHECK_NE(rt, kNoGpuRegister);
100 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700101 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
102 static_cast<uint32_t>(rs) << kRsShift |
103 static_cast<uint32_t>(rt) << kRtShift |
104 static_cast<uint32_t>(rd) << kRdShift |
105 shamt << kShamtShift |
106 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800107 Emit(encoding);
108}
109
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700110void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
111 int shamt, int funct) {
112 CHECK_NE(rs, kNoGpuRegister);
113 CHECK_NE(rd, kNoGpuRegister);
114 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
115 static_cast<uint32_t>(rs) << kRsShift |
116 static_cast<uint32_t>(ZERO) << kRtShift |
117 static_cast<uint32_t>(rd) << kRdShift |
118 shamt << kShamtShift |
119 funct;
120 Emit(encoding);
121}
122
123void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
124 int shamt, int funct) {
125 CHECK_NE(rt, kNoGpuRegister);
126 CHECK_NE(rd, kNoGpuRegister);
127 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
128 static_cast<uint32_t>(ZERO) << kRsShift |
129 static_cast<uint32_t>(rt) << kRtShift |
130 static_cast<uint32_t>(rd) << kRdShift |
131 shamt << kShamtShift |
132 funct;
133 Emit(encoding);
134}
135
Andreas Gampe57b34292015-01-14 15:45:59 -0800136void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
137 CHECK_NE(rs, kNoGpuRegister);
138 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700139 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
140 static_cast<uint32_t>(rs) << kRsShift |
141 static_cast<uint32_t>(rt) << kRtShift |
142 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800143 Emit(encoding);
144}
145
Alexey Frunze4dda3372015-06-01 18:31:49 -0700146void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
147 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700148 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700149 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
150 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700151 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700152 Emit(encoding);
153}
154
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700155void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
156 CHECK(IsUint<26>(imm26)) << imm26;
157 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800158 Emit(encoding);
159}
160
161void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700162 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800163 CHECK_NE(ft, kNoFpuRegister);
164 CHECK_NE(fs, kNoFpuRegister);
165 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700166 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
167 fmt << kFmtShift |
168 static_cast<uint32_t>(ft) << kFtShift |
169 static_cast<uint32_t>(fs) << kFsShift |
170 static_cast<uint32_t>(fd) << kFdShift |
171 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800172 Emit(encoding);
173}
174
Alexey Frunze4dda3372015-06-01 18:31:49 -0700175void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
176 CHECK_NE(ft, kNoFpuRegister);
177 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
178 fmt << kFmtShift |
179 static_cast<uint32_t>(ft) << kFtShift |
180 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800181 Emit(encoding);
182}
183
Andreas Gampe57b34292015-01-14 15:45:59 -0800184void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
185 EmitR(0, rs, rt, rd, 0, 0x21);
186}
187
188void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
189 EmitI(0x9, rs, rt, imm16);
190}
191
Alexey Frunze4dda3372015-06-01 18:31:49 -0700192void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
193 EmitR(0, rs, rt, rd, 0, 0x2d);
194}
195
Andreas Gampe57b34292015-01-14 15:45:59 -0800196void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
197 EmitI(0x19, rs, rt, imm16);
198}
199
Andreas Gampe57b34292015-01-14 15:45:59 -0800200void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
201 EmitR(0, rs, rt, rd, 0, 0x23);
202}
203
Alexey Frunze4dda3372015-06-01 18:31:49 -0700204void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
205 EmitR(0, rs, rt, rd, 0, 0x2f);
206}
207
Alexey Frunze4dda3372015-06-01 18:31:49 -0700208void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
209 EmitR(0, rs, rt, rd, 2, 0x18);
210}
211
Alexey Frunzec857c742015-09-23 15:12:39 -0700212void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
213 EmitR(0, rs, rt, rd, 3, 0x18);
214}
215
Alexey Frunze4dda3372015-06-01 18:31:49 -0700216void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
217 EmitR(0, rs, rt, rd, 2, 0x1a);
218}
219
220void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
221 EmitR(0, rs, rt, rd, 3, 0x1a);
222}
223
224void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
225 EmitR(0, rs, rt, rd, 2, 0x1b);
226}
227
228void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
229 EmitR(0, rs, rt, rd, 3, 0x1b);
230}
231
232void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
233 EmitR(0, rs, rt, rd, 2, 0x1c);
234}
235
Alexey Frunzec857c742015-09-23 15:12:39 -0700236void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
237 EmitR(0, rs, rt, rd, 3, 0x1c);
238}
239
Alexey Frunze4dda3372015-06-01 18:31:49 -0700240void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
241 EmitR(0, rs, rt, rd, 2, 0x1e);
242}
243
244void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
245 EmitR(0, rs, rt, rd, 3, 0x1e);
246}
247
248void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
249 EmitR(0, rs, rt, rd, 2, 0x1f);
250}
251
252void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
253 EmitR(0, rs, rt, rd, 3, 0x1f);
254}
255
Andreas Gampe57b34292015-01-14 15:45:59 -0800256void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
257 EmitR(0, rs, rt, rd, 0, 0x24);
258}
259
260void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
261 EmitI(0xc, rs, rt, imm16);
262}
263
264void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
265 EmitR(0, rs, rt, rd, 0, 0x25);
266}
267
268void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
269 EmitI(0xd, rs, rt, imm16);
270}
271
272void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
273 EmitR(0, rs, rt, rd, 0, 0x26);
274}
275
276void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
277 EmitI(0xe, rs, rt, imm16);
278}
279
280void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
281 EmitR(0, rs, rt, rd, 0, 0x27);
282}
283
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700284void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
285 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
286}
287
288void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
289 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
290}
291
Alexey Frunze4dda3372015-06-01 18:31:49 -0700292void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
293 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800294}
295
Alexey Frunze4dda3372015-06-01 18:31:49 -0700296void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
297 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800298}
299
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700300void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
301 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
302}
303
304void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
305 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
306}
307
Lazar Trsicd9672662015-09-03 17:33:01 +0200308void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
309 CHECK(IsUint<5>(pos)) << pos;
310 CHECK(IsUint<5>(size - 1)) << size;
311 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
312}
313
314void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
315 CHECK(IsUint<5>(pos - 32)) << pos;
316 CHECK(IsUint<5>(size - 1)) << size;
317 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
318 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800319}
320
Chris Larsene3660592016-11-09 11:13:42 -0800321void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
322 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
323 int sa = saPlusOne - 1;
324 EmitR(0x0, rs, rt, rd, sa, 0x05);
325}
326
327void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
328 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
329 int sa = saPlusOne - 1;
330 EmitR(0x0, rs, rt, rd, sa, 0x15);
331}
332
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700333void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
334 EmitRtd(0x1f, rt, rd, 2, 0x20);
335}
336
337void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200338 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700339 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
340}
341
342void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200343 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700344 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
345}
346
347void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200348 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700349 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
350}
351
352void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200353 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700354 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
355}
356
Alexey Frunze4dda3372015-06-01 18:31:49 -0700357void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
358 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
359}
360
361void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
362 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
363}
364
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700365void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
366 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
367}
368
Alexey Frunze4dda3372015-06-01 18:31:49 -0700369void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
370 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
371}
372
373void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800374 EmitR(0, rs, rt, rd, 0, 0x04);
375}
376
Chris Larsen9aebff22015-09-22 17:54:15 -0700377void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
378 EmitR(0, rs, rt, rd, 1, 0x06);
379}
380
Alexey Frunze4dda3372015-06-01 18:31:49 -0700381void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800382 EmitR(0, rs, rt, rd, 0, 0x06);
383}
384
Alexey Frunze4dda3372015-06-01 18:31:49 -0700385void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800386 EmitR(0, rs, rt, rd, 0, 0x07);
387}
388
Alexey Frunze4dda3372015-06-01 18:31:49 -0700389void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
390 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
391}
392
393void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
394 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
395}
396
Chris Larsen9aebff22015-09-22 17:54:15 -0700397void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
398 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
399}
400
Alexey Frunze4dda3372015-06-01 18:31:49 -0700401void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
402 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
403}
404
405void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
406 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
407}
408
409void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
410 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
411}
412
Chris Larsen9aebff22015-09-22 17:54:15 -0700413void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
414 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
415}
416
Alexey Frunze4dda3372015-06-01 18:31:49 -0700417void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
418 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
419}
420
421void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
422 EmitR(0, rs, rt, rd, 0, 0x14);
423}
424
425void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
426 EmitR(0, rs, rt, rd, 0, 0x16);
427}
428
Chris Larsen9aebff22015-09-22 17:54:15 -0700429void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
430 EmitR(0, rs, rt, rd, 1, 0x16);
431}
432
Alexey Frunze4dda3372015-06-01 18:31:49 -0700433void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
434 EmitR(0, rs, rt, rd, 0, 0x17);
435}
436
Andreas Gampe57b34292015-01-14 15:45:59 -0800437void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
438 EmitI(0x20, rs, rt, imm16);
439}
440
441void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
442 EmitI(0x21, rs, rt, imm16);
443}
444
445void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
446 EmitI(0x23, rs, rt, imm16);
447}
448
449void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
450 EmitI(0x37, rs, rt, imm16);
451}
452
453void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
454 EmitI(0x24, rs, rt, imm16);
455}
456
457void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
458 EmitI(0x25, rs, rt, imm16);
459}
460
Douglas Leungd90957f2015-04-30 19:22:49 -0700461void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
462 EmitI(0x27, rs, rt, imm16);
463}
464
Andreas Gampe57b34292015-01-14 15:45:59 -0800465void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
466 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
467}
468
Alexey Frunze4dda3372015-06-01 18:31:49 -0700469void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
470 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
471}
472
473void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
474 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
475}
476
477void Mips64Assembler::Sync(uint32_t stype) {
478 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
479 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
480}
481
Andreas Gampe57b34292015-01-14 15:45:59 -0800482void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
483 EmitI(0x28, rs, rt, imm16);
484}
485
486void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
487 EmitI(0x29, rs, rt, imm16);
488}
489
490void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
491 EmitI(0x2b, rs, rt, imm16);
492}
493
494void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
495 EmitI(0x3f, rs, rt, imm16);
496}
497
498void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
499 EmitR(0, rs, rt, rd, 0, 0x2a);
500}
501
502void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
503 EmitR(0, rs, rt, rd, 0, 0x2b);
504}
505
506void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
507 EmitI(0xa, rs, rt, imm16);
508}
509
510void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
511 EmitI(0xb, rs, rt, imm16);
512}
513
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700514void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
515 EmitR(0, rs, rt, rd, 0, 0x35);
516}
517
518void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
519 EmitR(0, rs, rt, rd, 0, 0x37);
520}
521
522void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
523 EmitRsd(0, rs, rd, 0x01, 0x10);
524}
525
526void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
527 EmitRsd(0, rs, rd, 0x01, 0x11);
528}
529
530void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
531 EmitRsd(0, rs, rd, 0x01, 0x12);
532}
533
534void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
535 EmitRsd(0, rs, rd, 0x01, 0x13);
536}
537
Alexey Frunze4dda3372015-06-01 18:31:49 -0700538void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
539 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800540}
541
542void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700543 Jalr(RA, rs);
544}
545
546void Mips64Assembler::Jr(GpuRegister rs) {
547 Jalr(ZERO, rs);
548}
549
550void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
551 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
552}
553
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700554void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
555 CHECK(IsUint<19>(imm19)) << imm19;
556 EmitI21(0x3B, rs, imm19);
557}
558
559void Mips64Assembler::Bc(uint32_t imm26) {
560 EmitI26(0x32, imm26);
561}
562
Alexey Frunze4dda3372015-06-01 18:31:49 -0700563void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
564 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
565}
566
567void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
568 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
569}
570
571void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
572 CHECK_NE(rs, ZERO);
573 CHECK_NE(rt, ZERO);
574 CHECK_NE(rs, rt);
575 EmitI(0x17, rs, rt, imm16);
576}
577
578void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
579 CHECK_NE(rt, ZERO);
580 EmitI(0x17, rt, rt, imm16);
581}
582
583void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
584 CHECK_NE(rt, ZERO);
585 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
586}
587
588void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
589 CHECK_NE(rs, ZERO);
590 CHECK_NE(rt, ZERO);
591 CHECK_NE(rs, rt);
592 EmitI(0x16, rs, rt, imm16);
593}
594
595void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
596 CHECK_NE(rt, ZERO);
597 EmitI(0x16, rt, rt, imm16);
598}
599
600void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
601 CHECK_NE(rt, ZERO);
602 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
603}
604
605void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
606 CHECK_NE(rs, ZERO);
607 CHECK_NE(rt, ZERO);
608 CHECK_NE(rs, rt);
609 EmitI(0x7, rs, rt, imm16);
610}
611
612void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
613 CHECK_NE(rs, ZERO);
614 CHECK_NE(rt, ZERO);
615 CHECK_NE(rs, rt);
616 EmitI(0x6, rs, rt, imm16);
617}
618
619void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
620 CHECK_NE(rs, ZERO);
621 CHECK_NE(rt, ZERO);
622 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700623 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700624}
625
626void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
627 CHECK_NE(rs, ZERO);
628 CHECK_NE(rt, ZERO);
629 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700630 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700631}
632
633void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
634 CHECK_NE(rs, ZERO);
635 EmitI21(0x36, rs, imm21);
636}
637
638void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
639 CHECK_NE(rs, ZERO);
640 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800641}
642
Alexey Frunze299a9392015-12-08 16:08:02 -0800643void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
644 EmitFI(0x11, 0x9, ft, imm16);
645}
646
647void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
648 EmitFI(0x11, 0xD, ft, imm16);
649}
650
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700651void Mips64Assembler::EmitBcondc(BranchCondition cond,
652 GpuRegister rs,
653 GpuRegister rt,
654 uint32_t imm16_21) {
655 switch (cond) {
656 case kCondLT:
657 Bltc(rs, rt, imm16_21);
658 break;
659 case kCondGE:
660 Bgec(rs, rt, imm16_21);
661 break;
662 case kCondLE:
663 Bgec(rt, rs, imm16_21);
664 break;
665 case kCondGT:
666 Bltc(rt, rs, imm16_21);
667 break;
668 case kCondLTZ:
669 CHECK_EQ(rt, ZERO);
670 Bltzc(rs, imm16_21);
671 break;
672 case kCondGEZ:
673 CHECK_EQ(rt, ZERO);
674 Bgezc(rs, imm16_21);
675 break;
676 case kCondLEZ:
677 CHECK_EQ(rt, ZERO);
678 Blezc(rs, imm16_21);
679 break;
680 case kCondGTZ:
681 CHECK_EQ(rt, ZERO);
682 Bgtzc(rs, imm16_21);
683 break;
684 case kCondEQ:
685 Beqc(rs, rt, imm16_21);
686 break;
687 case kCondNE:
688 Bnec(rs, rt, imm16_21);
689 break;
690 case kCondEQZ:
691 CHECK_EQ(rt, ZERO);
692 Beqzc(rs, imm16_21);
693 break;
694 case kCondNEZ:
695 CHECK_EQ(rt, ZERO);
696 Bnezc(rs, imm16_21);
697 break;
698 case kCondLTU:
699 Bltuc(rs, rt, imm16_21);
700 break;
701 case kCondGEU:
702 Bgeuc(rs, rt, imm16_21);
703 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800704 case kCondF:
705 CHECK_EQ(rt, ZERO);
706 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
707 break;
708 case kCondT:
709 CHECK_EQ(rt, ZERO);
710 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
711 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700712 case kUncond:
713 LOG(FATAL) << "Unexpected branch condition " << cond;
714 UNREACHABLE();
715 }
716}
717
Andreas Gampe57b34292015-01-14 15:45:59 -0800718void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
719 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
720}
721
722void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
723 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
724}
725
726void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
727 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
728}
729
730void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
731 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
732}
733
734void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700735 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800736}
737
738void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700739 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800740}
741
742void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700743 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800744}
745
746void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700747 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800748}
749
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700750void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
751 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
752}
753
754void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
755 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
756}
757
758void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
759 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
760}
761
762void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
763 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
764}
765
Andreas Gampe57b34292015-01-14 15:45:59 -0800766void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
767 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
768}
769
770void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700771 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
772}
773
774void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
775 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
776}
777
778void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
779 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
780}
781
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700782void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
783 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
784}
785
786void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
787 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
788}
789
790void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
791 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
792}
793
794void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
795 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
796}
797
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800798void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
799 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
800}
801
802void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
803 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
804}
805
806void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
807 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
808}
809
810void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
811 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
812}
813
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700814void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
815 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
816}
817
818void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
819 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
820}
821
822void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
823 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
824}
825
826void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
827 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
828}
829
830void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
831 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
832}
833
834void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
835 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
836}
837
838void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
839 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
840}
841
842void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
843 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
844}
845
846void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
847 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
848}
849
850void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
851 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
852}
853
854void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
855 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
856}
857
858void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
859 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
860}
861
862void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
863 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
864}
865
866void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
867 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
868}
869
870void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
871 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
872}
873
874void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
875 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
876}
877
878void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
879 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
880}
881
882void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
883 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
884}
885
Alexey Frunze299a9392015-12-08 16:08:02 -0800886void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
887 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
888}
889
890void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
891 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
892}
893
894void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
895 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
896}
897
898void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
899 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
900}
901
902void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
903 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
904}
905
906void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
907 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
908}
909
910void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
911 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
912}
913
914void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
915 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
916}
917
918void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
919 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
920}
921
922void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
923 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
924}
925
926void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
927 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
928}
929
930void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
931 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
932}
933
934void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
935 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
936}
937
938void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
939 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
940}
941
942void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
943 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
944}
945
946void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
947 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
948}
949
950void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
951 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
952}
953
954void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
955 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
956}
957
958void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
959 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
960}
961
962void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
963 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
964}
965
Alexey Frunze4dda3372015-06-01 18:31:49 -0700966void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
967 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
968}
969
970void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
971 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
972}
973
974void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
975 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
976}
977
978void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
979 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800980}
981
Chris Larsen51417632015-10-02 13:24:25 -0700982void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
983 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
984}
985
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700986void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
987 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
988}
989
Andreas Gampe57b34292015-01-14 15:45:59 -0800990void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
991 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
992}
993
Lazar Trsicd9672662015-09-03 17:33:01 +0200994void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
995 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
996}
997
Alexey Frunze4dda3372015-06-01 18:31:49 -0700998void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
999 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1000}
1001
Lazar Trsicd9672662015-09-03 17:33:01 +02001002void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1003 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1004}
1005
Alexey Frunze4dda3372015-06-01 18:31:49 -07001006void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1007 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1008}
1009
1010void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1011 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001012}
1013
1014void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1015 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1016}
1017
1018void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1019 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1020}
1021
1022void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1023 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1024}
1025
1026void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1027 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1028}
1029
1030void Mips64Assembler::Break() {
1031 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1032 static_cast<GpuRegister>(0), 0, 0xD);
1033}
1034
1035void Mips64Assembler::Nop() {
1036 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1037 static_cast<GpuRegister>(0), 0, 0x0);
1038}
1039
Alexey Frunze4dda3372015-06-01 18:31:49 -07001040void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1041 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001042}
1043
Alexey Frunze4dda3372015-06-01 18:31:49 -07001044void Mips64Assembler::Clear(GpuRegister rd) {
1045 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001046}
1047
Alexey Frunze4dda3372015-06-01 18:31:49 -07001048void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1049 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001050}
1051
Alexey Frunze4dda3372015-06-01 18:31:49 -07001052void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001053 TemplateLoadConst32(this, rd, value);
1054}
1055
1056// This function is only used for testing purposes.
1057void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001058}
1059
Alexey Frunze4dda3372015-06-01 18:31:49 -07001060void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001061 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001062}
1063
Alexey Frunze4dda3372015-06-01 18:31:49 -07001064void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1065 if (IsInt<16>(value)) {
1066 Daddiu(rt, rs, value);
1067 } else {
1068 LoadConst64(rtmp, value);
1069 Daddu(rt, rs, rtmp);
1070 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001071}
1072
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001073void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1074 Mips64Assembler::Branch::Type short_type,
1075 Mips64Assembler::Branch::Type long_type) {
1076 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1077}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001078
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001079void Mips64Assembler::Branch::InitializeType(bool is_call) {
1080 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1081 if (is_call) {
1082 InitShortOrLong(offset_size, kCall, kLongCall);
1083 } else if (condition_ == kUncond) {
1084 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1085 } else {
1086 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1087 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1088 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1089 } else {
1090 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1091 }
1092 }
1093 old_type_ = type_;
1094}
1095
1096bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1097 switch (condition) {
1098 case kCondLT:
1099 case kCondGT:
1100 case kCondNE:
1101 case kCondLTU:
1102 return lhs == rhs;
1103 default:
1104 return false;
1105 }
1106}
1107
1108bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1109 GpuRegister lhs,
1110 GpuRegister rhs) {
1111 switch (condition) {
1112 case kUncond:
1113 return true;
1114 case kCondGE:
1115 case kCondLE:
1116 case kCondEQ:
1117 case kCondGEU:
1118 return lhs == rhs;
1119 default:
1120 return false;
1121 }
1122}
1123
1124Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1125 : old_location_(location),
1126 location_(location),
1127 target_(target),
1128 lhs_reg_(ZERO),
1129 rhs_reg_(ZERO),
1130 condition_(kUncond) {
1131 InitializeType(false);
1132}
1133
1134Mips64Assembler::Branch::Branch(uint32_t location,
1135 uint32_t target,
1136 Mips64Assembler::BranchCondition condition,
1137 GpuRegister lhs_reg,
1138 GpuRegister rhs_reg)
1139 : old_location_(location),
1140 location_(location),
1141 target_(target),
1142 lhs_reg_(lhs_reg),
1143 rhs_reg_(rhs_reg),
1144 condition_(condition) {
1145 CHECK_NE(condition, kUncond);
1146 switch (condition) {
1147 case kCondEQ:
1148 case kCondNE:
1149 case kCondLT:
1150 case kCondGE:
1151 case kCondLE:
1152 case kCondGT:
1153 case kCondLTU:
1154 case kCondGEU:
1155 CHECK_NE(lhs_reg, ZERO);
1156 CHECK_NE(rhs_reg, ZERO);
1157 break;
1158 case kCondLTZ:
1159 case kCondGEZ:
1160 case kCondLEZ:
1161 case kCondGTZ:
1162 case kCondEQZ:
1163 case kCondNEZ:
1164 CHECK_NE(lhs_reg, ZERO);
1165 CHECK_EQ(rhs_reg, ZERO);
1166 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001167 case kCondF:
1168 case kCondT:
1169 CHECK_EQ(rhs_reg, ZERO);
1170 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001171 case kUncond:
1172 UNREACHABLE();
1173 }
1174 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1175 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1176 // Branch condition is always true, make the branch unconditional.
1177 condition_ = kUncond;
1178 }
1179 InitializeType(false);
1180}
1181
1182Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1183 : old_location_(location),
1184 location_(location),
1185 target_(target),
1186 lhs_reg_(indirect_reg),
1187 rhs_reg_(ZERO),
1188 condition_(kUncond) {
1189 CHECK_NE(indirect_reg, ZERO);
1190 CHECK_NE(indirect_reg, AT);
1191 InitializeType(true);
1192}
1193
1194Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1195 Mips64Assembler::BranchCondition cond) {
1196 switch (cond) {
1197 case kCondLT:
1198 return kCondGE;
1199 case kCondGE:
1200 return kCondLT;
1201 case kCondLE:
1202 return kCondGT;
1203 case kCondGT:
1204 return kCondLE;
1205 case kCondLTZ:
1206 return kCondGEZ;
1207 case kCondGEZ:
1208 return kCondLTZ;
1209 case kCondLEZ:
1210 return kCondGTZ;
1211 case kCondGTZ:
1212 return kCondLEZ;
1213 case kCondEQ:
1214 return kCondNE;
1215 case kCondNE:
1216 return kCondEQ;
1217 case kCondEQZ:
1218 return kCondNEZ;
1219 case kCondNEZ:
1220 return kCondEQZ;
1221 case kCondLTU:
1222 return kCondGEU;
1223 case kCondGEU:
1224 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001225 case kCondF:
1226 return kCondT;
1227 case kCondT:
1228 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001229 case kUncond:
1230 LOG(FATAL) << "Unexpected branch condition " << cond;
1231 }
1232 UNREACHABLE();
1233}
1234
1235Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1236 return type_;
1237}
1238
1239Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1240 return condition_;
1241}
1242
1243GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1244 return lhs_reg_;
1245}
1246
1247GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1248 return rhs_reg_;
1249}
1250
1251uint32_t Mips64Assembler::Branch::GetTarget() const {
1252 return target_;
1253}
1254
1255uint32_t Mips64Assembler::Branch::GetLocation() const {
1256 return location_;
1257}
1258
1259uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1260 return old_location_;
1261}
1262
1263uint32_t Mips64Assembler::Branch::GetLength() const {
1264 return branch_info_[type_].length;
1265}
1266
1267uint32_t Mips64Assembler::Branch::GetOldLength() const {
1268 return branch_info_[old_type_].length;
1269}
1270
1271uint32_t Mips64Assembler::Branch::GetSize() const {
1272 return GetLength() * sizeof(uint32_t);
1273}
1274
1275uint32_t Mips64Assembler::Branch::GetOldSize() const {
1276 return GetOldLength() * sizeof(uint32_t);
1277}
1278
1279uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1280 return GetLocation() + GetSize();
1281}
1282
1283uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1284 return GetOldLocation() + GetOldSize();
1285}
1286
1287bool Mips64Assembler::Branch::IsLong() const {
1288 switch (type_) {
1289 // Short branches.
1290 case kUncondBranch:
1291 case kCondBranch:
1292 case kCall:
1293 return false;
1294 // Long branches.
1295 case kLongUncondBranch:
1296 case kLongCondBranch:
1297 case kLongCall:
1298 return true;
1299 }
1300 UNREACHABLE();
1301}
1302
1303bool Mips64Assembler::Branch::IsResolved() const {
1304 return target_ != kUnresolved;
1305}
1306
1307Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1308 OffsetBits offset_size =
1309 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1310 ? kOffset23
1311 : branch_info_[type_].offset_size;
1312 return offset_size;
1313}
1314
1315Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1316 uint32_t target) {
1317 // For unresolved targets assume the shortest encoding
1318 // (later it will be made longer if needed).
1319 if (target == kUnresolved)
1320 return kOffset16;
1321 int64_t distance = static_cast<int64_t>(target) - location;
1322 // To simplify calculations in composite branches consisting of multiple instructions
1323 // bump up the distance by a value larger than the max byte size of a composite branch.
1324 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1325 if (IsInt<kOffset16>(distance))
1326 return kOffset16;
1327 else if (IsInt<kOffset18>(distance))
1328 return kOffset18;
1329 else if (IsInt<kOffset21>(distance))
1330 return kOffset21;
1331 else if (IsInt<kOffset23>(distance))
1332 return kOffset23;
1333 else if (IsInt<kOffset28>(distance))
1334 return kOffset28;
1335 return kOffset32;
1336}
1337
1338void Mips64Assembler::Branch::Resolve(uint32_t target) {
1339 target_ = target;
1340}
1341
1342void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1343 if (location_ > expand_location) {
1344 location_ += delta;
1345 }
1346 if (!IsResolved()) {
1347 return; // Don't know the target yet.
1348 }
1349 if (target_ > expand_location) {
1350 target_ += delta;
1351 }
1352}
1353
1354void Mips64Assembler::Branch::PromoteToLong() {
1355 switch (type_) {
1356 // Short branches.
1357 case kUncondBranch:
1358 type_ = kLongUncondBranch;
1359 break;
1360 case kCondBranch:
1361 type_ = kLongCondBranch;
1362 break;
1363 case kCall:
1364 type_ = kLongCall;
1365 break;
1366 default:
1367 // Note: 'type_' is already long.
1368 break;
1369 }
1370 CHECK(IsLong());
1371}
1372
1373uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1374 // If the branch is still unresolved or already long, nothing to do.
1375 if (IsLong() || !IsResolved()) {
1376 return 0;
1377 }
1378 // Promote the short branch to long if the offset size is too small
1379 // to hold the distance between location_ and target_.
1380 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1381 PromoteToLong();
1382 uint32_t old_size = GetOldSize();
1383 uint32_t new_size = GetSize();
1384 CHECK_GT(new_size, old_size);
1385 return new_size - old_size;
1386 }
1387 // The following logic is for debugging/testing purposes.
1388 // Promote some short branches to long when it's not really required.
1389 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1390 int64_t distance = static_cast<int64_t>(target_) - location_;
1391 distance = (distance >= 0) ? distance : -distance;
1392 if (distance >= max_short_distance) {
1393 PromoteToLong();
1394 uint32_t old_size = GetOldSize();
1395 uint32_t new_size = GetSize();
1396 CHECK_GT(new_size, old_size);
1397 return new_size - old_size;
1398 }
1399 }
1400 return 0;
1401}
1402
1403uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1404 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1405}
1406
1407uint32_t Mips64Assembler::Branch::GetOffset() const {
1408 CHECK(IsResolved());
1409 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1410 // Calculate the byte distance between instructions and also account for
1411 // different PC-relative origins.
1412 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1413 // Prepare the offset for encoding into the instruction(s).
1414 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1415 return offset;
1416}
1417
1418Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1419 CHECK_LT(branch_id, branches_.size());
1420 return &branches_[branch_id];
1421}
1422
1423const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1424 CHECK_LT(branch_id, branches_.size());
1425 return &branches_[branch_id];
1426}
1427
1428void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001429 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001430 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001431
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001432 // Walk the list of branches referring to and preceding this label.
1433 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001434 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001435 uint32_t branch_id = label->Position();
1436 Branch* branch = GetBranch(branch_id);
1437 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001438
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001439 uint32_t branch_location = branch->GetLocation();
1440 // Extract the location of the previous branch in the list (walking the list backwards;
1441 // the previous branch ID was stored in the space reserved for this branch).
1442 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001443
1444 // On to the previous branch in the list...
1445 label->position_ = prev;
1446 }
1447
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001448 // Now make the label object contain its own location (relative to the end of the preceding
1449 // branch, if any; it will be used by the branches referring to and following this label).
1450 label->prev_branch_id_plus_one_ = branches_.size();
1451 if (label->prev_branch_id_plus_one_) {
1452 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1453 const Branch* branch = GetBranch(branch_id);
1454 bound_pc -= branch->GetEndLocation();
1455 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001456 label->BindTo(bound_pc);
1457}
1458
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001459uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1460 CHECK(label->IsBound());
1461 uint32_t target = label->Position();
1462 if (label->prev_branch_id_plus_one_) {
1463 // Get label location based on the branch preceding it.
1464 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1465 const Branch* branch = GetBranch(branch_id);
1466 target += branch->GetEndLocation();
1467 }
1468 return target;
1469}
1470
1471uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1472 // We can reconstruct the adjustment by going through all the branches from the beginning
1473 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1474 // with increasing old_position, we can use the data from last AdjustedPosition() to
1475 // continue where we left off and the whole loop should be O(m+n) where m is the number
1476 // of positions to adjust and n is the number of branches.
1477 if (old_position < last_old_position_) {
1478 last_position_adjustment_ = 0;
1479 last_old_position_ = 0;
1480 last_branch_id_ = 0;
1481 }
1482 while (last_branch_id_ != branches_.size()) {
1483 const Branch* branch = GetBranch(last_branch_id_);
1484 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1485 break;
1486 }
1487 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1488 ++last_branch_id_;
1489 }
1490 last_old_position_ = old_position;
1491 return old_position + last_position_adjustment_;
1492}
1493
1494void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1495 uint32_t length = branches_.back().GetLength();
1496 if (!label->IsBound()) {
1497 // Branch forward (to a following label), distance is unknown.
1498 // The first branch forward will contain 0, serving as the terminator of
1499 // the list of forward-reaching branches.
1500 Emit(label->position_);
1501 length--;
1502 // Now make the label object point to this branch
1503 // (this forms a linked list of branches preceding this label).
1504 uint32_t branch_id = branches_.size() - 1;
1505 label->LinkTo(branch_id);
1506 }
1507 // Reserve space for the branch.
1508 while (length--) {
1509 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001510 }
1511}
1512
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001513void Mips64Assembler::Buncond(Mips64Label* label) {
1514 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1515 branches_.emplace_back(buffer_.Size(), target);
1516 FinalizeLabeledBranch(label);
1517}
1518
1519void Mips64Assembler::Bcond(Mips64Label* label,
1520 BranchCondition condition,
1521 GpuRegister lhs,
1522 GpuRegister rhs) {
1523 // If lhs = rhs, this can be a NOP.
1524 if (Branch::IsNop(condition, lhs, rhs)) {
1525 return;
1526 }
1527 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1528 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1529 FinalizeLabeledBranch(label);
1530}
1531
1532void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1533 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1534 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1535 FinalizeLabeledBranch(label);
1536}
1537
1538void Mips64Assembler::PromoteBranches() {
1539 // Promote short branches to long as necessary.
1540 bool changed;
1541 do {
1542 changed = false;
1543 for (auto& branch : branches_) {
1544 CHECK(branch.IsResolved());
1545 uint32_t delta = branch.PromoteIfNeeded();
1546 // If this branch has been promoted and needs to expand in size,
1547 // relocate all branches by the expansion size.
1548 if (delta) {
1549 changed = true;
1550 uint32_t expand_location = branch.GetLocation();
1551 for (auto& branch2 : branches_) {
1552 branch2.Relocate(expand_location, delta);
1553 }
1554 }
1555 }
1556 } while (changed);
1557
1558 // Account for branch expansion by resizing the code buffer
1559 // and moving the code in it to its final location.
1560 size_t branch_count = branches_.size();
1561 if (branch_count > 0) {
1562 // Resize.
1563 Branch& last_branch = branches_[branch_count - 1];
1564 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1565 uint32_t old_size = buffer_.Size();
1566 buffer_.Resize(old_size + size_delta);
1567 // Move the code residing between branch placeholders.
1568 uint32_t end = old_size;
1569 for (size_t i = branch_count; i > 0; ) {
1570 Branch& branch = branches_[--i];
1571 uint32_t size = end - branch.GetOldEndLocation();
1572 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1573 end = branch.GetOldLocation();
1574 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001575 }
1576}
1577
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001578// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1579const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1580 // Short branches.
1581 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1582 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1583 // Exception: kOffset23 for beqzc/bnezc
1584 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1585 // Long branches.
1586 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1587 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1588 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1589};
1590
1591// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1592void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1593 CHECK(overwriting_);
1594 overwrite_location_ = branch->GetLocation();
1595 uint32_t offset = branch->GetOffset();
1596 BranchCondition condition = branch->GetCondition();
1597 GpuRegister lhs = branch->GetLeftRegister();
1598 GpuRegister rhs = branch->GetRightRegister();
1599 switch (branch->GetType()) {
1600 // Short branches.
1601 case Branch::kUncondBranch:
1602 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1603 Bc(offset);
1604 break;
1605 case Branch::kCondBranch:
1606 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1607 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001608 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001609 break;
1610 case Branch::kCall:
1611 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1612 Addiupc(lhs, offset);
1613 Jialc(lhs, 0);
1614 break;
1615
1616 // Long branches.
1617 case Branch::kLongUncondBranch:
1618 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1619 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1620 Auipc(AT, High16Bits(offset));
1621 Jic(AT, Low16Bits(offset));
1622 break;
1623 case Branch::kLongCondBranch:
1624 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1625 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1626 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1627 Auipc(AT, High16Bits(offset));
1628 Jic(AT, Low16Bits(offset));
1629 break;
1630 case Branch::kLongCall:
1631 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1632 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1633 Auipc(lhs, High16Bits(offset));
1634 Daddiu(lhs, lhs, Low16Bits(offset));
1635 Jialc(lhs, 0);
1636 break;
1637 }
1638 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1639 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001640}
1641
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001642void Mips64Assembler::Bc(Mips64Label* label) {
1643 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001644}
1645
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001646void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1647 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001648}
1649
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001650void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1651 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001652}
1653
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001654void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1655 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001656}
1657
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001658void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1659 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001660}
1661
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001662void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1663 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001664}
1665
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001666void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1667 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001668}
1669
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001670void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1671 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001672}
1673
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001674void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1675 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001676}
1677
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001678void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1679 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001680}
1681
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001682void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1683 Bcond(label, kCondEQ, rs, rt);
1684}
1685
1686void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1687 Bcond(label, kCondNE, rs, rt);
1688}
1689
1690void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1691 Bcond(label, kCondEQZ, rs);
1692}
1693
1694void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1695 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001696}
1697
Alexey Frunze299a9392015-12-08 16:08:02 -08001698void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1699 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1700}
1701
1702void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1703 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1704}
1705
Andreas Gampe57b34292015-01-14 15:45:59 -08001706void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1707 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001708 if (!IsInt<16>(offset) ||
1709 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1710 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1711 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001712 Daddu(AT, AT, base);
1713 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001714 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001715 }
1716
Andreas Gampe57b34292015-01-14 15:45:59 -08001717 switch (type) {
1718 case kLoadSignedByte:
1719 Lb(reg, base, offset);
1720 break;
1721 case kLoadUnsignedByte:
1722 Lbu(reg, base, offset);
1723 break;
1724 case kLoadSignedHalfword:
1725 Lh(reg, base, offset);
1726 break;
1727 case kLoadUnsignedHalfword:
1728 Lhu(reg, base, offset);
1729 break;
1730 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001731 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001732 Lw(reg, base, offset);
1733 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001734 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001735 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07001736 Lwu(reg, base, offset);
1737 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001738 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001739 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1740 CHECK_ALIGNED(offset, kMips64WordSize);
1741 Lwu(reg, base, offset);
1742 Lwu(TMP2, base, offset + kMips64WordSize);
1743 Dinsu(reg, TMP2, 32, 32);
1744 } else {
1745 Ld(reg, base, offset);
1746 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001747 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001748 }
1749}
1750
1751void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1752 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001753 if (!IsInt<16>(offset) ||
1754 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1755 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1756 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001757 Daddu(AT, AT, base);
1758 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001759 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001760 }
1761
Andreas Gampe57b34292015-01-14 15:45:59 -08001762 switch (type) {
1763 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001764 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001765 Lwc1(reg, base, offset);
1766 break;
1767 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001768 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1769 CHECK_ALIGNED(offset, kMips64WordSize);
1770 Lwc1(reg, base, offset);
1771 Lw(TMP2, base, offset + kMips64WordSize);
1772 Mthc1(TMP2, reg);
1773 } else {
1774 Ldc1(reg, base, offset);
1775 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001776 break;
1777 default:
1778 LOG(FATAL) << "UNREACHABLE";
1779 }
1780}
1781
1782void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1783 size_t size) {
1784 Mips64ManagedRegister dst = m_dst.AsMips64();
1785 if (dst.IsNoRegister()) {
1786 CHECK_EQ(0u, size) << dst;
1787 } else if (dst.IsGpuRegister()) {
1788 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001789 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1790 } else if (size == 8) {
1791 CHECK_EQ(8u, size) << dst;
1792 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1793 } else {
1794 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1795 }
1796 } else if (dst.IsFpuRegister()) {
1797 if (size == 4) {
1798 CHECK_EQ(4u, size) << dst;
1799 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1800 } else if (size == 8) {
1801 CHECK_EQ(8u, size) << dst;
1802 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1803 } else {
1804 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1805 }
1806 }
1807}
1808
1809void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1810 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001811 if (!IsInt<16>(offset) ||
1812 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1813 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1814 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001815 Daddu(AT, AT, base);
1816 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001817 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001818 }
1819
Andreas Gampe57b34292015-01-14 15:45:59 -08001820 switch (type) {
1821 case kStoreByte:
1822 Sb(reg, base, offset);
1823 break;
1824 case kStoreHalfword:
1825 Sh(reg, base, offset);
1826 break;
1827 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001828 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001829 Sw(reg, base, offset);
1830 break;
1831 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001832 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1833 CHECK_ALIGNED(offset, kMips64WordSize);
1834 Sw(reg, base, offset);
1835 Dsrl32(TMP2, reg, 0);
1836 Sw(TMP2, base, offset + kMips64WordSize);
1837 } else {
1838 Sd(reg, base, offset);
1839 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001840 break;
1841 default:
1842 LOG(FATAL) << "UNREACHABLE";
1843 }
1844}
1845
1846void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1847 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001848 if (!IsInt<16>(offset) ||
1849 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1850 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1851 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001852 Daddu(AT, AT, base);
1853 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001854 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001855 }
1856
Andreas Gampe57b34292015-01-14 15:45:59 -08001857 switch (type) {
1858 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001859 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001860 Swc1(reg, base, offset);
1861 break;
1862 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001863 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1864 CHECK_ALIGNED(offset, kMips64WordSize);
1865 Mfhc1(TMP2, reg);
1866 Swc1(reg, base, offset);
1867 Sw(TMP2, base, offset + kMips64WordSize);
1868 } else {
1869 Sdc1(reg, base, offset);
1870 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001871 break;
1872 default:
1873 LOG(FATAL) << "UNREACHABLE";
1874 }
1875}
1876
David Srbeckydd973932015-04-07 20:29:48 +01001877static dwarf::Reg DWARFReg(GpuRegister reg) {
1878 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1879}
1880
Andreas Gampe57b34292015-01-14 15:45:59 -08001881constexpr size_t kFramePointerSize = 8;
1882
Vladimir Marko32248382016-05-19 10:37:24 +01001883void Mips64Assembler::BuildFrame(size_t frame_size,
1884 ManagedRegister method_reg,
1885 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08001886 const ManagedRegisterEntrySpills& entry_spills) {
1887 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001888 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001889
1890 // Increase frame to required size.
1891 IncreaseFrameSize(frame_size);
1892
1893 // Push callee saves and return address
1894 int stack_offset = frame_size - kFramePointerSize;
1895 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001896 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001897 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1898 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01001899 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08001900 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001901 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001902 }
1903
1904 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001905 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001906
1907 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001908 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08001909 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01001910 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08001911 ManagedRegisterSpill spill = entry_spills.at(i);
1912 int32_t size = spill.getSize();
1913 if (reg.IsNoRegister()) {
1914 // only increment stack offset.
1915 offset += size;
1916 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001917 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1918 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001919 offset += size;
1920 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001921 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1922 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001923 offset += size;
1924 }
1925 }
1926}
1927
1928void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01001929 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001930 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001931 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01001932 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08001933
1934 // Pop callee saves and return address
1935 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
1936 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01001937 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08001938 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001939 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08001940 stack_offset += kFramePointerSize;
1941 }
1942 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001943 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08001944
1945 // Decrease frame to required size.
1946 DecreaseFrameSize(frame_size);
1947
1948 // Then jump to the return address.
1949 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001950 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01001951
1952 // The CFI should be restored for any code that follows the exit block.
1953 cfi_.RestoreState();
1954 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08001955}
1956
1957void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001958 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001959 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001960 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001961 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001962}
1963
1964void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001965 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001966 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001967 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001968 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001969}
1970
1971void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
1972 Mips64ManagedRegister src = msrc.AsMips64();
1973 if (src.IsNoRegister()) {
1974 CHECK_EQ(0u, size);
1975 } else if (src.IsGpuRegister()) {
1976 CHECK(size == 4 || size == 8) << size;
1977 if (size == 8) {
1978 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
1979 } else if (size == 4) {
1980 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
1981 } else {
1982 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
1983 }
1984 } else if (src.IsFpuRegister()) {
1985 CHECK(size == 4 || size == 8) << size;
1986 if (size == 8) {
1987 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
1988 } else if (size == 4) {
1989 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
1990 } else {
1991 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
1992 }
1993 }
1994}
1995
1996void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
1997 Mips64ManagedRegister src = msrc.AsMips64();
1998 CHECK(src.IsGpuRegister());
1999 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2000}
2001
2002void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2003 Mips64ManagedRegister src = msrc.AsMips64();
2004 CHECK(src.IsGpuRegister());
2005 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2006}
2007
2008void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2009 ManagedRegister mscratch) {
2010 Mips64ManagedRegister scratch = mscratch.AsMips64();
2011 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002012 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002013 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2014}
2015
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002016void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2017 FrameOffset fr_offs,
2018 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002019 Mips64ManagedRegister scratch = mscratch.AsMips64();
2020 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002021 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002022 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2023}
2024
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002025void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002026 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2027}
2028
2029void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2030 FrameOffset in_off, ManagedRegister mscratch) {
2031 Mips64ManagedRegister src = msrc.AsMips64();
2032 Mips64ManagedRegister scratch = mscratch.AsMips64();
2033 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2034 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2035 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2036}
2037
2038void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2039 return EmitLoad(mdest, SP, src.Int32Value(), size);
2040}
2041
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002042void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002043 return EmitLoad(mdest, S1, src.Int32Value(), size);
2044}
2045
2046void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2047 Mips64ManagedRegister dest = mdest.AsMips64();
2048 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002049 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002050}
2051
Mathieu Chartiere401d142015-04-22 13:56:20 -07002052void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002053 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002054 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002055 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2056 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002057 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002058 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002059 // TODO: review
2060 // Negate the 32-bit ref
2061 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2062 // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
Lazar Trsicd9672662015-09-03 17:33:01 +02002063 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002064 }
2065}
2066
2067void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002068 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002069 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002070 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002071 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2072 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2073}
2074
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002075void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002076 Mips64ManagedRegister dest = mdest.AsMips64();
2077 CHECK(dest.IsGpuRegister());
2078 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2079}
2080
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002081void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2082 size_t size ATTRIBUTE_UNUSED) {
2083 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002084}
2085
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002086void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2087 size_t size ATTRIBUTE_UNUSED) {
2088 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002089}
2090
2091void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2092 Mips64ManagedRegister dest = mdest.AsMips64();
2093 Mips64ManagedRegister src = msrc.AsMips64();
2094 if (!dest.Equals(src)) {
2095 if (dest.IsGpuRegister()) {
2096 CHECK(src.IsGpuRegister()) << src;
2097 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2098 } else if (dest.IsFpuRegister()) {
2099 CHECK(src.IsFpuRegister()) << src;
2100 if (size == 4) {
2101 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2102 } else if (size == 8) {
2103 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2104 } else {
2105 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2106 }
2107 }
2108 }
2109}
2110
2111void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2112 ManagedRegister mscratch) {
2113 Mips64ManagedRegister scratch = mscratch.AsMips64();
2114 CHECK(scratch.IsGpuRegister()) << scratch;
2115 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2116 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2117}
2118
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002119void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2120 ThreadOffset64 thr_offs,
2121 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002122 Mips64ManagedRegister scratch = mscratch.AsMips64();
2123 CHECK(scratch.IsGpuRegister()) << scratch;
2124 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2125 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2126}
2127
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002128void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2129 FrameOffset fr_offs,
2130 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002131 Mips64ManagedRegister scratch = mscratch.AsMips64();
2132 CHECK(scratch.IsGpuRegister()) << scratch;
2133 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2134 SP, fr_offs.Int32Value());
2135 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2136 S1, thr_offs.Int32Value());
2137}
2138
2139void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2140 ManagedRegister mscratch, size_t size) {
2141 Mips64ManagedRegister scratch = mscratch.AsMips64();
2142 CHECK(scratch.IsGpuRegister()) << scratch;
2143 CHECK(size == 4 || size == 8) << size;
2144 if (size == 4) {
2145 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002146 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002147 } else if (size == 8) {
2148 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2149 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2150 } else {
2151 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2152 }
2153}
2154
2155void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002156 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002157 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2158 CHECK(size == 4 || size == 8) << size;
2159 if (size == 4) {
2160 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2161 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002162 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002163 } else if (size == 8) {
2164 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2165 src_offset.Int32Value());
2166 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2167 } else {
2168 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2169 }
2170}
2171
2172void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002173 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002174 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2175 CHECK(size == 4 || size == 8) << size;
2176 if (size == 4) {
2177 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002178 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002179 dest_offset.Int32Value());
2180 } else if (size == 8) {
2181 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2182 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2183 dest_offset.Int32Value());
2184 } else {
2185 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2186 }
2187}
2188
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002189void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2190 FrameOffset src_base ATTRIBUTE_UNUSED,
2191 Offset src_offset ATTRIBUTE_UNUSED,
2192 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2193 size_t size ATTRIBUTE_UNUSED) {
2194 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002195}
2196
2197void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002198 ManagedRegister src, Offset src_offset,
2199 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002200 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2201 CHECK(size == 4 || size == 8) << size;
2202 if (size == 4) {
2203 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002204 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002205 } else if (size == 8) {
2206 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2207 src_offset.Int32Value());
2208 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2209 dest_offset.Int32Value());
2210 } else {
2211 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2212 }
2213}
2214
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002215void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2216 Offset dest_offset ATTRIBUTE_UNUSED,
2217 FrameOffset src ATTRIBUTE_UNUSED,
2218 Offset src_offset ATTRIBUTE_UNUSED,
2219 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2220 size_t size ATTRIBUTE_UNUSED) {
2221 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002222}
2223
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002224void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002225 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002226 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002227}
2228
2229void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002230 FrameOffset handle_scope_offset,
2231 ManagedRegister min_reg,
2232 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002233 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2234 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2235 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2236 CHECK(out_reg.IsGpuRegister()) << out_reg;
2237 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002238 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002239 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2240 // the address in the handle scope holding the reference.
2241 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2242 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002243 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002244 SP, handle_scope_offset.Int32Value());
2245 in_reg = out_reg;
2246 }
2247 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002248 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002249 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002250 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2251 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2252 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002253 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002254 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002255 }
2256}
2257
2258void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002259 FrameOffset handle_scope_offset,
2260 ManagedRegister mscratch,
2261 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002262 Mips64ManagedRegister scratch = mscratch.AsMips64();
2263 CHECK(scratch.IsGpuRegister()) << scratch;
2264 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002265 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002266 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002267 handle_scope_offset.Int32Value());
2268 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2269 // the address in the handle scope holding the reference.
2270 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002271 Beqzc(scratch.AsGpuRegister(), &null_arg);
2272 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2273 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002274 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002275 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 }
2277 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2278}
2279
2280// Given a handle scope entry, load the associated reference.
2281void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002282 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002283 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2284 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2285 CHECK(out_reg.IsGpuRegister()) << out_reg;
2286 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002287 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002288 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002289 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002290 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002291 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002292 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2293 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002294 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002295}
2296
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002297void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2298 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002299 // TODO: not validating references
2300}
2301
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002302void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2303 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002304 // TODO: not validating references
2305}
2306
2307void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2308 Mips64ManagedRegister base = mbase.AsMips64();
2309 Mips64ManagedRegister scratch = mscratch.AsMips64();
2310 CHECK(base.IsGpuRegister()) << base;
2311 CHECK(scratch.IsGpuRegister()) << scratch;
2312 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2313 base.AsGpuRegister(), offset.Int32Value());
2314 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002315 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002316 // TODO: place reference map on call
2317}
2318
2319void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2320 Mips64ManagedRegister scratch = mscratch.AsMips64();
2321 CHECK(scratch.IsGpuRegister()) << scratch;
2322 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002323 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002324 SP, base.Int32Value());
2325 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2326 scratch.AsGpuRegister(), offset.Int32Value());
2327 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002328 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002329 // TODO: place reference map on call
2330}
2331
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002332void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2333 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002334 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002335}
2336
2337void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2338 Move(tr.AsMips64().AsGpuRegister(), S1);
2339}
2340
2341void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002342 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002343 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2344}
2345
2346void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2347 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002348 exception_blocks_.emplace_back(scratch, stack_adjust);
2349 LoadFromOffset(kLoadDoubleword,
2350 scratch.AsGpuRegister(),
2351 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002352 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002353 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002354}
2355
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002356void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2357 Bind(exception->Entry());
2358 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2359 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002360 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002361 // Pass exception object as argument.
2362 // Don't care about preserving A0 as this call won't return.
2363 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2364 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002365 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002366 LoadFromOffset(kLoadDoubleword,
2367 T9,
2368 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002369 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002370 Jr(T9);
2371 Nop();
2372
Andreas Gampe57b34292015-01-14 15:45:59 -08002373 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002374 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002375}
2376
2377} // namespace mips64
2378} // namespace art