blob: f9ff2df8bb4deef9f528452550dfbe3e2f8b7286 [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
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800774void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
775 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
776}
777
778void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
779 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
780}
781
782void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
783 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
784}
785
786void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
787 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
788}
789
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700790void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
791 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
792}
793
794void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
795 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
796}
797
798void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
799 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
800}
801
802void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
803 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
804}
805
806void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
807 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
808}
809
810void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
811 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
812}
813
814void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
815 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
816}
817
818void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
819 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
820}
821
822void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
823 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
824}
825
826void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
827 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
828}
829
830void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
831 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
832}
833
834void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
835 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
836}
837
838void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
839 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
840}
841
842void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
843 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
844}
845
846void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
847 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
848}
849
850void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
851 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
852}
853
854void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
855 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
856}
857
858void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
859 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
860}
861
Alexey Frunze299a9392015-12-08 16:08:02 -0800862void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
863 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
864}
865
866void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
867 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
868}
869
870void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
871 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
872}
873
874void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
875 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
876}
877
878void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
879 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
880}
881
882void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
883 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
884}
885
886void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
887 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
888}
889
890void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
891 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
892}
893
894void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
895 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
896}
897
898void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
899 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
900}
901
902void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
903 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
904}
905
906void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
907 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
908}
909
910void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
911 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
912}
913
914void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
915 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
916}
917
918void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
919 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
920}
921
922void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
923 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
924}
925
926void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
927 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
928}
929
930void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
931 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
932}
933
934void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
935 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
936}
937
938void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
939 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
940}
941
Alexey Frunze4dda3372015-06-01 18:31:49 -0700942void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
943 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
944}
945
946void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
947 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
948}
949
950void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
951 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
952}
953
954void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
955 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800956}
957
Chris Larsen51417632015-10-02 13:24:25 -0700958void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
959 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
960}
961
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700962void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
963 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
964}
965
Andreas Gampe57b34292015-01-14 15:45:59 -0800966void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
967 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
968}
969
Alexey Frunze4dda3372015-06-01 18:31:49 -0700970void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
971 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
972}
973
974void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
975 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
976}
977
978void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
979 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800980}
981
982void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
983 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
984}
985
986void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
987 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
988}
989
990void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
991 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
992}
993
994void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
995 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
996}
997
998void Mips64Assembler::Break() {
999 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1000 static_cast<GpuRegister>(0), 0, 0xD);
1001}
1002
1003void Mips64Assembler::Nop() {
1004 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1005 static_cast<GpuRegister>(0), 0, 0x0);
1006}
1007
Alexey Frunze4dda3372015-06-01 18:31:49 -07001008void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1009 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001010}
1011
Alexey Frunze4dda3372015-06-01 18:31:49 -07001012void Mips64Assembler::Clear(GpuRegister rd) {
1013 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001014}
1015
Alexey Frunze4dda3372015-06-01 18:31:49 -07001016void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1017 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001018}
1019
Alexey Frunze4dda3372015-06-01 18:31:49 -07001020void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
1021 if (IsUint<16>(value)) {
1022 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1023 Ori(rd, ZERO, value);
1024 } else if (IsInt<16>(value)) {
1025 // Use ADD with (signed) immediate to encode 16b signed int.
1026 Addiu(rd, ZERO, value);
1027 } else {
1028 Lui(rd, value >> 16);
1029 if (value & 0xFFFF)
1030 Ori(rd, rd, value);
1031 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001032}
1033
Alexey Frunze4dda3372015-06-01 18:31:49 -07001034void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
1035 int bit31 = (value & UINT64_C(0x80000000)) != 0;
1036
1037 // Loads with 1 instruction.
1038 if (IsUint<16>(value)) {
1039 Ori(rd, ZERO, value);
1040 } else if (IsInt<16>(value)) {
1041 Daddiu(rd, ZERO, value);
1042 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
1043 Lui(rd, value >> 16);
1044 } else if (IsInt<32>(value)) {
1045 // Loads with 2 instructions.
1046 Lui(rd, value >> 16);
1047 Ori(rd, rd, value);
1048 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
1049 Ori(rd, ZERO, value);
1050 Dahi(rd, value >> 32);
1051 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
1052 Ori(rd, ZERO, value);
1053 Dati(rd, value >> 48);
1054 } else if ((value & 0xFFFF) == 0 &&
1055 (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
1056 Lui(rd, value >> 16);
1057 Dahi(rd, (value >> 32) + bit31);
1058 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
1059 Lui(rd, value >> 16);
1060 Dati(rd, (value >> 48) + bit31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001061 } else if (IsPowerOfTwo(value + UINT64_C(1))) {
1062 int shift_cnt = 64 - CTZ(value + UINT64_C(1));
1063 Daddiu(rd, ZERO, -1);
1064 if (shift_cnt < 32) {
1065 Dsrl(rd, rd, shift_cnt);
1066 } else {
1067 Dsrl32(rd, rd, shift_cnt & 31);
1068 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001069 } else {
1070 int shift_cnt = CTZ(value);
1071 int64_t tmp = value >> shift_cnt;
1072 if (IsUint<16>(tmp)) {
1073 Ori(rd, ZERO, 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 if (IsInt<16>(tmp)) {
1080 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001081 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001082 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001083 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001084 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001085 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001086 } else if (IsInt<32>(tmp)) {
1087 // Loads with 3 instructions.
1088 Lui(rd, tmp >> 16);
1089 Ori(rd, rd, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001090 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001091 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001092 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001093 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001094 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001095 } else {
1096 shift_cnt = 16 + CTZ(value >> 16);
1097 tmp = value >> shift_cnt;
1098 if (IsUint<16>(tmp)) {
1099 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001100 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001101 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001102 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001103 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001104 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001105 Ori(rd, rd, value);
1106 } else if (IsInt<16>(tmp)) {
1107 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001108 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001109 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001110 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001111 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001112 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001113 Ori(rd, rd, value);
1114 } else {
1115 // Loads with 3-4 instructions.
1116 uint64_t tmp2 = value;
1117 bool used_lui = false;
1118 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
1119 Lui(rd, tmp2 >> 16);
1120 used_lui = true;
1121 }
1122 if ((tmp2 & 0xFFFF) != 0) {
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001123 if (used_lui) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001124 Ori(rd, rd, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001125 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001126 Ori(rd, ZERO, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001127 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001128 }
1129 if (bit31) {
1130 tmp2 += UINT64_C(0x100000000);
1131 }
1132 if (((tmp2 >> 32) & 0xFFFF) != 0) {
1133 Dahi(rd, tmp2 >> 32);
1134 }
1135 if (tmp2 & UINT64_C(0x800000000000)) {
1136 tmp2 += UINT64_C(0x1000000000000);
1137 }
1138 if ((tmp2 >> 48) != 0) {
1139 Dati(rd, tmp2 >> 48);
1140 }
1141 }
1142 }
1143 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001144}
1145
Alexey Frunze4dda3372015-06-01 18:31:49 -07001146void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1147 if (IsInt<16>(value)) {
1148 Daddiu(rt, rs, value);
1149 } else {
1150 LoadConst64(rtmp, value);
1151 Daddu(rt, rs, rtmp);
1152 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001153}
1154
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001155void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1156 Mips64Assembler::Branch::Type short_type,
1157 Mips64Assembler::Branch::Type long_type) {
1158 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1159}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001160
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001161void Mips64Assembler::Branch::InitializeType(bool is_call) {
1162 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1163 if (is_call) {
1164 InitShortOrLong(offset_size, kCall, kLongCall);
1165 } else if (condition_ == kUncond) {
1166 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1167 } else {
1168 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1169 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1170 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1171 } else {
1172 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1173 }
1174 }
1175 old_type_ = type_;
1176}
1177
1178bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1179 switch (condition) {
1180 case kCondLT:
1181 case kCondGT:
1182 case kCondNE:
1183 case kCondLTU:
1184 return lhs == rhs;
1185 default:
1186 return false;
1187 }
1188}
1189
1190bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1191 GpuRegister lhs,
1192 GpuRegister rhs) {
1193 switch (condition) {
1194 case kUncond:
1195 return true;
1196 case kCondGE:
1197 case kCondLE:
1198 case kCondEQ:
1199 case kCondGEU:
1200 return lhs == rhs;
1201 default:
1202 return false;
1203 }
1204}
1205
1206Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1207 : old_location_(location),
1208 location_(location),
1209 target_(target),
1210 lhs_reg_(ZERO),
1211 rhs_reg_(ZERO),
1212 condition_(kUncond) {
1213 InitializeType(false);
1214}
1215
1216Mips64Assembler::Branch::Branch(uint32_t location,
1217 uint32_t target,
1218 Mips64Assembler::BranchCondition condition,
1219 GpuRegister lhs_reg,
1220 GpuRegister rhs_reg)
1221 : old_location_(location),
1222 location_(location),
1223 target_(target),
1224 lhs_reg_(lhs_reg),
1225 rhs_reg_(rhs_reg),
1226 condition_(condition) {
1227 CHECK_NE(condition, kUncond);
1228 switch (condition) {
1229 case kCondEQ:
1230 case kCondNE:
1231 case kCondLT:
1232 case kCondGE:
1233 case kCondLE:
1234 case kCondGT:
1235 case kCondLTU:
1236 case kCondGEU:
1237 CHECK_NE(lhs_reg, ZERO);
1238 CHECK_NE(rhs_reg, ZERO);
1239 break;
1240 case kCondLTZ:
1241 case kCondGEZ:
1242 case kCondLEZ:
1243 case kCondGTZ:
1244 case kCondEQZ:
1245 case kCondNEZ:
1246 CHECK_NE(lhs_reg, ZERO);
1247 CHECK_EQ(rhs_reg, ZERO);
1248 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001249 case kCondF:
1250 case kCondT:
1251 CHECK_EQ(rhs_reg, ZERO);
1252 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001253 case kUncond:
1254 UNREACHABLE();
1255 }
1256 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1257 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1258 // Branch condition is always true, make the branch unconditional.
1259 condition_ = kUncond;
1260 }
1261 InitializeType(false);
1262}
1263
1264Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1265 : old_location_(location),
1266 location_(location),
1267 target_(target),
1268 lhs_reg_(indirect_reg),
1269 rhs_reg_(ZERO),
1270 condition_(kUncond) {
1271 CHECK_NE(indirect_reg, ZERO);
1272 CHECK_NE(indirect_reg, AT);
1273 InitializeType(true);
1274}
1275
1276Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1277 Mips64Assembler::BranchCondition cond) {
1278 switch (cond) {
1279 case kCondLT:
1280 return kCondGE;
1281 case kCondGE:
1282 return kCondLT;
1283 case kCondLE:
1284 return kCondGT;
1285 case kCondGT:
1286 return kCondLE;
1287 case kCondLTZ:
1288 return kCondGEZ;
1289 case kCondGEZ:
1290 return kCondLTZ;
1291 case kCondLEZ:
1292 return kCondGTZ;
1293 case kCondGTZ:
1294 return kCondLEZ;
1295 case kCondEQ:
1296 return kCondNE;
1297 case kCondNE:
1298 return kCondEQ;
1299 case kCondEQZ:
1300 return kCondNEZ;
1301 case kCondNEZ:
1302 return kCondEQZ;
1303 case kCondLTU:
1304 return kCondGEU;
1305 case kCondGEU:
1306 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001307 case kCondF:
1308 return kCondT;
1309 case kCondT:
1310 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001311 case kUncond:
1312 LOG(FATAL) << "Unexpected branch condition " << cond;
1313 }
1314 UNREACHABLE();
1315}
1316
1317Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1318 return type_;
1319}
1320
1321Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1322 return condition_;
1323}
1324
1325GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1326 return lhs_reg_;
1327}
1328
1329GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1330 return rhs_reg_;
1331}
1332
1333uint32_t Mips64Assembler::Branch::GetTarget() const {
1334 return target_;
1335}
1336
1337uint32_t Mips64Assembler::Branch::GetLocation() const {
1338 return location_;
1339}
1340
1341uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1342 return old_location_;
1343}
1344
1345uint32_t Mips64Assembler::Branch::GetLength() const {
1346 return branch_info_[type_].length;
1347}
1348
1349uint32_t Mips64Assembler::Branch::GetOldLength() const {
1350 return branch_info_[old_type_].length;
1351}
1352
1353uint32_t Mips64Assembler::Branch::GetSize() const {
1354 return GetLength() * sizeof(uint32_t);
1355}
1356
1357uint32_t Mips64Assembler::Branch::GetOldSize() const {
1358 return GetOldLength() * sizeof(uint32_t);
1359}
1360
1361uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1362 return GetLocation() + GetSize();
1363}
1364
1365uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1366 return GetOldLocation() + GetOldSize();
1367}
1368
1369bool Mips64Assembler::Branch::IsLong() const {
1370 switch (type_) {
1371 // Short branches.
1372 case kUncondBranch:
1373 case kCondBranch:
1374 case kCall:
1375 return false;
1376 // Long branches.
1377 case kLongUncondBranch:
1378 case kLongCondBranch:
1379 case kLongCall:
1380 return true;
1381 }
1382 UNREACHABLE();
1383}
1384
1385bool Mips64Assembler::Branch::IsResolved() const {
1386 return target_ != kUnresolved;
1387}
1388
1389Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1390 OffsetBits offset_size =
1391 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1392 ? kOffset23
1393 : branch_info_[type_].offset_size;
1394 return offset_size;
1395}
1396
1397Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1398 uint32_t target) {
1399 // For unresolved targets assume the shortest encoding
1400 // (later it will be made longer if needed).
1401 if (target == kUnresolved)
1402 return kOffset16;
1403 int64_t distance = static_cast<int64_t>(target) - location;
1404 // To simplify calculations in composite branches consisting of multiple instructions
1405 // bump up the distance by a value larger than the max byte size of a composite branch.
1406 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1407 if (IsInt<kOffset16>(distance))
1408 return kOffset16;
1409 else if (IsInt<kOffset18>(distance))
1410 return kOffset18;
1411 else if (IsInt<kOffset21>(distance))
1412 return kOffset21;
1413 else if (IsInt<kOffset23>(distance))
1414 return kOffset23;
1415 else if (IsInt<kOffset28>(distance))
1416 return kOffset28;
1417 return kOffset32;
1418}
1419
1420void Mips64Assembler::Branch::Resolve(uint32_t target) {
1421 target_ = target;
1422}
1423
1424void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1425 if (location_ > expand_location) {
1426 location_ += delta;
1427 }
1428 if (!IsResolved()) {
1429 return; // Don't know the target yet.
1430 }
1431 if (target_ > expand_location) {
1432 target_ += delta;
1433 }
1434}
1435
1436void Mips64Assembler::Branch::PromoteToLong() {
1437 switch (type_) {
1438 // Short branches.
1439 case kUncondBranch:
1440 type_ = kLongUncondBranch;
1441 break;
1442 case kCondBranch:
1443 type_ = kLongCondBranch;
1444 break;
1445 case kCall:
1446 type_ = kLongCall;
1447 break;
1448 default:
1449 // Note: 'type_' is already long.
1450 break;
1451 }
1452 CHECK(IsLong());
1453}
1454
1455uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1456 // If the branch is still unresolved or already long, nothing to do.
1457 if (IsLong() || !IsResolved()) {
1458 return 0;
1459 }
1460 // Promote the short branch to long if the offset size is too small
1461 // to hold the distance between location_ and target_.
1462 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1463 PromoteToLong();
1464 uint32_t old_size = GetOldSize();
1465 uint32_t new_size = GetSize();
1466 CHECK_GT(new_size, old_size);
1467 return new_size - old_size;
1468 }
1469 // The following logic is for debugging/testing purposes.
1470 // Promote some short branches to long when it's not really required.
1471 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1472 int64_t distance = static_cast<int64_t>(target_) - location_;
1473 distance = (distance >= 0) ? distance : -distance;
1474 if (distance >= max_short_distance) {
1475 PromoteToLong();
1476 uint32_t old_size = GetOldSize();
1477 uint32_t new_size = GetSize();
1478 CHECK_GT(new_size, old_size);
1479 return new_size - old_size;
1480 }
1481 }
1482 return 0;
1483}
1484
1485uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1486 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1487}
1488
1489uint32_t Mips64Assembler::Branch::GetOffset() const {
1490 CHECK(IsResolved());
1491 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1492 // Calculate the byte distance between instructions and also account for
1493 // different PC-relative origins.
1494 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1495 // Prepare the offset for encoding into the instruction(s).
1496 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1497 return offset;
1498}
1499
1500Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1501 CHECK_LT(branch_id, branches_.size());
1502 return &branches_[branch_id];
1503}
1504
1505const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1506 CHECK_LT(branch_id, branches_.size());
1507 return &branches_[branch_id];
1508}
1509
1510void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001511 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001512 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001513
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001514 // Walk the list of branches referring to and preceding this label.
1515 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001516 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001517 uint32_t branch_id = label->Position();
1518 Branch* branch = GetBranch(branch_id);
1519 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001520
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001521 uint32_t branch_location = branch->GetLocation();
1522 // Extract the location of the previous branch in the list (walking the list backwards;
1523 // the previous branch ID was stored in the space reserved for this branch).
1524 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001525
1526 // On to the previous branch in the list...
1527 label->position_ = prev;
1528 }
1529
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001530 // Now make the label object contain its own location (relative to the end of the preceding
1531 // branch, if any; it will be used by the branches referring to and following this label).
1532 label->prev_branch_id_plus_one_ = branches_.size();
1533 if (label->prev_branch_id_plus_one_) {
1534 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1535 const Branch* branch = GetBranch(branch_id);
1536 bound_pc -= branch->GetEndLocation();
1537 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001538 label->BindTo(bound_pc);
1539}
1540
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001541uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1542 CHECK(label->IsBound());
1543 uint32_t target = label->Position();
1544 if (label->prev_branch_id_plus_one_) {
1545 // Get label location based on the branch preceding it.
1546 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1547 const Branch* branch = GetBranch(branch_id);
1548 target += branch->GetEndLocation();
1549 }
1550 return target;
1551}
1552
1553uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1554 // We can reconstruct the adjustment by going through all the branches from the beginning
1555 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1556 // with increasing old_position, we can use the data from last AdjustedPosition() to
1557 // continue where we left off and the whole loop should be O(m+n) where m is the number
1558 // of positions to adjust and n is the number of branches.
1559 if (old_position < last_old_position_) {
1560 last_position_adjustment_ = 0;
1561 last_old_position_ = 0;
1562 last_branch_id_ = 0;
1563 }
1564 while (last_branch_id_ != branches_.size()) {
1565 const Branch* branch = GetBranch(last_branch_id_);
1566 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1567 break;
1568 }
1569 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1570 ++last_branch_id_;
1571 }
1572 last_old_position_ = old_position;
1573 return old_position + last_position_adjustment_;
1574}
1575
1576void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1577 uint32_t length = branches_.back().GetLength();
1578 if (!label->IsBound()) {
1579 // Branch forward (to a following label), distance is unknown.
1580 // The first branch forward will contain 0, serving as the terminator of
1581 // the list of forward-reaching branches.
1582 Emit(label->position_);
1583 length--;
1584 // Now make the label object point to this branch
1585 // (this forms a linked list of branches preceding this label).
1586 uint32_t branch_id = branches_.size() - 1;
1587 label->LinkTo(branch_id);
1588 }
1589 // Reserve space for the branch.
1590 while (length--) {
1591 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001592 }
1593}
1594
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001595void Mips64Assembler::Buncond(Mips64Label* label) {
1596 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1597 branches_.emplace_back(buffer_.Size(), target);
1598 FinalizeLabeledBranch(label);
1599}
1600
1601void Mips64Assembler::Bcond(Mips64Label* label,
1602 BranchCondition condition,
1603 GpuRegister lhs,
1604 GpuRegister rhs) {
1605 // If lhs = rhs, this can be a NOP.
1606 if (Branch::IsNop(condition, lhs, rhs)) {
1607 return;
1608 }
1609 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1610 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1611 FinalizeLabeledBranch(label);
1612}
1613
1614void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1615 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1616 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1617 FinalizeLabeledBranch(label);
1618}
1619
1620void Mips64Assembler::PromoteBranches() {
1621 // Promote short branches to long as necessary.
1622 bool changed;
1623 do {
1624 changed = false;
1625 for (auto& branch : branches_) {
1626 CHECK(branch.IsResolved());
1627 uint32_t delta = branch.PromoteIfNeeded();
1628 // If this branch has been promoted and needs to expand in size,
1629 // relocate all branches by the expansion size.
1630 if (delta) {
1631 changed = true;
1632 uint32_t expand_location = branch.GetLocation();
1633 for (auto& branch2 : branches_) {
1634 branch2.Relocate(expand_location, delta);
1635 }
1636 }
1637 }
1638 } while (changed);
1639
1640 // Account for branch expansion by resizing the code buffer
1641 // and moving the code in it to its final location.
1642 size_t branch_count = branches_.size();
1643 if (branch_count > 0) {
1644 // Resize.
1645 Branch& last_branch = branches_[branch_count - 1];
1646 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1647 uint32_t old_size = buffer_.Size();
1648 buffer_.Resize(old_size + size_delta);
1649 // Move the code residing between branch placeholders.
1650 uint32_t end = old_size;
1651 for (size_t i = branch_count; i > 0; ) {
1652 Branch& branch = branches_[--i];
1653 uint32_t size = end - branch.GetOldEndLocation();
1654 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1655 end = branch.GetOldLocation();
1656 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001657 }
1658}
1659
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001660// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1661const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1662 // Short branches.
1663 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1664 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1665 // Exception: kOffset23 for beqzc/bnezc
1666 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1667 // Long branches.
1668 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1669 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1670 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1671};
1672
1673// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1674void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1675 CHECK(overwriting_);
1676 overwrite_location_ = branch->GetLocation();
1677 uint32_t offset = branch->GetOffset();
1678 BranchCondition condition = branch->GetCondition();
1679 GpuRegister lhs = branch->GetLeftRegister();
1680 GpuRegister rhs = branch->GetRightRegister();
1681 switch (branch->GetType()) {
1682 // Short branches.
1683 case Branch::kUncondBranch:
1684 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1685 Bc(offset);
1686 break;
1687 case Branch::kCondBranch:
1688 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1689 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001690 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001691 break;
1692 case Branch::kCall:
1693 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1694 Addiupc(lhs, offset);
1695 Jialc(lhs, 0);
1696 break;
1697
1698 // Long branches.
1699 case Branch::kLongUncondBranch:
1700 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1701 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1702 Auipc(AT, High16Bits(offset));
1703 Jic(AT, Low16Bits(offset));
1704 break;
1705 case Branch::kLongCondBranch:
1706 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1707 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1708 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1709 Auipc(AT, High16Bits(offset));
1710 Jic(AT, Low16Bits(offset));
1711 break;
1712 case Branch::kLongCall:
1713 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1714 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1715 Auipc(lhs, High16Bits(offset));
1716 Daddiu(lhs, lhs, Low16Bits(offset));
1717 Jialc(lhs, 0);
1718 break;
1719 }
1720 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1721 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001722}
1723
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001724void Mips64Assembler::Bc(Mips64Label* label) {
1725 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001726}
1727
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001728void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1729 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001730}
1731
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001732void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1733 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001734}
1735
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001736void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1737 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001738}
1739
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001740void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1741 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001742}
1743
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001744void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1745 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001746}
1747
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001748void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1749 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001750}
1751
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001752void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1753 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001754}
1755
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001756void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1757 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001758}
1759
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001760void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1761 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001762}
1763
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001764void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1765 Bcond(label, kCondEQ, rs, rt);
1766}
1767
1768void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1769 Bcond(label, kCondNE, rs, rt);
1770}
1771
1772void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1773 Bcond(label, kCondEQZ, rs);
1774}
1775
1776void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1777 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001778}
1779
Alexey Frunze299a9392015-12-08 16:08:02 -08001780void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1781 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1782}
1783
1784void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1785 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1786}
1787
Andreas Gampe57b34292015-01-14 15:45:59 -08001788void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1789 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001790 if (!IsInt<16>(offset)) {
1791 LoadConst32(AT, offset);
1792 Daddu(AT, AT, base);
1793 base = AT;
1794 offset = 0;
1795 }
1796
Andreas Gampe57b34292015-01-14 15:45:59 -08001797 switch (type) {
1798 case kLoadSignedByte:
1799 Lb(reg, base, offset);
1800 break;
1801 case kLoadUnsignedByte:
1802 Lbu(reg, base, offset);
1803 break;
1804 case kLoadSignedHalfword:
1805 Lh(reg, base, offset);
1806 break;
1807 case kLoadUnsignedHalfword:
1808 Lhu(reg, base, offset);
1809 break;
1810 case kLoadWord:
1811 Lw(reg, base, offset);
1812 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001813 case kLoadUnsignedWord:
1814 Lwu(reg, base, offset);
1815 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001816 case kLoadDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001817 Ld(reg, base, offset);
1818 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001819 }
1820}
1821
1822void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1823 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001824 if (!IsInt<16>(offset)) {
1825 LoadConst32(AT, offset);
1826 Daddu(AT, AT, base);
1827 base = AT;
1828 offset = 0;
1829 }
1830
Andreas Gampe57b34292015-01-14 15:45:59 -08001831 switch (type) {
1832 case kLoadWord:
1833 Lwc1(reg, base, offset);
1834 break;
1835 case kLoadDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001836 Ldc1(reg, base, offset);
1837 break;
1838 default:
1839 LOG(FATAL) << "UNREACHABLE";
1840 }
1841}
1842
1843void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1844 size_t size) {
1845 Mips64ManagedRegister dst = m_dst.AsMips64();
1846 if (dst.IsNoRegister()) {
1847 CHECK_EQ(0u, size) << dst;
1848 } else if (dst.IsGpuRegister()) {
1849 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001850 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1851 } else if (size == 8) {
1852 CHECK_EQ(8u, size) << dst;
1853 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1854 } else {
1855 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1856 }
1857 } else if (dst.IsFpuRegister()) {
1858 if (size == 4) {
1859 CHECK_EQ(4u, size) << dst;
1860 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1861 } else if (size == 8) {
1862 CHECK_EQ(8u, size) << dst;
1863 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1864 } else {
1865 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1866 }
1867 }
1868}
1869
1870void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1871 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001872 if (!IsInt<16>(offset)) {
1873 LoadConst32(AT, offset);
1874 Daddu(AT, AT, base);
1875 base = AT;
1876 offset = 0;
1877 }
1878
Andreas Gampe57b34292015-01-14 15:45:59 -08001879 switch (type) {
1880 case kStoreByte:
1881 Sb(reg, base, offset);
1882 break;
1883 case kStoreHalfword:
1884 Sh(reg, base, offset);
1885 break;
1886 case kStoreWord:
1887 Sw(reg, base, offset);
1888 break;
1889 case kStoreDoubleword:
Andreas Gampe57b34292015-01-14 15:45:59 -08001890 Sd(reg, base, offset);
1891 break;
1892 default:
1893 LOG(FATAL) << "UNREACHABLE";
1894 }
1895}
1896
1897void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1898 int32_t offset) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001899 if (!IsInt<16>(offset)) {
1900 LoadConst32(AT, offset);
1901 Daddu(AT, AT, base);
1902 base = AT;
1903 offset = 0;
1904 }
1905
Andreas Gampe57b34292015-01-14 15:45:59 -08001906 switch (type) {
1907 case kStoreWord:
1908 Swc1(reg, base, offset);
1909 break;
1910 case kStoreDoubleword:
1911 Sdc1(reg, base, offset);
1912 break;
1913 default:
1914 LOG(FATAL) << "UNREACHABLE";
1915 }
1916}
1917
David Srbeckydd973932015-04-07 20:29:48 +01001918static dwarf::Reg DWARFReg(GpuRegister reg) {
1919 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1920}
1921
Andreas Gampe57b34292015-01-14 15:45:59 -08001922constexpr size_t kFramePointerSize = 8;
1923
1924void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
1925 const std::vector<ManagedRegister>& callee_save_regs,
1926 const ManagedRegisterEntrySpills& entry_spills) {
1927 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001928 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001929
1930 // Increase frame to required size.
1931 IncreaseFrameSize(frame_size);
1932
1933 // Push callee saves and return address
1934 int stack_offset = frame_size - kFramePointerSize;
1935 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001936 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001937 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1938 stack_offset -= kFramePointerSize;
1939 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
1940 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001941 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001942 }
1943
1944 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001945 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001946
1947 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001948 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08001949 for (size_t i = 0; i < entry_spills.size(); ++i) {
1950 Mips64ManagedRegister reg = entry_spills.at(i).AsMips64();
1951 ManagedRegisterSpill spill = entry_spills.at(i);
1952 int32_t size = spill.getSize();
1953 if (reg.IsNoRegister()) {
1954 // only increment stack offset.
1955 offset += size;
1956 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001957 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1958 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001959 offset += size;
1960 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001961 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1962 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001963 offset += size;
1964 }
1965 }
1966}
1967
1968void Mips64Assembler::RemoveFrame(size_t frame_size,
1969 const std::vector<ManagedRegister>& callee_save_regs) {
1970 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001971 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01001972 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08001973
1974 // Pop callee saves and return address
1975 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
1976 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
1977 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
1978 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001979 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08001980 stack_offset += kFramePointerSize;
1981 }
1982 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001983 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08001984
1985 // Decrease frame to required size.
1986 DecreaseFrameSize(frame_size);
1987
1988 // Then jump to the return address.
1989 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001990 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01001991
1992 // The CFI should be restored for any code that follows the exit block.
1993 cfi_.RestoreState();
1994 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08001995}
1996
1997void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001998 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001999 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002000 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002001 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002002}
2003
2004void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002005 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002006 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002007 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002008 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002009}
2010
2011void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2012 Mips64ManagedRegister src = msrc.AsMips64();
2013 if (src.IsNoRegister()) {
2014 CHECK_EQ(0u, size);
2015 } else if (src.IsGpuRegister()) {
2016 CHECK(size == 4 || size == 8) << size;
2017 if (size == 8) {
2018 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2019 } else if (size == 4) {
2020 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2021 } else {
2022 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2023 }
2024 } else if (src.IsFpuRegister()) {
2025 CHECK(size == 4 || size == 8) << size;
2026 if (size == 8) {
2027 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2028 } else if (size == 4) {
2029 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2030 } else {
2031 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2032 }
2033 }
2034}
2035
2036void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2037 Mips64ManagedRegister src = msrc.AsMips64();
2038 CHECK(src.IsGpuRegister());
2039 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2040}
2041
2042void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2043 Mips64ManagedRegister src = msrc.AsMips64();
2044 CHECK(src.IsGpuRegister());
2045 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2046}
2047
2048void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2049 ManagedRegister mscratch) {
2050 Mips64ManagedRegister scratch = mscratch.AsMips64();
2051 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002052 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002053 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2054}
2055
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002056void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002057 FrameOffset fr_offs,
2058 ManagedRegister mscratch) {
2059 Mips64ManagedRegister scratch = mscratch.AsMips64();
2060 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002061 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002062 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2063}
2064
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002065void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002066 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2067}
2068
2069void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2070 FrameOffset in_off, ManagedRegister mscratch) {
2071 Mips64ManagedRegister src = msrc.AsMips64();
2072 Mips64ManagedRegister scratch = mscratch.AsMips64();
2073 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2074 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2075 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2076}
2077
2078void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2079 return EmitLoad(mdest, SP, src.Int32Value(), size);
2080}
2081
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002082void Mips64Assembler::LoadFromThread64(ManagedRegister mdest,
2083 ThreadOffset<kMipsDoublewordSize> src,
2084 size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002085 return EmitLoad(mdest, S1, src.Int32Value(), size);
2086}
2087
2088void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2089 Mips64ManagedRegister dest = mdest.AsMips64();
2090 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002091 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002092}
2093
Mathieu Chartiere401d142015-04-22 13:56:20 -07002094void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002095 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002096 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002097 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2098 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002099 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002100 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002101 // TODO: review
2102 // Negate the 32-bit ref
2103 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2104 // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
2105 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 31);
Andreas Gampe57b34292015-01-14 15:45:59 -08002106 }
2107}
2108
2109void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002110 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002111 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002112 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002113 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2114 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2115}
2116
2117void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002118 ThreadOffset<kMipsDoublewordSize> offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002119 Mips64ManagedRegister dest = mdest.AsMips64();
2120 CHECK(dest.IsGpuRegister());
2121 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2122}
2123
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002124void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2125 size_t size ATTRIBUTE_UNUSED) {
2126 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002127}
2128
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002129void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2130 size_t size ATTRIBUTE_UNUSED) {
2131 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002132}
2133
2134void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2135 Mips64ManagedRegister dest = mdest.AsMips64();
2136 Mips64ManagedRegister src = msrc.AsMips64();
2137 if (!dest.Equals(src)) {
2138 if (dest.IsGpuRegister()) {
2139 CHECK(src.IsGpuRegister()) << src;
2140 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2141 } else if (dest.IsFpuRegister()) {
2142 CHECK(src.IsFpuRegister()) << src;
2143 if (size == 4) {
2144 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2145 } else if (size == 8) {
2146 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2147 } else {
2148 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2149 }
2150 }
2151 }
2152}
2153
2154void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2155 ManagedRegister mscratch) {
2156 Mips64ManagedRegister scratch = mscratch.AsMips64();
2157 CHECK(scratch.IsGpuRegister()) << scratch;
2158 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2159 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2160}
2161
2162void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002163 ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002164 ManagedRegister mscratch) {
2165 Mips64ManagedRegister scratch = mscratch.AsMips64();
2166 CHECK(scratch.IsGpuRegister()) << scratch;
2167 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2168 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2169}
2170
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002171void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002172 FrameOffset fr_offs,
2173 ManagedRegister mscratch) {
2174 Mips64ManagedRegister scratch = mscratch.AsMips64();
2175 CHECK(scratch.IsGpuRegister()) << scratch;
2176 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2177 SP, fr_offs.Int32Value());
2178 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2179 S1, thr_offs.Int32Value());
2180}
2181
2182void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2183 ManagedRegister mscratch, size_t size) {
2184 Mips64ManagedRegister scratch = mscratch.AsMips64();
2185 CHECK(scratch.IsGpuRegister()) << scratch;
2186 CHECK(size == 4 || size == 8) << size;
2187 if (size == 4) {
2188 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002189 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002190 } else if (size == 8) {
2191 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2192 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2193 } else {
2194 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2195 }
2196}
2197
2198void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002199 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002200 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2201 CHECK(size == 4 || size == 8) << size;
2202 if (size == 4) {
2203 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2204 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002205 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002206 } else if (size == 8) {
2207 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2208 src_offset.Int32Value());
2209 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2210 } else {
2211 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2212 }
2213}
2214
2215void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002216 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002217 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2218 CHECK(size == 4 || size == 8) << size;
2219 if (size == 4) {
2220 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002221 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002222 dest_offset.Int32Value());
2223 } else if (size == 8) {
2224 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2225 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2226 dest_offset.Int32Value());
2227 } else {
2228 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2229 }
2230}
2231
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002232void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2233 FrameOffset src_base ATTRIBUTE_UNUSED,
2234 Offset src_offset ATTRIBUTE_UNUSED,
2235 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2236 size_t size ATTRIBUTE_UNUSED) {
2237 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002238}
2239
2240void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002241 ManagedRegister src, Offset src_offset,
2242 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002243 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2244 CHECK(size == 4 || size == 8) << size;
2245 if (size == 4) {
2246 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002247 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002248 } else if (size == 8) {
2249 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2250 src_offset.Int32Value());
2251 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2252 dest_offset.Int32Value());
2253 } else {
2254 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2255 }
2256}
2257
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002258void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2259 Offset dest_offset ATTRIBUTE_UNUSED,
2260 FrameOffset src ATTRIBUTE_UNUSED,
2261 Offset src_offset ATTRIBUTE_UNUSED,
2262 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2263 size_t size ATTRIBUTE_UNUSED) {
2264 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002265}
2266
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002267void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002268 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002269 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002270}
2271
2272void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002273 FrameOffset handle_scope_offset,
2274 ManagedRegister min_reg,
2275 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2277 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2278 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2279 CHECK(out_reg.IsGpuRegister()) << out_reg;
2280 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002281 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002282 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2283 // the address in the handle scope holding the reference.
2284 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2285 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002286 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002287 SP, handle_scope_offset.Int32Value());
2288 in_reg = out_reg;
2289 }
2290 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002291 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002292 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002293 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2294 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2295 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002296 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002297 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002298 }
2299}
2300
2301void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002302 FrameOffset handle_scope_offset,
2303 ManagedRegister mscratch,
2304 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002305 Mips64ManagedRegister scratch = mscratch.AsMips64();
2306 CHECK(scratch.IsGpuRegister()) << scratch;
2307 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002308 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002309 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002310 handle_scope_offset.Int32Value());
2311 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2312 // the address in the handle scope holding the reference.
2313 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002314 Beqzc(scratch.AsGpuRegister(), &null_arg);
2315 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2316 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002317 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002318 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002319 }
2320 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2321}
2322
2323// Given a handle scope entry, load the associated reference.
2324void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002325 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002326 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2327 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2328 CHECK(out_reg.IsGpuRegister()) << out_reg;
2329 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002330 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002331 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002332 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002333 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002334 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002335 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2336 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002337 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002338}
2339
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002340void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2341 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002342 // TODO: not validating references
2343}
2344
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002345void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2346 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002347 // TODO: not validating references
2348}
2349
2350void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2351 Mips64ManagedRegister base = mbase.AsMips64();
2352 Mips64ManagedRegister scratch = mscratch.AsMips64();
2353 CHECK(base.IsGpuRegister()) << base;
2354 CHECK(scratch.IsGpuRegister()) << scratch;
2355 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2356 base.AsGpuRegister(), offset.Int32Value());
2357 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002358 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002359 // TODO: place reference map on call
2360}
2361
2362void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2363 Mips64ManagedRegister scratch = mscratch.AsMips64();
2364 CHECK(scratch.IsGpuRegister()) << scratch;
2365 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002366 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002367 SP, base.Int32Value());
2368 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2369 scratch.AsGpuRegister(), offset.Int32Value());
2370 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002371 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002372 // TODO: place reference map on call
2373}
2374
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002375void Mips64Assembler::CallFromThread64(ThreadOffset<kMipsDoublewordSize> offset ATTRIBUTE_UNUSED,
2376 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2377 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002378}
2379
2380void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2381 Move(tr.AsMips64().AsGpuRegister(), S1);
2382}
2383
2384void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002385 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002386 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2387}
2388
2389void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2390 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002391 exception_blocks_.emplace_back(scratch, stack_adjust);
2392 LoadFromOffset(kLoadDoubleword,
2393 scratch.AsGpuRegister(),
2394 S1,
2395 Thread::ExceptionOffset<kMipsDoublewordSize>().Int32Value());
2396 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002397}
2398
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002399void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2400 Bind(exception->Entry());
2401 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2402 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002403 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002404 // Pass exception object as argument.
2405 // Don't care about preserving A0 as this call won't return.
2406 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2407 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002408 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002409 LoadFromOffset(kLoadDoubleword,
2410 T9,
2411 S1,
2412 QUICK_ENTRYPOINT_OFFSET(kMipsDoublewordSize, pDeliverException).Int32Value());
2413 Jr(T9);
2414 Nop();
2415
Andreas Gampe57b34292015-01-14 15:45:59 -08002416 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002417 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002418}
2419
2420} // namespace mips64
2421} // namespace art