blob: cfd8421e938cc37cf51d1efe0e51e312f300e47b [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
Alexey Frunzea0e87b02015-09-24 22:57:20 -070029void Mips64Assembler::FinalizeCode() {
30 for (auto& exception_block : exception_blocks_) {
31 EmitExceptionPoll(&exception_block);
32 }
33 PromoteBranches();
34}
35
36void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
37 EmitBranches();
38 Assembler::FinalizeInstructions(region);
39 PatchCFI();
40}
41
42void Mips64Assembler::PatchCFI() {
43 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
44 return;
45 }
46
47 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
48 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
49 const std::vector<uint8_t>& old_stream = data.first;
50 const std::vector<DelayedAdvancePC>& advances = data.second;
51
52 // Refill our data buffer with patched opcodes.
53 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
54 size_t stream_pos = 0;
55 for (const DelayedAdvancePC& advance : advances) {
56 DCHECK_GE(advance.stream_pos, stream_pos);
57 // Copy old data up to the point where advance was issued.
58 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
59 stream_pos = advance.stream_pos;
60 // Insert the advance command with its final offset.
61 size_t final_pc = GetAdjustedPosition(advance.pc);
62 cfi().AdvancePC(final_pc);
63 }
64 // Copy the final segment if any.
65 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
66}
67
68void Mips64Assembler::EmitBranches() {
69 CHECK(!overwriting_);
70 // Switch from appending instructions at the end of the buffer to overwriting
71 // existing instructions (branch placeholders) in the buffer.
72 overwriting_ = true;
73 for (auto& branch : branches_) {
74 EmitBranch(&branch);
75 }
76 overwriting_ = false;
77}
78
Alexey Frunze4dda3372015-06-01 18:31:49 -070079void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070080 if (overwriting_) {
81 // Branches to labels are emitted into their placeholders here.
82 buffer_.Store<uint32_t>(overwrite_location_, value);
83 overwrite_location_ += sizeof(uint32_t);
84 } else {
85 // Other instructions are simply appended at the end here.
86 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
87 buffer_.Emit<uint32_t>(value);
88 }
Andreas Gampe57b34292015-01-14 15:45:59 -080089}
90
91void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
92 int shamt, int funct) {
93 CHECK_NE(rs, kNoGpuRegister);
94 CHECK_NE(rt, kNoGpuRegister);
95 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -070096 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
97 static_cast<uint32_t>(rs) << kRsShift |
98 static_cast<uint32_t>(rt) << kRtShift |
99 static_cast<uint32_t>(rd) << kRdShift |
100 shamt << kShamtShift |
101 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800102 Emit(encoding);
103}
104
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700105void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
106 int shamt, int funct) {
107 CHECK_NE(rs, kNoGpuRegister);
108 CHECK_NE(rd, kNoGpuRegister);
109 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
110 static_cast<uint32_t>(rs) << kRsShift |
111 static_cast<uint32_t>(ZERO) << kRtShift |
112 static_cast<uint32_t>(rd) << kRdShift |
113 shamt << kShamtShift |
114 funct;
115 Emit(encoding);
116}
117
118void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
119 int shamt, int funct) {
120 CHECK_NE(rt, kNoGpuRegister);
121 CHECK_NE(rd, kNoGpuRegister);
122 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
123 static_cast<uint32_t>(ZERO) << kRsShift |
124 static_cast<uint32_t>(rt) << kRtShift |
125 static_cast<uint32_t>(rd) << kRdShift |
126 shamt << kShamtShift |
127 funct;
128 Emit(encoding);
129}
130
Andreas Gampe57b34292015-01-14 15:45:59 -0800131void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
132 CHECK_NE(rs, kNoGpuRegister);
133 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700134 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
135 static_cast<uint32_t>(rs) << kRsShift |
136 static_cast<uint32_t>(rt) << kRtShift |
137 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800138 Emit(encoding);
139}
140
Alexey Frunze4dda3372015-06-01 18:31:49 -0700141void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
142 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700143 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700144 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
145 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700146 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700147 Emit(encoding);
148}
149
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700150void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
151 CHECK(IsUint<26>(imm26)) << imm26;
152 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800153 Emit(encoding);
154}
155
156void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700157 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800158 CHECK_NE(ft, kNoFpuRegister);
159 CHECK_NE(fs, kNoFpuRegister);
160 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700161 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
162 fmt << kFmtShift |
163 static_cast<uint32_t>(ft) << kFtShift |
164 static_cast<uint32_t>(fs) << kFsShift |
165 static_cast<uint32_t>(fd) << kFdShift |
166 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800167 Emit(encoding);
168}
169
Alexey Frunze4dda3372015-06-01 18:31:49 -0700170void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
171 CHECK_NE(ft, kNoFpuRegister);
172 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
173 fmt << kFmtShift |
174 static_cast<uint32_t>(ft) << kFtShift |
175 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800176 Emit(encoding);
177}
178
Andreas Gampe57b34292015-01-14 15:45:59 -0800179void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
180 EmitR(0, rs, rt, rd, 0, 0x21);
181}
182
183void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
184 EmitI(0x9, rs, rt, imm16);
185}
186
Alexey Frunze4dda3372015-06-01 18:31:49 -0700187void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
188 EmitR(0, rs, rt, rd, 0, 0x2d);
189}
190
Andreas Gampe57b34292015-01-14 15:45:59 -0800191void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
192 EmitI(0x19, rs, rt, imm16);
193}
194
Andreas Gampe57b34292015-01-14 15:45:59 -0800195void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
196 EmitR(0, rs, rt, rd, 0, 0x23);
197}
198
Alexey Frunze4dda3372015-06-01 18:31:49 -0700199void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
200 EmitR(0, rs, rt, rd, 0, 0x2f);
201}
202
Alexey Frunze4dda3372015-06-01 18:31:49 -0700203void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
204 EmitR(0, rs, rt, rd, 2, 0x18);
205}
206
Alexey Frunzec857c742015-09-23 15:12:39 -0700207void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
208 EmitR(0, rs, rt, rd, 3, 0x18);
209}
210
Alexey Frunze4dda3372015-06-01 18:31:49 -0700211void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
212 EmitR(0, rs, rt, rd, 2, 0x1a);
213}
214
215void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
216 EmitR(0, rs, rt, rd, 3, 0x1a);
217}
218
219void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
220 EmitR(0, rs, rt, rd, 2, 0x1b);
221}
222
223void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
224 EmitR(0, rs, rt, rd, 3, 0x1b);
225}
226
227void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
228 EmitR(0, rs, rt, rd, 2, 0x1c);
229}
230
Alexey Frunzec857c742015-09-23 15:12:39 -0700231void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
232 EmitR(0, rs, rt, rd, 3, 0x1c);
233}
234
Alexey Frunze4dda3372015-06-01 18:31:49 -0700235void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
236 EmitR(0, rs, rt, rd, 2, 0x1e);
237}
238
239void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
240 EmitR(0, rs, rt, rd, 3, 0x1e);
241}
242
243void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
244 EmitR(0, rs, rt, rd, 2, 0x1f);
245}
246
247void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
248 EmitR(0, rs, rt, rd, 3, 0x1f);
249}
250
Andreas Gampe57b34292015-01-14 15:45:59 -0800251void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
252 EmitR(0, rs, rt, rd, 0, 0x24);
253}
254
255void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
256 EmitI(0xc, rs, rt, imm16);
257}
258
259void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
260 EmitR(0, rs, rt, rd, 0, 0x25);
261}
262
263void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
264 EmitI(0xd, rs, rt, imm16);
265}
266
267void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
268 EmitR(0, rs, rt, rd, 0, 0x26);
269}
270
271void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
272 EmitI(0xe, rs, rt, imm16);
273}
274
275void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
276 EmitR(0, rs, rt, rd, 0, 0x27);
277}
278
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700279void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
280 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
281}
282
283void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
284 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
285}
286
Alexey Frunze4dda3372015-06-01 18:31:49 -0700287void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
288 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800289}
290
Alexey Frunze4dda3372015-06-01 18:31:49 -0700291void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
292 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800293}
294
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700295void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
296 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
297}
298
299void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
300 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
301}
302
Alexey Frunze4dda3372015-06-01 18:31:49 -0700303void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size_less_one) {
304 DCHECK(0 <= pos && pos < 32) << pos;
305 DCHECK(0 <= size_less_one && size_less_one < 32) << size_less_one;
306 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size_less_one), pos, 3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800307}
308
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700309void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
310 EmitRtd(0x1f, rt, rd, 2, 0x20);
311}
312
313void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
314 DCHECK((-256 <= imm9) && (imm9 < 256));
315 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
316}
317
318void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
319 DCHECK((-256 <= imm9) && (imm9 < 256));
320 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
321}
322
323void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
324 DCHECK((-256 <= imm9) && (imm9 < 256));
325 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
326}
327
328void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
329 DCHECK((-256 <= imm9) && (imm9 < 256));
330 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
331}
332
Alexey Frunze4dda3372015-06-01 18:31:49 -0700333void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
334 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
335}
336
337void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
338 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
339}
340
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700341void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
342 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
343}
344
Alexey Frunze4dda3372015-06-01 18:31:49 -0700345void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
346 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
347}
348
349void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800350 EmitR(0, rs, rt, rd, 0, 0x04);
351}
352
Chris Larsen9aebff22015-09-22 17:54:15 -0700353void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
354 EmitR(0, rs, rt, rd, 1, 0x06);
355}
356
Alexey Frunze4dda3372015-06-01 18:31:49 -0700357void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800358 EmitR(0, rs, rt, rd, 0, 0x06);
359}
360
Alexey Frunze4dda3372015-06-01 18:31:49 -0700361void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800362 EmitR(0, rs, rt, rd, 0, 0x07);
363}
364
Alexey Frunze4dda3372015-06-01 18:31:49 -0700365void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
366 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
367}
368
369void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
370 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
371}
372
Chris Larsen9aebff22015-09-22 17:54:15 -0700373void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
374 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
375}
376
Alexey Frunze4dda3372015-06-01 18:31:49 -0700377void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
378 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
379}
380
381void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
382 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
383}
384
385void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
386 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
387}
388
Chris Larsen9aebff22015-09-22 17:54:15 -0700389void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
390 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
391}
392
Alexey Frunze4dda3372015-06-01 18:31:49 -0700393void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
394 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
395}
396
397void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
398 EmitR(0, rs, rt, rd, 0, 0x14);
399}
400
401void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
402 EmitR(0, rs, rt, rd, 0, 0x16);
403}
404
Chris Larsen9aebff22015-09-22 17:54:15 -0700405void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
406 EmitR(0, rs, rt, rd, 1, 0x16);
407}
408
Alexey Frunze4dda3372015-06-01 18:31:49 -0700409void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
410 EmitR(0, rs, rt, rd, 0, 0x17);
411}
412
Andreas Gampe57b34292015-01-14 15:45:59 -0800413void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
414 EmitI(0x20, rs, rt, imm16);
415}
416
417void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
418 EmitI(0x21, rs, rt, imm16);
419}
420
421void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
422 EmitI(0x23, rs, rt, imm16);
423}
424
425void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
426 EmitI(0x37, rs, rt, imm16);
427}
428
429void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
430 EmitI(0x24, rs, rt, imm16);
431}
432
433void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
434 EmitI(0x25, rs, rt, imm16);
435}
436
Douglas Leungd90957f2015-04-30 19:22:49 -0700437void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
438 EmitI(0x27, rs, rt, imm16);
439}
440
Andreas Gampe57b34292015-01-14 15:45:59 -0800441void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
442 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
443}
444
Alexey Frunze4dda3372015-06-01 18:31:49 -0700445void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
446 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
447}
448
449void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
450 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
451}
452
453void Mips64Assembler::Sync(uint32_t stype) {
454 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
455 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
456}
457
Andreas Gampe57b34292015-01-14 15:45:59 -0800458void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
459 EmitI(0x28, rs, rt, imm16);
460}
461
462void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
463 EmitI(0x29, rs, rt, imm16);
464}
465
466void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
467 EmitI(0x2b, rs, rt, imm16);
468}
469
470void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
471 EmitI(0x3f, rs, rt, imm16);
472}
473
474void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
475 EmitR(0, rs, rt, rd, 0, 0x2a);
476}
477
478void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
479 EmitR(0, rs, rt, rd, 0, 0x2b);
480}
481
482void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
483 EmitI(0xa, rs, rt, imm16);
484}
485
486void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
487 EmitI(0xb, rs, rt, imm16);
488}
489
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700490void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
491 EmitR(0, rs, rt, rd, 0, 0x35);
492}
493
494void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
495 EmitR(0, rs, rt, rd, 0, 0x37);
496}
497
498void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
499 EmitRsd(0, rs, rd, 0x01, 0x10);
500}
501
502void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
503 EmitRsd(0, rs, rd, 0x01, 0x11);
504}
505
506void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
507 EmitRsd(0, rs, rd, 0x01, 0x12);
508}
509
510void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
511 EmitRsd(0, rs, rd, 0x01, 0x13);
512}
513
Alexey Frunze4dda3372015-06-01 18:31:49 -0700514void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
515 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800516}
517
518void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700519 Jalr(RA, rs);
520}
521
522void Mips64Assembler::Jr(GpuRegister rs) {
523 Jalr(ZERO, rs);
524}
525
526void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
527 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
528}
529
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700530void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
531 CHECK(IsUint<19>(imm19)) << imm19;
532 EmitI21(0x3B, rs, imm19);
533}
534
535void Mips64Assembler::Bc(uint32_t imm26) {
536 EmitI26(0x32, imm26);
537}
538
Alexey Frunze4dda3372015-06-01 18:31:49 -0700539void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
540 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
541}
542
543void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
544 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
545}
546
547void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
548 CHECK_NE(rs, ZERO);
549 CHECK_NE(rt, ZERO);
550 CHECK_NE(rs, rt);
551 EmitI(0x17, rs, rt, imm16);
552}
553
554void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
555 CHECK_NE(rt, ZERO);
556 EmitI(0x17, rt, rt, imm16);
557}
558
559void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
560 CHECK_NE(rt, ZERO);
561 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
562}
563
564void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
565 CHECK_NE(rs, ZERO);
566 CHECK_NE(rt, ZERO);
567 CHECK_NE(rs, rt);
568 EmitI(0x16, rs, rt, imm16);
569}
570
571void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
572 CHECK_NE(rt, ZERO);
573 EmitI(0x16, rt, rt, imm16);
574}
575
576void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
577 CHECK_NE(rt, ZERO);
578 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
579}
580
581void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
582 CHECK_NE(rs, ZERO);
583 CHECK_NE(rt, ZERO);
584 CHECK_NE(rs, rt);
585 EmitI(0x7, rs, rt, imm16);
586}
587
588void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
589 CHECK_NE(rs, ZERO);
590 CHECK_NE(rt, ZERO);
591 CHECK_NE(rs, rt);
592 EmitI(0x6, rs, rt, imm16);
593}
594
595void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
596 CHECK_NE(rs, ZERO);
597 CHECK_NE(rt, ZERO);
598 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700599 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700600}
601
602void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
603 CHECK_NE(rs, ZERO);
604 CHECK_NE(rt, ZERO);
605 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700606 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700607}
608
609void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
610 CHECK_NE(rs, ZERO);
611 EmitI21(0x36, rs, imm21);
612}
613
614void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
615 CHECK_NE(rs, ZERO);
616 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800617}
618
Alexey Frunze299a9392015-12-08 16:08:02 -0800619void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
620 EmitFI(0x11, 0x9, ft, imm16);
621}
622
623void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
624 EmitFI(0x11, 0xD, ft, imm16);
625}
626
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700627void Mips64Assembler::EmitBcondc(BranchCondition cond,
628 GpuRegister rs,
629 GpuRegister rt,
630 uint32_t imm16_21) {
631 switch (cond) {
632 case kCondLT:
633 Bltc(rs, rt, imm16_21);
634 break;
635 case kCondGE:
636 Bgec(rs, rt, imm16_21);
637 break;
638 case kCondLE:
639 Bgec(rt, rs, imm16_21);
640 break;
641 case kCondGT:
642 Bltc(rt, rs, imm16_21);
643 break;
644 case kCondLTZ:
645 CHECK_EQ(rt, ZERO);
646 Bltzc(rs, imm16_21);
647 break;
648 case kCondGEZ:
649 CHECK_EQ(rt, ZERO);
650 Bgezc(rs, imm16_21);
651 break;
652 case kCondLEZ:
653 CHECK_EQ(rt, ZERO);
654 Blezc(rs, imm16_21);
655 break;
656 case kCondGTZ:
657 CHECK_EQ(rt, ZERO);
658 Bgtzc(rs, imm16_21);
659 break;
660 case kCondEQ:
661 Beqc(rs, rt, imm16_21);
662 break;
663 case kCondNE:
664 Bnec(rs, rt, imm16_21);
665 break;
666 case kCondEQZ:
667 CHECK_EQ(rt, ZERO);
668 Beqzc(rs, imm16_21);
669 break;
670 case kCondNEZ:
671 CHECK_EQ(rt, ZERO);
672 Bnezc(rs, imm16_21);
673 break;
674 case kCondLTU:
675 Bltuc(rs, rt, imm16_21);
676 break;
677 case kCondGEU:
678 Bgeuc(rs, rt, imm16_21);
679 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800680 case kCondF:
681 CHECK_EQ(rt, ZERO);
682 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
683 break;
684 case kCondT:
685 CHECK_EQ(rt, ZERO);
686 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
687 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700688 case kUncond:
689 LOG(FATAL) << "Unexpected branch condition " << cond;
690 UNREACHABLE();
691 }
692}
693
Andreas Gampe57b34292015-01-14 15:45:59 -0800694void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
695 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
696}
697
698void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
699 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
700}
701
702void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
703 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
704}
705
706void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
707 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
708}
709
710void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700711 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800712}
713
714void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700715 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800716}
717
718void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700719 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800720}
721
722void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700723 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800724}
725
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700726void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
727 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
728}
729
730void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
731 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
732}
733
734void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
735 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
736}
737
738void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
739 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
740}
741
Andreas Gampe57b34292015-01-14 15:45:59 -0800742void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
743 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
744}
745
746void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700747 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
748}
749
750void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
751 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
752}
753
754void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
755 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
756}
757
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700758void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
759 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
760}
761
762void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
763 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
764}
765
766void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
767 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
768}
769
770void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
771 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
772}
773
774void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
775 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
776}
777
778void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
779 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
780}
781
782void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
783 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
784}
785
786void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
787 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
788}
789
790void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
791 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
792}
793
794void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
795 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
796}
797
798void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
799 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
800}
801
802void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
803 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
804}
805
806void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
807 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
808}
809
810void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
811 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
812}
813
814void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
815 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
816}
817
818void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
819 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
820}
821
822void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
823 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
824}
825
826void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
827 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
828}
829
830void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
831 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
832}
833
834void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
835 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
836}
837
838void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
839 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
840}
841
842void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
843 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
844}
845
Alexey Frunze299a9392015-12-08 16:08:02 -0800846void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
847 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
848}
849
850void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
851 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
852}
853
854void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
855 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
856}
857
858void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
859 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
860}
861
862void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
863 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
864}
865
866void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
867 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
868}
869
870void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
871 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
872}
873
874void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
875 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
876}
877
878void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
879 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
880}
881
882void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
883 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
884}
885
886void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
887 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
888}
889
890void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
891 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
892}
893
894void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
895 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
896}
897
898void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
899 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
900}
901
902void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
903 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
904}
905
906void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
907 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
908}
909
910void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
911 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
912}
913
914void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
915 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
916}
917
918void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
919 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
920}
921
922void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
923 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
924}
925
Alexey Frunze4dda3372015-06-01 18:31:49 -0700926void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
927 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
928}
929
930void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
931 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
932}
933
934void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
935 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
936}
937
938void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
939 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800940}
941
Chris Larsen51417632015-10-02 13:24:25 -0700942void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
943 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
944}
945
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700946void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
947 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
948}
949
Andreas Gampe57b34292015-01-14 15:45:59 -0800950void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
951 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
952}
953
Alexey Frunze4dda3372015-06-01 18:31:49 -0700954void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
955 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
956}
957
958void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
959 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
960}
961
962void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
963 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800964}
965
966void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
967 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
968}
969
970void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
971 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
972}
973
974void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
975 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
976}
977
978void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
979 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
980}
981
982void Mips64Assembler::Break() {
983 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
984 static_cast<GpuRegister>(0), 0, 0xD);
985}
986
987void Mips64Assembler::Nop() {
988 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
989 static_cast<GpuRegister>(0), 0, 0x0);
990}
991
Alexey Frunze4dda3372015-06-01 18:31:49 -0700992void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
993 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -0800994}
995
Alexey Frunze4dda3372015-06-01 18:31:49 -0700996void Mips64Assembler::Clear(GpuRegister rd) {
997 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -0800998}
999
Alexey Frunze4dda3372015-06-01 18:31:49 -07001000void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1001 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001002}
1003
Alexey Frunze4dda3372015-06-01 18:31:49 -07001004void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
1005 if (IsUint<16>(value)) {
1006 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1007 Ori(rd, ZERO, value);
1008 } else if (IsInt<16>(value)) {
1009 // Use ADD with (signed) immediate to encode 16b signed int.
1010 Addiu(rd, ZERO, value);
1011 } else {
1012 Lui(rd, value >> 16);
1013 if (value & 0xFFFF)
1014 Ori(rd, rd, value);
1015 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001016}
1017
Alexey Frunze4dda3372015-06-01 18:31:49 -07001018void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
1019 int bit31 = (value & UINT64_C(0x80000000)) != 0;
1020
1021 // Loads with 1 instruction.
1022 if (IsUint<16>(value)) {
1023 Ori(rd, ZERO, value);
1024 } else if (IsInt<16>(value)) {
1025 Daddiu(rd, ZERO, value);
1026 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
1027 Lui(rd, value >> 16);
1028 } else if (IsInt<32>(value)) {
1029 // Loads with 2 instructions.
1030 Lui(rd, value >> 16);
1031 Ori(rd, rd, value);
1032 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
1033 Ori(rd, ZERO, value);
1034 Dahi(rd, value >> 32);
1035 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
1036 Ori(rd, ZERO, value);
1037 Dati(rd, value >> 48);
1038 } else if ((value & 0xFFFF) == 0 &&
1039 (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
1040 Lui(rd, value >> 16);
1041 Dahi(rd, (value >> 32) + bit31);
1042 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
1043 Lui(rd, value >> 16);
1044 Dati(rd, (value >> 48) + bit31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001045 } else if (IsPowerOfTwo(value + UINT64_C(1))) {
1046 int shift_cnt = 64 - CTZ(value + UINT64_C(1));
1047 Daddiu(rd, ZERO, -1);
1048 if (shift_cnt < 32) {
1049 Dsrl(rd, rd, shift_cnt);
1050 } else {
1051 Dsrl32(rd, rd, shift_cnt & 31);
1052 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001053 } else {
1054 int shift_cnt = CTZ(value);
1055 int64_t tmp = value >> shift_cnt;
1056 if (IsUint<16>(tmp)) {
1057 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001058 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001059 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001060 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001061 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001062 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001063 } else if (IsInt<16>(tmp)) {
1064 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001065 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001066 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001067 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001068 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001069 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001070 } else if (IsInt<32>(tmp)) {
1071 // Loads with 3 instructions.
1072 Lui(rd, tmp >> 16);
1073 Ori(rd, rd, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001074 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001075 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001076 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001077 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001078 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001079 } else {
1080 shift_cnt = 16 + CTZ(value >> 16);
1081 tmp = value >> shift_cnt;
1082 if (IsUint<16>(tmp)) {
1083 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001084 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001085 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001086 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001087 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001088 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001089 Ori(rd, rd, value);
1090 } else if (IsInt<16>(tmp)) {
1091 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001092 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001093 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001094 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001095 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001096 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001097 Ori(rd, rd, value);
1098 } else {
1099 // Loads with 3-4 instructions.
1100 uint64_t tmp2 = value;
1101 bool used_lui = false;
1102 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
1103 Lui(rd, tmp2 >> 16);
1104 used_lui = true;
1105 }
1106 if ((tmp2 & 0xFFFF) != 0) {
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001107 if (used_lui) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001108 Ori(rd, rd, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001109 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001110 Ori(rd, ZERO, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001111 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001112 }
1113 if (bit31) {
1114 tmp2 += UINT64_C(0x100000000);
1115 }
1116 if (((tmp2 >> 32) & 0xFFFF) != 0) {
1117 Dahi(rd, tmp2 >> 32);
1118 }
1119 if (tmp2 & UINT64_C(0x800000000000)) {
1120 tmp2 += UINT64_C(0x1000000000000);
1121 }
1122 if ((tmp2 >> 48) != 0) {
1123 Dati(rd, tmp2 >> 48);
1124 }
1125 }
1126 }
1127 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001128}
1129
Alexey Frunze4dda3372015-06-01 18:31:49 -07001130void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1131 if (IsInt<16>(value)) {
1132 Daddiu(rt, rs, value);
1133 } else {
1134 LoadConst64(rtmp, value);
1135 Daddu(rt, rs, rtmp);
1136 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001137}
1138
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001139void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1140 Mips64Assembler::Branch::Type short_type,
1141 Mips64Assembler::Branch::Type long_type) {
1142 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1143}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001144
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001145void Mips64Assembler::Branch::InitializeType(bool is_call) {
1146 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1147 if (is_call) {
1148 InitShortOrLong(offset_size, kCall, kLongCall);
1149 } else if (condition_ == kUncond) {
1150 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1151 } else {
1152 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1153 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1154 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1155 } else {
1156 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1157 }
1158 }
1159 old_type_ = type_;
1160}
1161
1162bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1163 switch (condition) {
1164 case kCondLT:
1165 case kCondGT:
1166 case kCondNE:
1167 case kCondLTU:
1168 return lhs == rhs;
1169 default:
1170 return false;
1171 }
1172}
1173
1174bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1175 GpuRegister lhs,
1176 GpuRegister rhs) {
1177 switch (condition) {
1178 case kUncond:
1179 return true;
1180 case kCondGE:
1181 case kCondLE:
1182 case kCondEQ:
1183 case kCondGEU:
1184 return lhs == rhs;
1185 default:
1186 return false;
1187 }
1188}
1189
1190Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1191 : old_location_(location),
1192 location_(location),
1193 target_(target),
1194 lhs_reg_(ZERO),
1195 rhs_reg_(ZERO),
1196 condition_(kUncond) {
1197 InitializeType(false);
1198}
1199
1200Mips64Assembler::Branch::Branch(uint32_t location,
1201 uint32_t target,
1202 Mips64Assembler::BranchCondition condition,
1203 GpuRegister lhs_reg,
1204 GpuRegister rhs_reg)
1205 : old_location_(location),
1206 location_(location),
1207 target_(target),
1208 lhs_reg_(lhs_reg),
1209 rhs_reg_(rhs_reg),
1210 condition_(condition) {
1211 CHECK_NE(condition, kUncond);
1212 switch (condition) {
1213 case kCondEQ:
1214 case kCondNE:
1215 case kCondLT:
1216 case kCondGE:
1217 case kCondLE:
1218 case kCondGT:
1219 case kCondLTU:
1220 case kCondGEU:
1221 CHECK_NE(lhs_reg, ZERO);
1222 CHECK_NE(rhs_reg, ZERO);
1223 break;
1224 case kCondLTZ:
1225 case kCondGEZ:
1226 case kCondLEZ:
1227 case kCondGTZ:
1228 case kCondEQZ:
1229 case kCondNEZ:
1230 CHECK_NE(lhs_reg, ZERO);
1231 CHECK_EQ(rhs_reg, ZERO);
1232 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001233 case kCondF:
1234 case kCondT:
1235 CHECK_EQ(rhs_reg, ZERO);
1236 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001237 case kUncond:
1238 UNREACHABLE();
1239 }
1240 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1241 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1242 // Branch condition is always true, make the branch unconditional.
1243 condition_ = kUncond;
1244 }
1245 InitializeType(false);
1246}
1247
1248Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1249 : old_location_(location),
1250 location_(location),
1251 target_(target),
1252 lhs_reg_(indirect_reg),
1253 rhs_reg_(ZERO),
1254 condition_(kUncond) {
1255 CHECK_NE(indirect_reg, ZERO);
1256 CHECK_NE(indirect_reg, AT);
1257 InitializeType(true);
1258}
1259
1260Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1261 Mips64Assembler::BranchCondition cond) {
1262 switch (cond) {
1263 case kCondLT:
1264 return kCondGE;
1265 case kCondGE:
1266 return kCondLT;
1267 case kCondLE:
1268 return kCondGT;
1269 case kCondGT:
1270 return kCondLE;
1271 case kCondLTZ:
1272 return kCondGEZ;
1273 case kCondGEZ:
1274 return kCondLTZ;
1275 case kCondLEZ:
1276 return kCondGTZ;
1277 case kCondGTZ:
1278 return kCondLEZ;
1279 case kCondEQ:
1280 return kCondNE;
1281 case kCondNE:
1282 return kCondEQ;
1283 case kCondEQZ:
1284 return kCondNEZ;
1285 case kCondNEZ:
1286 return kCondEQZ;
1287 case kCondLTU:
1288 return kCondGEU;
1289 case kCondGEU:
1290 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001291 case kCondF:
1292 return kCondT;
1293 case kCondT:
1294 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001295 case kUncond:
1296 LOG(FATAL) << "Unexpected branch condition " << cond;
1297 }
1298 UNREACHABLE();
1299}
1300
1301Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1302 return type_;
1303}
1304
1305Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1306 return condition_;
1307}
1308
1309GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1310 return lhs_reg_;
1311}
1312
1313GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1314 return rhs_reg_;
1315}
1316
1317uint32_t Mips64Assembler::Branch::GetTarget() const {
1318 return target_;
1319}
1320
1321uint32_t Mips64Assembler::Branch::GetLocation() const {
1322 return location_;
1323}
1324
1325uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1326 return old_location_;
1327}
1328
1329uint32_t Mips64Assembler::Branch::GetLength() const {
1330 return branch_info_[type_].length;
1331}
1332
1333uint32_t Mips64Assembler::Branch::GetOldLength() const {
1334 return branch_info_[old_type_].length;
1335}
1336
1337uint32_t Mips64Assembler::Branch::GetSize() const {
1338 return GetLength() * sizeof(uint32_t);
1339}
1340
1341uint32_t Mips64Assembler::Branch::GetOldSize() const {
1342 return GetOldLength() * sizeof(uint32_t);
1343}
1344
1345uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1346 return GetLocation() + GetSize();
1347}
1348
1349uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1350 return GetOldLocation() + GetOldSize();
1351}
1352
1353bool Mips64Assembler::Branch::IsLong() const {
1354 switch (type_) {
1355 // Short branches.
1356 case kUncondBranch:
1357 case kCondBranch:
1358 case kCall:
1359 return false;
1360 // Long branches.
1361 case kLongUncondBranch:
1362 case kLongCondBranch:
1363 case kLongCall:
1364 return true;
1365 }
1366 UNREACHABLE();
1367}
1368
1369bool Mips64Assembler::Branch::IsResolved() const {
1370 return target_ != kUnresolved;
1371}
1372
1373Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1374 OffsetBits offset_size =
1375 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1376 ? kOffset23
1377 : branch_info_[type_].offset_size;
1378 return offset_size;
1379}
1380
1381Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1382 uint32_t target) {
1383 // For unresolved targets assume the shortest encoding
1384 // (later it will be made longer if needed).
1385 if (target == kUnresolved)
1386 return kOffset16;
1387 int64_t distance = static_cast<int64_t>(target) - location;
1388 // To simplify calculations in composite branches consisting of multiple instructions
1389 // bump up the distance by a value larger than the max byte size of a composite branch.
1390 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1391 if (IsInt<kOffset16>(distance))
1392 return kOffset16;
1393 else if (IsInt<kOffset18>(distance))
1394 return kOffset18;
1395 else if (IsInt<kOffset21>(distance))
1396 return kOffset21;
1397 else if (IsInt<kOffset23>(distance))
1398 return kOffset23;
1399 else if (IsInt<kOffset28>(distance))
1400 return kOffset28;
1401 return kOffset32;
1402}
1403
1404void Mips64Assembler::Branch::Resolve(uint32_t target) {
1405 target_ = target;
1406}
1407
1408void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1409 if (location_ > expand_location) {
1410 location_ += delta;
1411 }
1412 if (!IsResolved()) {
1413 return; // Don't know the target yet.
1414 }
1415 if (target_ > expand_location) {
1416 target_ += delta;
1417 }
1418}
1419
1420void Mips64Assembler::Branch::PromoteToLong() {
1421 switch (type_) {
1422 // Short branches.
1423 case kUncondBranch:
1424 type_ = kLongUncondBranch;
1425 break;
1426 case kCondBranch:
1427 type_ = kLongCondBranch;
1428 break;
1429 case kCall:
1430 type_ = kLongCall;
1431 break;
1432 default:
1433 // Note: 'type_' is already long.
1434 break;
1435 }
1436 CHECK(IsLong());
1437}
1438
1439uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1440 // If the branch is still unresolved or already long, nothing to do.
1441 if (IsLong() || !IsResolved()) {
1442 return 0;
1443 }
1444 // Promote the short branch to long if the offset size is too small
1445 // to hold the distance between location_ and target_.
1446 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1447 PromoteToLong();
1448 uint32_t old_size = GetOldSize();
1449 uint32_t new_size = GetSize();
1450 CHECK_GT(new_size, old_size);
1451 return new_size - old_size;
1452 }
1453 // The following logic is for debugging/testing purposes.
1454 // Promote some short branches to long when it's not really required.
1455 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1456 int64_t distance = static_cast<int64_t>(target_) - location_;
1457 distance = (distance >= 0) ? distance : -distance;
1458 if (distance >= max_short_distance) {
1459 PromoteToLong();
1460 uint32_t old_size = GetOldSize();
1461 uint32_t new_size = GetSize();
1462 CHECK_GT(new_size, old_size);
1463 return new_size - old_size;
1464 }
1465 }
1466 return 0;
1467}
1468
1469uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1470 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1471}
1472
1473uint32_t Mips64Assembler::Branch::GetOffset() const {
1474 CHECK(IsResolved());
1475 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1476 // Calculate the byte distance between instructions and also account for
1477 // different PC-relative origins.
1478 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1479 // Prepare the offset for encoding into the instruction(s).
1480 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1481 return offset;
1482}
1483
1484Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1485 CHECK_LT(branch_id, branches_.size());
1486 return &branches_[branch_id];
1487}
1488
1489const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1490 CHECK_LT(branch_id, branches_.size());
1491 return &branches_[branch_id];
1492}
1493
1494void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001495 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001496 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001497
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001498 // Walk the list of branches referring to and preceding this label.
1499 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001500 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001501 uint32_t branch_id = label->Position();
1502 Branch* branch = GetBranch(branch_id);
1503 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001504
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001505 uint32_t branch_location = branch->GetLocation();
1506 // Extract the location of the previous branch in the list (walking the list backwards;
1507 // the previous branch ID was stored in the space reserved for this branch).
1508 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001509
1510 // On to the previous branch in the list...
1511 label->position_ = prev;
1512 }
1513
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001514 // Now make the label object contain its own location (relative to the end of the preceding
1515 // branch, if any; it will be used by the branches referring to and following this label).
1516 label->prev_branch_id_plus_one_ = branches_.size();
1517 if (label->prev_branch_id_plus_one_) {
1518 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1519 const Branch* branch = GetBranch(branch_id);
1520 bound_pc -= branch->GetEndLocation();
1521 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001522 label->BindTo(bound_pc);
1523}
1524
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001525uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1526 CHECK(label->IsBound());
1527 uint32_t target = label->Position();
1528 if (label->prev_branch_id_plus_one_) {
1529 // Get label location based on the branch preceding it.
1530 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1531 const Branch* branch = GetBranch(branch_id);
1532 target += branch->GetEndLocation();
1533 }
1534 return target;
1535}
1536
1537uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1538 // We can reconstruct the adjustment by going through all the branches from the beginning
1539 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1540 // with increasing old_position, we can use the data from last AdjustedPosition() to
1541 // continue where we left off and the whole loop should be O(m+n) where m is the number
1542 // of positions to adjust and n is the number of branches.
1543 if (old_position < last_old_position_) {
1544 last_position_adjustment_ = 0;
1545 last_old_position_ = 0;
1546 last_branch_id_ = 0;
1547 }
1548 while (last_branch_id_ != branches_.size()) {
1549 const Branch* branch = GetBranch(last_branch_id_);
1550 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1551 break;
1552 }
1553 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1554 ++last_branch_id_;
1555 }
1556 last_old_position_ = old_position;
1557 return old_position + last_position_adjustment_;
1558}
1559
1560void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1561 uint32_t length = branches_.back().GetLength();
1562 if (!label->IsBound()) {
1563 // Branch forward (to a following label), distance is unknown.
1564 // The first branch forward will contain 0, serving as the terminator of
1565 // the list of forward-reaching branches.
1566 Emit(label->position_);
1567 length--;
1568 // Now make the label object point to this branch
1569 // (this forms a linked list of branches preceding this label).
1570 uint32_t branch_id = branches_.size() - 1;
1571 label->LinkTo(branch_id);
1572 }
1573 // Reserve space for the branch.
1574 while (length--) {
1575 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001576 }
1577}
1578
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001579void Mips64Assembler::Buncond(Mips64Label* label) {
1580 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1581 branches_.emplace_back(buffer_.Size(), target);
1582 FinalizeLabeledBranch(label);
1583}
1584
1585void Mips64Assembler::Bcond(Mips64Label* label,
1586 BranchCondition condition,
1587 GpuRegister lhs,
1588 GpuRegister rhs) {
1589 // If lhs = rhs, this can be a NOP.
1590 if (Branch::IsNop(condition, lhs, rhs)) {
1591 return;
1592 }
1593 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1594 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1595 FinalizeLabeledBranch(label);
1596}
1597
1598void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1599 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1600 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1601 FinalizeLabeledBranch(label);
1602}
1603
1604void Mips64Assembler::PromoteBranches() {
1605 // Promote short branches to long as necessary.
1606 bool changed;
1607 do {
1608 changed = false;
1609 for (auto& branch : branches_) {
1610 CHECK(branch.IsResolved());
1611 uint32_t delta = branch.PromoteIfNeeded();
1612 // If this branch has been promoted and needs to expand in size,
1613 // relocate all branches by the expansion size.
1614 if (delta) {
1615 changed = true;
1616 uint32_t expand_location = branch.GetLocation();
1617 for (auto& branch2 : branches_) {
1618 branch2.Relocate(expand_location, delta);
1619 }
1620 }
1621 }
1622 } while (changed);
1623
1624 // Account for branch expansion by resizing the code buffer
1625 // and moving the code in it to its final location.
1626 size_t branch_count = branches_.size();
1627 if (branch_count > 0) {
1628 // Resize.
1629 Branch& last_branch = branches_[branch_count - 1];
1630 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1631 uint32_t old_size = buffer_.Size();
1632 buffer_.Resize(old_size + size_delta);
1633 // Move the code residing between branch placeholders.
1634 uint32_t end = old_size;
1635 for (size_t i = branch_count; i > 0; ) {
1636 Branch& branch = branches_[--i];
1637 uint32_t size = end - branch.GetOldEndLocation();
1638 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1639 end = branch.GetOldLocation();
1640 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001641 }
1642}
1643
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001644// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1645const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1646 // Short branches.
1647 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1648 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1649 // Exception: kOffset23 for beqzc/bnezc
1650 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1651 // Long branches.
1652 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1653 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1654 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1655};
1656
1657// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1658void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1659 CHECK(overwriting_);
1660 overwrite_location_ = branch->GetLocation();
1661 uint32_t offset = branch->GetOffset();
1662 BranchCondition condition = branch->GetCondition();
1663 GpuRegister lhs = branch->GetLeftRegister();
1664 GpuRegister rhs = branch->GetRightRegister();
1665 switch (branch->GetType()) {
1666 // Short branches.
1667 case Branch::kUncondBranch:
1668 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1669 Bc(offset);
1670 break;
1671 case Branch::kCondBranch:
1672 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1673 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001674 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001675 break;
1676 case Branch::kCall:
1677 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1678 Addiupc(lhs, offset);
1679 Jialc(lhs, 0);
1680 break;
1681
1682 // Long branches.
1683 case Branch::kLongUncondBranch:
1684 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1685 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1686 Auipc(AT, High16Bits(offset));
1687 Jic(AT, Low16Bits(offset));
1688 break;
1689 case Branch::kLongCondBranch:
1690 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1691 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1692 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1693 Auipc(AT, High16Bits(offset));
1694 Jic(AT, Low16Bits(offset));
1695 break;
1696 case Branch::kLongCall:
1697 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1698 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1699 Auipc(lhs, High16Bits(offset));
1700 Daddiu(lhs, lhs, Low16Bits(offset));
1701 Jialc(lhs, 0);
1702 break;
1703 }
1704 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1705 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001706}
1707
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001708void Mips64Assembler::Bc(Mips64Label* label) {
1709 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001710}
1711
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001712void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1713 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001714}
1715
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001716void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1717 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001718}
1719
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001720void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1721 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001722}
1723
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001724void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1725 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001726}
1727
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001728void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1729 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001730}
1731
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001732void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1733 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001734}
1735
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001736void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1737 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001738}
1739
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001740void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1741 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001742}
1743
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001744void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1745 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001746}
1747
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001748void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1749 Bcond(label, kCondEQ, rs, rt);
1750}
1751
1752void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1753 Bcond(label, kCondNE, rs, rt);
1754}
1755
1756void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1757 Bcond(label, kCondEQZ, rs);
1758}
1759
1760void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1761 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001762}
1763
Alexey Frunze299a9392015-12-08 16:08:02 -08001764void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1765 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1766}
1767
1768void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1769 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1770}
1771
Andreas Gampe57b34292015-01-14 15:45:59 -08001772void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1773 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001774 if (!IsInt<16>(offset)) {
1775 LoadConst32(AT, offset);
1776 Daddu(AT, AT, base);
1777 base = AT;
1778 offset = 0;
1779 }
1780
Andreas Gampe57b34292015-01-14 15:45:59 -08001781 switch (type) {
1782 case kLoadSignedByte:
1783 Lb(reg, base, offset);
1784 break;
1785 case kLoadUnsignedByte:
1786 Lbu(reg, base, offset);
1787 break;
1788 case kLoadSignedHalfword:
1789 Lh(reg, base, offset);
1790 break;
1791 case kLoadUnsignedHalfword:
1792 Lhu(reg, base, offset);
1793 break;
1794 case kLoadWord:
1795 Lw(reg, base, offset);
1796 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001797 case kLoadUnsignedWord:
1798 Lwu(reg, base, offset);
1799 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001800 case kLoadDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001801 Ld(reg, base, offset);
1802 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001803 }
1804}
1805
1806void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1807 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001808 if (!IsInt<16>(offset)) {
1809 LoadConst32(AT, offset);
1810 Daddu(AT, AT, base);
1811 base = AT;
1812 offset = 0;
1813 }
1814
Andreas Gampe57b34292015-01-14 15:45:59 -08001815 switch (type) {
1816 case kLoadWord:
1817 Lwc1(reg, base, offset);
1818 break;
1819 case kLoadDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001820 Ldc1(reg, base, offset);
1821 break;
1822 default:
1823 LOG(FATAL) << "UNREACHABLE";
1824 }
1825}
1826
1827void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1828 size_t size) {
1829 Mips64ManagedRegister dst = m_dst.AsMips64();
1830 if (dst.IsNoRegister()) {
1831 CHECK_EQ(0u, size) << dst;
1832 } else if (dst.IsGpuRegister()) {
1833 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001834 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1835 } else if (size == 8) {
1836 CHECK_EQ(8u, size) << dst;
1837 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1838 } else {
1839 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1840 }
1841 } else if (dst.IsFpuRegister()) {
1842 if (size == 4) {
1843 CHECK_EQ(4u, size) << dst;
1844 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1845 } else if (size == 8) {
1846 CHECK_EQ(8u, size) << dst;
1847 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1848 } else {
1849 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1850 }
1851 }
1852}
1853
1854void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1855 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001856 if (!IsInt<16>(offset)) {
1857 LoadConst32(AT, offset);
1858 Daddu(AT, AT, base);
1859 base = AT;
1860 offset = 0;
1861 }
1862
Andreas Gampe57b34292015-01-14 15:45:59 -08001863 switch (type) {
1864 case kStoreByte:
1865 Sb(reg, base, offset);
1866 break;
1867 case kStoreHalfword:
1868 Sh(reg, base, offset);
1869 break;
1870 case kStoreWord:
1871 Sw(reg, base, offset);
1872 break;
1873 case kStoreDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001874 Sd(reg, base, offset);
1875 break;
1876 default:
1877 LOG(FATAL) << "UNREACHABLE";
1878 }
1879}
1880
1881void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1882 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001883 if (!IsInt<16>(offset)) {
1884 LoadConst32(AT, offset);
1885 Daddu(AT, AT, base);
1886 base = AT;
1887 offset = 0;
1888 }
1889
Andreas Gampe57b34292015-01-14 15:45:59 -08001890 switch (type) {
1891 case kStoreWord:
1892 Swc1(reg, base, offset);
1893 break;
1894 case kStoreDoubleword:
1895 Sdc1(reg, base, offset);
1896 break;
1897 default:
1898 LOG(FATAL) << "UNREACHABLE";
1899 }
1900}
1901
David Srbeckydd973932015-04-07 20:29:48 +01001902static dwarf::Reg DWARFReg(GpuRegister reg) {
1903 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1904}
1905
Andreas Gampe57b34292015-01-14 15:45:59 -08001906constexpr size_t kFramePointerSize = 8;
1907
1908void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
1909 const std::vector<ManagedRegister>& callee_save_regs,
1910 const ManagedRegisterEntrySpills& entry_spills) {
1911 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001912 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001913
1914 // Increase frame to required size.
1915 IncreaseFrameSize(frame_size);
1916
1917 // Push callee saves and return address
1918 int stack_offset = frame_size - kFramePointerSize;
1919 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001920 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001921 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1922 stack_offset -= kFramePointerSize;
1923 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
1924 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001925 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001926 }
1927
1928 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001929 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001930
1931 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001932 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08001933 for (size_t i = 0; i < entry_spills.size(); ++i) {
1934 Mips64ManagedRegister reg = entry_spills.at(i).AsMips64();
1935 ManagedRegisterSpill spill = entry_spills.at(i);
1936 int32_t size = spill.getSize();
1937 if (reg.IsNoRegister()) {
1938 // only increment stack offset.
1939 offset += size;
1940 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001941 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1942 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001943 offset += size;
1944 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001945 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1946 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001947 offset += size;
1948 }
1949 }
1950}
1951
1952void Mips64Assembler::RemoveFrame(size_t frame_size,
1953 const std::vector<ManagedRegister>& callee_save_regs) {
1954 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001955 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01001956 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08001957
1958 // Pop callee saves and return address
1959 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
1960 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
1961 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
1962 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001963 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08001964 stack_offset += kFramePointerSize;
1965 }
1966 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001967 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08001968
1969 // Decrease frame to required size.
1970 DecreaseFrameSize(frame_size);
1971
1972 // Then jump to the return address.
1973 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001974 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01001975
1976 // The CFI should be restored for any code that follows the exit block.
1977 cfi_.RestoreState();
1978 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08001979}
1980
1981void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001982 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001983 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001984 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001985 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001986}
1987
1988void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001989 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001990 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001991 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001992 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001993}
1994
1995void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
1996 Mips64ManagedRegister src = msrc.AsMips64();
1997 if (src.IsNoRegister()) {
1998 CHECK_EQ(0u, size);
1999 } else if (src.IsGpuRegister()) {
2000 CHECK(size == 4 || size == 8) << size;
2001 if (size == 8) {
2002 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2003 } else if (size == 4) {
2004 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2005 } else {
2006 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2007 }
2008 } else if (src.IsFpuRegister()) {
2009 CHECK(size == 4 || size == 8) << size;
2010 if (size == 8) {
2011 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2012 } else if (size == 4) {
2013 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2014 } else {
2015 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2016 }
2017 }
2018}
2019
2020void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2021 Mips64ManagedRegister src = msrc.AsMips64();
2022 CHECK(src.IsGpuRegister());
2023 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2024}
2025
2026void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2027 Mips64ManagedRegister src = msrc.AsMips64();
2028 CHECK(src.IsGpuRegister());
2029 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2030}
2031
2032void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2033 ManagedRegister mscratch) {
2034 Mips64ManagedRegister scratch = mscratch.AsMips64();
2035 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002036 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002037 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2038}
2039
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002040void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002041 FrameOffset fr_offs,
2042 ManagedRegister mscratch) {
2043 Mips64ManagedRegister scratch = mscratch.AsMips64();
2044 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002045 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002046 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2047}
2048
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002049void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002050 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2051}
2052
2053void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2054 FrameOffset in_off, ManagedRegister mscratch) {
2055 Mips64ManagedRegister src = msrc.AsMips64();
2056 Mips64ManagedRegister scratch = mscratch.AsMips64();
2057 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2058 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2059 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2060}
2061
2062void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2063 return EmitLoad(mdest, SP, src.Int32Value(), size);
2064}
2065
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002066void Mips64Assembler::LoadFromThread64(ManagedRegister mdest,
2067 ThreadOffset<kMipsDoublewordSize> src,
2068 size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002069 return EmitLoad(mdest, S1, src.Int32Value(), size);
2070}
2071
2072void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2073 Mips64ManagedRegister dest = mdest.AsMips64();
2074 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002075 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002076}
2077
Mathieu Chartiere401d142015-04-22 13:56:20 -07002078void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002079 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002080 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002081 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2082 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002083 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002084 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002085 // TODO: review
2086 // Negate the 32-bit ref
2087 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2088 // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
2089 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 31);
Andreas Gampe57b34292015-01-14 15:45:59 -08002090 }
2091}
2092
2093void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002094 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002095 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002096 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002097 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2098 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2099}
2100
2101void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002102 ThreadOffset<kMipsDoublewordSize> offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002103 Mips64ManagedRegister dest = mdest.AsMips64();
2104 CHECK(dest.IsGpuRegister());
2105 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2106}
2107
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002108void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2109 size_t size ATTRIBUTE_UNUSED) {
2110 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002111}
2112
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002113void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2114 size_t size ATTRIBUTE_UNUSED) {
2115 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002116}
2117
2118void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2119 Mips64ManagedRegister dest = mdest.AsMips64();
2120 Mips64ManagedRegister src = msrc.AsMips64();
2121 if (!dest.Equals(src)) {
2122 if (dest.IsGpuRegister()) {
2123 CHECK(src.IsGpuRegister()) << src;
2124 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2125 } else if (dest.IsFpuRegister()) {
2126 CHECK(src.IsFpuRegister()) << src;
2127 if (size == 4) {
2128 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2129 } else if (size == 8) {
2130 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2131 } else {
2132 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2133 }
2134 }
2135 }
2136}
2137
2138void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2139 ManagedRegister mscratch) {
2140 Mips64ManagedRegister scratch = mscratch.AsMips64();
2141 CHECK(scratch.IsGpuRegister()) << scratch;
2142 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2143 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2144}
2145
2146void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002147 ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002148 ManagedRegister mscratch) {
2149 Mips64ManagedRegister scratch = mscratch.AsMips64();
2150 CHECK(scratch.IsGpuRegister()) << scratch;
2151 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2152 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2153}
2154
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002155void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002156 FrameOffset fr_offs,
2157 ManagedRegister mscratch) {
2158 Mips64ManagedRegister scratch = mscratch.AsMips64();
2159 CHECK(scratch.IsGpuRegister()) << scratch;
2160 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2161 SP, fr_offs.Int32Value());
2162 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2163 S1, thr_offs.Int32Value());
2164}
2165
2166void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2167 ManagedRegister mscratch, size_t size) {
2168 Mips64ManagedRegister scratch = mscratch.AsMips64();
2169 CHECK(scratch.IsGpuRegister()) << scratch;
2170 CHECK(size == 4 || size == 8) << size;
2171 if (size == 4) {
2172 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002173 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002174 } else if (size == 8) {
2175 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2176 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2177 } else {
2178 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2179 }
2180}
2181
2182void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002183 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002184 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2185 CHECK(size == 4 || size == 8) << size;
2186 if (size == 4) {
2187 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2188 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002189 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002190 } else if (size == 8) {
2191 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2192 src_offset.Int32Value());
2193 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2194 } else {
2195 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2196 }
2197}
2198
2199void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002200 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002201 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2202 CHECK(size == 4 || size == 8) << size;
2203 if (size == 4) {
2204 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002205 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002206 dest_offset.Int32Value());
2207 } else if (size == 8) {
2208 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2209 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2210 dest_offset.Int32Value());
2211 } else {
2212 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2213 }
2214}
2215
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002216void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2217 FrameOffset src_base 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
2224void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002225 ManagedRegister src, Offset src_offset,
2226 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002227 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2228 CHECK(size == 4 || size == 8) << size;
2229 if (size == 4) {
2230 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002231 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002232 } else if (size == 8) {
2233 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2234 src_offset.Int32Value());
2235 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2236 dest_offset.Int32Value());
2237 } else {
2238 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2239 }
2240}
2241
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002242void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2243 Offset dest_offset ATTRIBUTE_UNUSED,
2244 FrameOffset src ATTRIBUTE_UNUSED,
2245 Offset src_offset ATTRIBUTE_UNUSED,
2246 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2247 size_t size ATTRIBUTE_UNUSED) {
2248 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002249}
2250
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002251void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002252 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002253 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002254}
2255
2256void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002257 FrameOffset handle_scope_offset,
2258 ManagedRegister min_reg,
2259 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002260 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2261 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2262 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2263 CHECK(out_reg.IsGpuRegister()) << out_reg;
2264 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002265 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002266 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2267 // the address in the handle scope holding the reference.
2268 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2269 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002270 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002271 SP, handle_scope_offset.Int32Value());
2272 in_reg = out_reg;
2273 }
2274 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002275 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002277 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2278 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2279 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002280 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002281 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002282 }
2283}
2284
2285void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002286 FrameOffset handle_scope_offset,
2287 ManagedRegister mscratch,
2288 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002289 Mips64ManagedRegister scratch = mscratch.AsMips64();
2290 CHECK(scratch.IsGpuRegister()) << scratch;
2291 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002292 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002293 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002294 handle_scope_offset.Int32Value());
2295 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2296 // the address in the handle scope holding the reference.
2297 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002298 Beqzc(scratch.AsGpuRegister(), &null_arg);
2299 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2300 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002301 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002302 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002303 }
2304 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2305}
2306
2307// Given a handle scope entry, load the associated reference.
2308void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002309 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002310 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2311 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2312 CHECK(out_reg.IsGpuRegister()) << out_reg;
2313 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002314 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002315 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002316 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002317 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002318 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002319 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2320 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002321 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002322}
2323
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002324void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2325 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002326 // TODO: not validating references
2327}
2328
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002329void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2330 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002331 // TODO: not validating references
2332}
2333
2334void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2335 Mips64ManagedRegister base = mbase.AsMips64();
2336 Mips64ManagedRegister scratch = mscratch.AsMips64();
2337 CHECK(base.IsGpuRegister()) << base;
2338 CHECK(scratch.IsGpuRegister()) << scratch;
2339 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2340 base.AsGpuRegister(), offset.Int32Value());
2341 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002342 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002343 // TODO: place reference map on call
2344}
2345
2346void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2347 Mips64ManagedRegister scratch = mscratch.AsMips64();
2348 CHECK(scratch.IsGpuRegister()) << scratch;
2349 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002350 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002351 SP, base.Int32Value());
2352 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2353 scratch.AsGpuRegister(), offset.Int32Value());
2354 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002355 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002356 // TODO: place reference map on call
2357}
2358
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002359void Mips64Assembler::CallFromThread64(ThreadOffset<kMipsDoublewordSize> offset ATTRIBUTE_UNUSED,
2360 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2361 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002362}
2363
2364void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2365 Move(tr.AsMips64().AsGpuRegister(), S1);
2366}
2367
2368void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002369 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002370 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2371}
2372
2373void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2374 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002375 exception_blocks_.emplace_back(scratch, stack_adjust);
2376 LoadFromOffset(kLoadDoubleword,
2377 scratch.AsGpuRegister(),
2378 S1,
2379 Thread::ExceptionOffset<kMipsDoublewordSize>().Int32Value());
2380 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002381}
2382
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002383void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2384 Bind(exception->Entry());
2385 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2386 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002387 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002388 // Pass exception object as argument.
2389 // Don't care about preserving A0 as this call won't return.
2390 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2391 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002392 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002393 LoadFromOffset(kLoadDoubleword,
2394 T9,
2395 S1,
2396 QUICK_ENTRYPOINT_OFFSET(kMipsDoublewordSize, pDeliverException).Int32Value());
2397 Jr(T9);
2398 Nop();
2399
Andreas Gampe57b34292015-01-14 15:45:59 -08002400 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002401 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002402}
2403
2404} // namespace mips64
2405} // namespace art