blob: 447ede5166be6dc1ccf4f0381d5117a820f513d1 [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
Lazar Trsicd9672662015-09-03 17:33:01 +0200303void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
304 CHECK(IsUint<5>(pos)) << pos;
305 CHECK(IsUint<5>(size - 1)) << size;
306 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
307}
308
309void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
310 CHECK(IsUint<5>(pos - 32)) << pos;
311 CHECK(IsUint<5>(size - 1)) << size;
312 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
313 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800314}
315
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700316void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
317 EmitRtd(0x1f, rt, rd, 2, 0x20);
318}
319
320void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200321 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700322 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
323}
324
325void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200326 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700327 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
328}
329
330void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200331 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700332 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
333}
334
335void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200336 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700337 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
338}
339
Alexey Frunze4dda3372015-06-01 18:31:49 -0700340void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
341 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
342}
343
344void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
345 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
346}
347
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700348void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
349 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
350}
351
Alexey Frunze4dda3372015-06-01 18:31:49 -0700352void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
353 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
354}
355
356void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800357 EmitR(0, rs, rt, rd, 0, 0x04);
358}
359
Chris Larsen9aebff22015-09-22 17:54:15 -0700360void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
361 EmitR(0, rs, rt, rd, 1, 0x06);
362}
363
Alexey Frunze4dda3372015-06-01 18:31:49 -0700364void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800365 EmitR(0, rs, rt, rd, 0, 0x06);
366}
367
Alexey Frunze4dda3372015-06-01 18:31:49 -0700368void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800369 EmitR(0, rs, rt, rd, 0, 0x07);
370}
371
Alexey Frunze4dda3372015-06-01 18:31:49 -0700372void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
373 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
374}
375
376void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
377 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
378}
379
Chris Larsen9aebff22015-09-22 17:54:15 -0700380void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
381 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
382}
383
Alexey Frunze4dda3372015-06-01 18:31:49 -0700384void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
385 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
386}
387
388void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
389 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
390}
391
392void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
393 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
394}
395
Chris Larsen9aebff22015-09-22 17:54:15 -0700396void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
397 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
398}
399
Alexey Frunze4dda3372015-06-01 18:31:49 -0700400void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
401 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
402}
403
404void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
405 EmitR(0, rs, rt, rd, 0, 0x14);
406}
407
408void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
409 EmitR(0, rs, rt, rd, 0, 0x16);
410}
411
Chris Larsen9aebff22015-09-22 17:54:15 -0700412void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
413 EmitR(0, rs, rt, rd, 1, 0x16);
414}
415
Alexey Frunze4dda3372015-06-01 18:31:49 -0700416void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
417 EmitR(0, rs, rt, rd, 0, 0x17);
418}
419
Andreas Gampe57b34292015-01-14 15:45:59 -0800420void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
421 EmitI(0x20, rs, rt, imm16);
422}
423
424void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
425 EmitI(0x21, rs, rt, imm16);
426}
427
428void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
429 EmitI(0x23, rs, rt, imm16);
430}
431
432void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
433 EmitI(0x37, rs, rt, imm16);
434}
435
436void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
437 EmitI(0x24, rs, rt, imm16);
438}
439
440void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
441 EmitI(0x25, rs, rt, imm16);
442}
443
Douglas Leungd90957f2015-04-30 19:22:49 -0700444void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
445 EmitI(0x27, rs, rt, imm16);
446}
447
Andreas Gampe57b34292015-01-14 15:45:59 -0800448void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
449 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
450}
451
Alexey Frunze4dda3372015-06-01 18:31:49 -0700452void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
453 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
454}
455
456void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
457 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
458}
459
460void Mips64Assembler::Sync(uint32_t stype) {
461 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
462 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
463}
464
Andreas Gampe57b34292015-01-14 15:45:59 -0800465void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
466 EmitI(0x28, rs, rt, imm16);
467}
468
469void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
470 EmitI(0x29, rs, rt, imm16);
471}
472
473void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
474 EmitI(0x2b, rs, rt, imm16);
475}
476
477void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
478 EmitI(0x3f, rs, rt, imm16);
479}
480
481void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
482 EmitR(0, rs, rt, rd, 0, 0x2a);
483}
484
485void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
486 EmitR(0, rs, rt, rd, 0, 0x2b);
487}
488
489void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
490 EmitI(0xa, rs, rt, imm16);
491}
492
493void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
494 EmitI(0xb, rs, rt, imm16);
495}
496
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700497void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
498 EmitR(0, rs, rt, rd, 0, 0x35);
499}
500
501void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
502 EmitR(0, rs, rt, rd, 0, 0x37);
503}
504
505void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
506 EmitRsd(0, rs, rd, 0x01, 0x10);
507}
508
509void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
510 EmitRsd(0, rs, rd, 0x01, 0x11);
511}
512
513void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
514 EmitRsd(0, rs, rd, 0x01, 0x12);
515}
516
517void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
518 EmitRsd(0, rs, rd, 0x01, 0x13);
519}
520
Alexey Frunze4dda3372015-06-01 18:31:49 -0700521void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
522 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800523}
524
525void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700526 Jalr(RA, rs);
527}
528
529void Mips64Assembler::Jr(GpuRegister rs) {
530 Jalr(ZERO, rs);
531}
532
533void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
534 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
535}
536
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700537void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
538 CHECK(IsUint<19>(imm19)) << imm19;
539 EmitI21(0x3B, rs, imm19);
540}
541
542void Mips64Assembler::Bc(uint32_t imm26) {
543 EmitI26(0x32, imm26);
544}
545
Alexey Frunze4dda3372015-06-01 18:31:49 -0700546void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
547 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
548}
549
550void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
551 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
552}
553
554void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
555 CHECK_NE(rs, ZERO);
556 CHECK_NE(rt, ZERO);
557 CHECK_NE(rs, rt);
558 EmitI(0x17, rs, rt, imm16);
559}
560
561void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
562 CHECK_NE(rt, ZERO);
563 EmitI(0x17, rt, rt, imm16);
564}
565
566void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
567 CHECK_NE(rt, ZERO);
568 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
569}
570
571void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
572 CHECK_NE(rs, ZERO);
573 CHECK_NE(rt, ZERO);
574 CHECK_NE(rs, rt);
575 EmitI(0x16, rs, rt, imm16);
576}
577
578void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
579 CHECK_NE(rt, ZERO);
580 EmitI(0x16, rt, rt, imm16);
581}
582
583void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
584 CHECK_NE(rt, ZERO);
585 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
586}
587
588void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
589 CHECK_NE(rs, ZERO);
590 CHECK_NE(rt, ZERO);
591 CHECK_NE(rs, rt);
592 EmitI(0x7, rs, rt, imm16);
593}
594
595void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
596 CHECK_NE(rs, ZERO);
597 CHECK_NE(rt, ZERO);
598 CHECK_NE(rs, rt);
599 EmitI(0x6, rs, rt, imm16);
600}
601
602void Mips64Assembler::Beqc(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(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700607}
608
609void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
610 CHECK_NE(rs, ZERO);
611 CHECK_NE(rt, ZERO);
612 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700613 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700614}
615
616void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
617 CHECK_NE(rs, ZERO);
618 EmitI21(0x36, rs, imm21);
619}
620
621void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
622 CHECK_NE(rs, ZERO);
623 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800624}
625
Alexey Frunze299a9392015-12-08 16:08:02 -0800626void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
627 EmitFI(0x11, 0x9, ft, imm16);
628}
629
630void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
631 EmitFI(0x11, 0xD, ft, imm16);
632}
633
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700634void Mips64Assembler::EmitBcondc(BranchCondition cond,
635 GpuRegister rs,
636 GpuRegister rt,
637 uint32_t imm16_21) {
638 switch (cond) {
639 case kCondLT:
640 Bltc(rs, rt, imm16_21);
641 break;
642 case kCondGE:
643 Bgec(rs, rt, imm16_21);
644 break;
645 case kCondLE:
646 Bgec(rt, rs, imm16_21);
647 break;
648 case kCondGT:
649 Bltc(rt, rs, imm16_21);
650 break;
651 case kCondLTZ:
652 CHECK_EQ(rt, ZERO);
653 Bltzc(rs, imm16_21);
654 break;
655 case kCondGEZ:
656 CHECK_EQ(rt, ZERO);
657 Bgezc(rs, imm16_21);
658 break;
659 case kCondLEZ:
660 CHECK_EQ(rt, ZERO);
661 Blezc(rs, imm16_21);
662 break;
663 case kCondGTZ:
664 CHECK_EQ(rt, ZERO);
665 Bgtzc(rs, imm16_21);
666 break;
667 case kCondEQ:
668 Beqc(rs, rt, imm16_21);
669 break;
670 case kCondNE:
671 Bnec(rs, rt, imm16_21);
672 break;
673 case kCondEQZ:
674 CHECK_EQ(rt, ZERO);
675 Beqzc(rs, imm16_21);
676 break;
677 case kCondNEZ:
678 CHECK_EQ(rt, ZERO);
679 Bnezc(rs, imm16_21);
680 break;
681 case kCondLTU:
682 Bltuc(rs, rt, imm16_21);
683 break;
684 case kCondGEU:
685 Bgeuc(rs, rt, imm16_21);
686 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800687 case kCondF:
688 CHECK_EQ(rt, ZERO);
689 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
690 break;
691 case kCondT:
692 CHECK_EQ(rt, ZERO);
693 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
694 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700695 case kUncond:
696 LOG(FATAL) << "Unexpected branch condition " << cond;
697 UNREACHABLE();
698 }
699}
700
Andreas Gampe57b34292015-01-14 15:45:59 -0800701void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
702 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
703}
704
705void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
706 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
707}
708
709void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
710 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
711}
712
713void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
714 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
715}
716
717void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700718 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800719}
720
721void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700722 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800723}
724
725void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700726 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800727}
728
729void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700730 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800731}
732
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700733void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
734 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
735}
736
737void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
738 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
739}
740
741void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
742 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
743}
744
745void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
746 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
747}
748
Andreas Gampe57b34292015-01-14 15:45:59 -0800749void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
750 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
751}
752
753void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700754 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
755}
756
757void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
758 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
759}
760
761void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
762 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
763}
764
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700765void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
766 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
767}
768
769void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
770 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
771}
772
773void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
774 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
775}
776
777void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
778 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
779}
780
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800781void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
782 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
783}
784
785void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
786 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
787}
788
789void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
790 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
791}
792
793void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
794 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
795}
796
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700797void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
798 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
799}
800
801void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
802 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
803}
804
805void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
806 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
807}
808
809void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
810 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
811}
812
813void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
814 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
815}
816
817void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
818 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
819}
820
821void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
822 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
823}
824
825void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
826 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
827}
828
829void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
830 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
831}
832
833void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
834 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
835}
836
837void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
838 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
839}
840
841void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
842 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
843}
844
845void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
846 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
847}
848
849void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
850 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
851}
852
853void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
854 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
855}
856
857void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
858 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
859}
860
861void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
862 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
863}
864
865void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
866 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
867}
868
Alexey Frunze299a9392015-12-08 16:08:02 -0800869void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
870 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
871}
872
873void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
874 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
875}
876
877void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
878 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
879}
880
881void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
882 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
883}
884
885void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
886 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
887}
888
889void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
890 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
891}
892
893void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
894 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
895}
896
897void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
898 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
899}
900
901void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
902 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
903}
904
905void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
906 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
907}
908
909void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
910 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
911}
912
913void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
914 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
915}
916
917void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
918 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
919}
920
921void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
922 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
923}
924
925void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
926 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
927}
928
929void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
930 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
931}
932
933void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
934 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
935}
936
937void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
938 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
939}
940
941void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
942 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
943}
944
945void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
946 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
947}
948
Alexey Frunze4dda3372015-06-01 18:31:49 -0700949void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
950 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
951}
952
953void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
954 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
955}
956
957void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
958 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
959}
960
961void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
962 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800963}
964
Chris Larsen51417632015-10-02 13:24:25 -0700965void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
966 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
967}
968
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700969void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
970 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
971}
972
Andreas Gampe57b34292015-01-14 15:45:59 -0800973void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
974 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
975}
976
Lazar Trsicd9672662015-09-03 17:33:01 +0200977void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
978 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
979}
980
Alexey Frunze4dda3372015-06-01 18:31:49 -0700981void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
982 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
983}
984
Lazar Trsicd9672662015-09-03 17:33:01 +0200985void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
986 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
987}
988
Alexey Frunze4dda3372015-06-01 18:31:49 -0700989void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
990 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
991}
992
993void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
994 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800995}
996
997void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
998 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
999}
1000
1001void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1002 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1003}
1004
1005void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1006 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1007}
1008
1009void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1010 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1011}
1012
1013void Mips64Assembler::Break() {
1014 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1015 static_cast<GpuRegister>(0), 0, 0xD);
1016}
1017
1018void Mips64Assembler::Nop() {
1019 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1020 static_cast<GpuRegister>(0), 0, 0x0);
1021}
1022
Alexey Frunze4dda3372015-06-01 18:31:49 -07001023void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1024 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001025}
1026
Alexey Frunze4dda3372015-06-01 18:31:49 -07001027void Mips64Assembler::Clear(GpuRegister rd) {
1028 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001029}
1030
Alexey Frunze4dda3372015-06-01 18:31:49 -07001031void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1032 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001033}
1034
Alexey Frunze4dda3372015-06-01 18:31:49 -07001035void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
1036 if (IsUint<16>(value)) {
1037 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1038 Ori(rd, ZERO, value);
1039 } else if (IsInt<16>(value)) {
1040 // Use ADD with (signed) immediate to encode 16b signed int.
1041 Addiu(rd, ZERO, value);
1042 } else {
1043 Lui(rd, value >> 16);
1044 if (value & 0xFFFF)
1045 Ori(rd, rd, value);
1046 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001047}
1048
Alexey Frunze4dda3372015-06-01 18:31:49 -07001049void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
1050 int bit31 = (value & UINT64_C(0x80000000)) != 0;
1051
1052 // Loads with 1 instruction.
1053 if (IsUint<16>(value)) {
1054 Ori(rd, ZERO, value);
1055 } else if (IsInt<16>(value)) {
1056 Daddiu(rd, ZERO, value);
1057 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
1058 Lui(rd, value >> 16);
1059 } else if (IsInt<32>(value)) {
1060 // Loads with 2 instructions.
1061 Lui(rd, value >> 16);
1062 Ori(rd, rd, value);
1063 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
1064 Ori(rd, ZERO, value);
1065 Dahi(rd, value >> 32);
1066 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
1067 Ori(rd, ZERO, value);
1068 Dati(rd, value >> 48);
1069 } else if ((value & 0xFFFF) == 0 &&
1070 (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
1071 Lui(rd, value >> 16);
1072 Dahi(rd, (value >> 32) + bit31);
1073 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
1074 Lui(rd, value >> 16);
1075 Dati(rd, (value >> 48) + bit31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001076 } else if (IsPowerOfTwo(value + UINT64_C(1))) {
1077 int shift_cnt = 64 - CTZ(value + UINT64_C(1));
1078 Daddiu(rd, ZERO, -1);
1079 if (shift_cnt < 32) {
1080 Dsrl(rd, rd, shift_cnt);
1081 } else {
1082 Dsrl32(rd, rd, shift_cnt & 31);
1083 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001084 } else {
1085 int shift_cnt = CTZ(value);
1086 int64_t tmp = value >> shift_cnt;
1087 if (IsUint<16>(tmp)) {
1088 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001089 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001090 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001091 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001092 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001093 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001094 } else if (IsInt<16>(tmp)) {
1095 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001096 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001097 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001098 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001099 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001100 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001101 } else if (IsInt<32>(tmp)) {
1102 // Loads with 3 instructions.
1103 Lui(rd, tmp >> 16);
1104 Ori(rd, rd, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001105 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001106 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001107 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001108 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001109 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001110 } else {
1111 shift_cnt = 16 + CTZ(value >> 16);
1112 tmp = value >> shift_cnt;
1113 if (IsUint<16>(tmp)) {
1114 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001115 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001116 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001117 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001118 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001119 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001120 Ori(rd, rd, value);
1121 } else if (IsInt<16>(tmp)) {
1122 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001123 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001124 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001125 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001126 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001127 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001128 Ori(rd, rd, value);
1129 } else {
1130 // Loads with 3-4 instructions.
1131 uint64_t tmp2 = value;
1132 bool used_lui = false;
1133 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
1134 Lui(rd, tmp2 >> 16);
1135 used_lui = true;
1136 }
1137 if ((tmp2 & 0xFFFF) != 0) {
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001138 if (used_lui) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001139 Ori(rd, rd, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001140 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001141 Ori(rd, ZERO, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001142 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001143 }
1144 if (bit31) {
1145 tmp2 += UINT64_C(0x100000000);
1146 }
1147 if (((tmp2 >> 32) & 0xFFFF) != 0) {
1148 Dahi(rd, tmp2 >> 32);
1149 }
1150 if (tmp2 & UINT64_C(0x800000000000)) {
1151 tmp2 += UINT64_C(0x1000000000000);
1152 }
1153 if ((tmp2 >> 48) != 0) {
1154 Dati(rd, tmp2 >> 48);
1155 }
1156 }
1157 }
1158 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001159}
1160
Alexey Frunze4dda3372015-06-01 18:31:49 -07001161void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1162 if (IsInt<16>(value)) {
1163 Daddiu(rt, rs, value);
1164 } else {
1165 LoadConst64(rtmp, value);
1166 Daddu(rt, rs, rtmp);
1167 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001168}
1169
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001170void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1171 Mips64Assembler::Branch::Type short_type,
1172 Mips64Assembler::Branch::Type long_type) {
1173 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1174}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001175
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001176void Mips64Assembler::Branch::InitializeType(bool is_call) {
1177 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1178 if (is_call) {
1179 InitShortOrLong(offset_size, kCall, kLongCall);
1180 } else if (condition_ == kUncond) {
1181 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1182 } else {
1183 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1184 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1185 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1186 } else {
1187 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1188 }
1189 }
1190 old_type_ = type_;
1191}
1192
1193bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1194 switch (condition) {
1195 case kCondLT:
1196 case kCondGT:
1197 case kCondNE:
1198 case kCondLTU:
1199 return lhs == rhs;
1200 default:
1201 return false;
1202 }
1203}
1204
1205bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1206 GpuRegister lhs,
1207 GpuRegister rhs) {
1208 switch (condition) {
1209 case kUncond:
1210 return true;
1211 case kCondGE:
1212 case kCondLE:
1213 case kCondEQ:
1214 case kCondGEU:
1215 return lhs == rhs;
1216 default:
1217 return false;
1218 }
1219}
1220
1221Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1222 : old_location_(location),
1223 location_(location),
1224 target_(target),
1225 lhs_reg_(ZERO),
1226 rhs_reg_(ZERO),
1227 condition_(kUncond) {
1228 InitializeType(false);
1229}
1230
1231Mips64Assembler::Branch::Branch(uint32_t location,
1232 uint32_t target,
1233 Mips64Assembler::BranchCondition condition,
1234 GpuRegister lhs_reg,
1235 GpuRegister rhs_reg)
1236 : old_location_(location),
1237 location_(location),
1238 target_(target),
1239 lhs_reg_(lhs_reg),
1240 rhs_reg_(rhs_reg),
1241 condition_(condition) {
1242 CHECK_NE(condition, kUncond);
1243 switch (condition) {
1244 case kCondEQ:
1245 case kCondNE:
1246 case kCondLT:
1247 case kCondGE:
1248 case kCondLE:
1249 case kCondGT:
1250 case kCondLTU:
1251 case kCondGEU:
1252 CHECK_NE(lhs_reg, ZERO);
1253 CHECK_NE(rhs_reg, ZERO);
1254 break;
1255 case kCondLTZ:
1256 case kCondGEZ:
1257 case kCondLEZ:
1258 case kCondGTZ:
1259 case kCondEQZ:
1260 case kCondNEZ:
1261 CHECK_NE(lhs_reg, ZERO);
1262 CHECK_EQ(rhs_reg, ZERO);
1263 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001264 case kCondF:
1265 case kCondT:
1266 CHECK_EQ(rhs_reg, ZERO);
1267 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001268 case kUncond:
1269 UNREACHABLE();
1270 }
1271 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1272 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1273 // Branch condition is always true, make the branch unconditional.
1274 condition_ = kUncond;
1275 }
1276 InitializeType(false);
1277}
1278
1279Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1280 : old_location_(location),
1281 location_(location),
1282 target_(target),
1283 lhs_reg_(indirect_reg),
1284 rhs_reg_(ZERO),
1285 condition_(kUncond) {
1286 CHECK_NE(indirect_reg, ZERO);
1287 CHECK_NE(indirect_reg, AT);
1288 InitializeType(true);
1289}
1290
1291Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1292 Mips64Assembler::BranchCondition cond) {
1293 switch (cond) {
1294 case kCondLT:
1295 return kCondGE;
1296 case kCondGE:
1297 return kCondLT;
1298 case kCondLE:
1299 return kCondGT;
1300 case kCondGT:
1301 return kCondLE;
1302 case kCondLTZ:
1303 return kCondGEZ;
1304 case kCondGEZ:
1305 return kCondLTZ;
1306 case kCondLEZ:
1307 return kCondGTZ;
1308 case kCondGTZ:
1309 return kCondLEZ;
1310 case kCondEQ:
1311 return kCondNE;
1312 case kCondNE:
1313 return kCondEQ;
1314 case kCondEQZ:
1315 return kCondNEZ;
1316 case kCondNEZ:
1317 return kCondEQZ;
1318 case kCondLTU:
1319 return kCondGEU;
1320 case kCondGEU:
1321 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001322 case kCondF:
1323 return kCondT;
1324 case kCondT:
1325 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001326 case kUncond:
1327 LOG(FATAL) << "Unexpected branch condition " << cond;
1328 }
1329 UNREACHABLE();
1330}
1331
1332Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1333 return type_;
1334}
1335
1336Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1337 return condition_;
1338}
1339
1340GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1341 return lhs_reg_;
1342}
1343
1344GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1345 return rhs_reg_;
1346}
1347
1348uint32_t Mips64Assembler::Branch::GetTarget() const {
1349 return target_;
1350}
1351
1352uint32_t Mips64Assembler::Branch::GetLocation() const {
1353 return location_;
1354}
1355
1356uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1357 return old_location_;
1358}
1359
1360uint32_t Mips64Assembler::Branch::GetLength() const {
1361 return branch_info_[type_].length;
1362}
1363
1364uint32_t Mips64Assembler::Branch::GetOldLength() const {
1365 return branch_info_[old_type_].length;
1366}
1367
1368uint32_t Mips64Assembler::Branch::GetSize() const {
1369 return GetLength() * sizeof(uint32_t);
1370}
1371
1372uint32_t Mips64Assembler::Branch::GetOldSize() const {
1373 return GetOldLength() * sizeof(uint32_t);
1374}
1375
1376uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1377 return GetLocation() + GetSize();
1378}
1379
1380uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1381 return GetOldLocation() + GetOldSize();
1382}
1383
1384bool Mips64Assembler::Branch::IsLong() const {
1385 switch (type_) {
1386 // Short branches.
1387 case kUncondBranch:
1388 case kCondBranch:
1389 case kCall:
1390 return false;
1391 // Long branches.
1392 case kLongUncondBranch:
1393 case kLongCondBranch:
1394 case kLongCall:
1395 return true;
1396 }
1397 UNREACHABLE();
1398}
1399
1400bool Mips64Assembler::Branch::IsResolved() const {
1401 return target_ != kUnresolved;
1402}
1403
1404Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1405 OffsetBits offset_size =
1406 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1407 ? kOffset23
1408 : branch_info_[type_].offset_size;
1409 return offset_size;
1410}
1411
1412Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1413 uint32_t target) {
1414 // For unresolved targets assume the shortest encoding
1415 // (later it will be made longer if needed).
1416 if (target == kUnresolved)
1417 return kOffset16;
1418 int64_t distance = static_cast<int64_t>(target) - location;
1419 // To simplify calculations in composite branches consisting of multiple instructions
1420 // bump up the distance by a value larger than the max byte size of a composite branch.
1421 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1422 if (IsInt<kOffset16>(distance))
1423 return kOffset16;
1424 else if (IsInt<kOffset18>(distance))
1425 return kOffset18;
1426 else if (IsInt<kOffset21>(distance))
1427 return kOffset21;
1428 else if (IsInt<kOffset23>(distance))
1429 return kOffset23;
1430 else if (IsInt<kOffset28>(distance))
1431 return kOffset28;
1432 return kOffset32;
1433}
1434
1435void Mips64Assembler::Branch::Resolve(uint32_t target) {
1436 target_ = target;
1437}
1438
1439void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1440 if (location_ > expand_location) {
1441 location_ += delta;
1442 }
1443 if (!IsResolved()) {
1444 return; // Don't know the target yet.
1445 }
1446 if (target_ > expand_location) {
1447 target_ += delta;
1448 }
1449}
1450
1451void Mips64Assembler::Branch::PromoteToLong() {
1452 switch (type_) {
1453 // Short branches.
1454 case kUncondBranch:
1455 type_ = kLongUncondBranch;
1456 break;
1457 case kCondBranch:
1458 type_ = kLongCondBranch;
1459 break;
1460 case kCall:
1461 type_ = kLongCall;
1462 break;
1463 default:
1464 // Note: 'type_' is already long.
1465 break;
1466 }
1467 CHECK(IsLong());
1468}
1469
1470uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1471 // If the branch is still unresolved or already long, nothing to do.
1472 if (IsLong() || !IsResolved()) {
1473 return 0;
1474 }
1475 // Promote the short branch to long if the offset size is too small
1476 // to hold the distance between location_ and target_.
1477 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1478 PromoteToLong();
1479 uint32_t old_size = GetOldSize();
1480 uint32_t new_size = GetSize();
1481 CHECK_GT(new_size, old_size);
1482 return new_size - old_size;
1483 }
1484 // The following logic is for debugging/testing purposes.
1485 // Promote some short branches to long when it's not really required.
1486 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1487 int64_t distance = static_cast<int64_t>(target_) - location_;
1488 distance = (distance >= 0) ? distance : -distance;
1489 if (distance >= max_short_distance) {
1490 PromoteToLong();
1491 uint32_t old_size = GetOldSize();
1492 uint32_t new_size = GetSize();
1493 CHECK_GT(new_size, old_size);
1494 return new_size - old_size;
1495 }
1496 }
1497 return 0;
1498}
1499
1500uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1501 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1502}
1503
1504uint32_t Mips64Assembler::Branch::GetOffset() const {
1505 CHECK(IsResolved());
1506 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1507 // Calculate the byte distance between instructions and also account for
1508 // different PC-relative origins.
1509 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1510 // Prepare the offset for encoding into the instruction(s).
1511 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1512 return offset;
1513}
1514
1515Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1516 CHECK_LT(branch_id, branches_.size());
1517 return &branches_[branch_id];
1518}
1519
1520const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1521 CHECK_LT(branch_id, branches_.size());
1522 return &branches_[branch_id];
1523}
1524
1525void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001526 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001527 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001528
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001529 // Walk the list of branches referring to and preceding this label.
1530 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001531 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001532 uint32_t branch_id = label->Position();
1533 Branch* branch = GetBranch(branch_id);
1534 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001535
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001536 uint32_t branch_location = branch->GetLocation();
1537 // Extract the location of the previous branch in the list (walking the list backwards;
1538 // the previous branch ID was stored in the space reserved for this branch).
1539 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001540
1541 // On to the previous branch in the list...
1542 label->position_ = prev;
1543 }
1544
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001545 // Now make the label object contain its own location (relative to the end of the preceding
1546 // branch, if any; it will be used by the branches referring to and following this label).
1547 label->prev_branch_id_plus_one_ = branches_.size();
1548 if (label->prev_branch_id_plus_one_) {
1549 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1550 const Branch* branch = GetBranch(branch_id);
1551 bound_pc -= branch->GetEndLocation();
1552 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001553 label->BindTo(bound_pc);
1554}
1555
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001556uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1557 CHECK(label->IsBound());
1558 uint32_t target = label->Position();
1559 if (label->prev_branch_id_plus_one_) {
1560 // Get label location based on the branch preceding it.
1561 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1562 const Branch* branch = GetBranch(branch_id);
1563 target += branch->GetEndLocation();
1564 }
1565 return target;
1566}
1567
1568uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1569 // We can reconstruct the adjustment by going through all the branches from the beginning
1570 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1571 // with increasing old_position, we can use the data from last AdjustedPosition() to
1572 // continue where we left off and the whole loop should be O(m+n) where m is the number
1573 // of positions to adjust and n is the number of branches.
1574 if (old_position < last_old_position_) {
1575 last_position_adjustment_ = 0;
1576 last_old_position_ = 0;
1577 last_branch_id_ = 0;
1578 }
1579 while (last_branch_id_ != branches_.size()) {
1580 const Branch* branch = GetBranch(last_branch_id_);
1581 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1582 break;
1583 }
1584 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1585 ++last_branch_id_;
1586 }
1587 last_old_position_ = old_position;
1588 return old_position + last_position_adjustment_;
1589}
1590
1591void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1592 uint32_t length = branches_.back().GetLength();
1593 if (!label->IsBound()) {
1594 // Branch forward (to a following label), distance is unknown.
1595 // The first branch forward will contain 0, serving as the terminator of
1596 // the list of forward-reaching branches.
1597 Emit(label->position_);
1598 length--;
1599 // Now make the label object point to this branch
1600 // (this forms a linked list of branches preceding this label).
1601 uint32_t branch_id = branches_.size() - 1;
1602 label->LinkTo(branch_id);
1603 }
1604 // Reserve space for the branch.
1605 while (length--) {
1606 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001607 }
1608}
1609
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001610void Mips64Assembler::Buncond(Mips64Label* label) {
1611 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1612 branches_.emplace_back(buffer_.Size(), target);
1613 FinalizeLabeledBranch(label);
1614}
1615
1616void Mips64Assembler::Bcond(Mips64Label* label,
1617 BranchCondition condition,
1618 GpuRegister lhs,
1619 GpuRegister rhs) {
1620 // If lhs = rhs, this can be a NOP.
1621 if (Branch::IsNop(condition, lhs, rhs)) {
1622 return;
1623 }
1624 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1625 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1626 FinalizeLabeledBranch(label);
1627}
1628
1629void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1630 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1631 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1632 FinalizeLabeledBranch(label);
1633}
1634
1635void Mips64Assembler::PromoteBranches() {
1636 // Promote short branches to long as necessary.
1637 bool changed;
1638 do {
1639 changed = false;
1640 for (auto& branch : branches_) {
1641 CHECK(branch.IsResolved());
1642 uint32_t delta = branch.PromoteIfNeeded();
1643 // If this branch has been promoted and needs to expand in size,
1644 // relocate all branches by the expansion size.
1645 if (delta) {
1646 changed = true;
1647 uint32_t expand_location = branch.GetLocation();
1648 for (auto& branch2 : branches_) {
1649 branch2.Relocate(expand_location, delta);
1650 }
1651 }
1652 }
1653 } while (changed);
1654
1655 // Account for branch expansion by resizing the code buffer
1656 // and moving the code in it to its final location.
1657 size_t branch_count = branches_.size();
1658 if (branch_count > 0) {
1659 // Resize.
1660 Branch& last_branch = branches_[branch_count - 1];
1661 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1662 uint32_t old_size = buffer_.Size();
1663 buffer_.Resize(old_size + size_delta);
1664 // Move the code residing between branch placeholders.
1665 uint32_t end = old_size;
1666 for (size_t i = branch_count; i > 0; ) {
1667 Branch& branch = branches_[--i];
1668 uint32_t size = end - branch.GetOldEndLocation();
1669 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1670 end = branch.GetOldLocation();
1671 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001672 }
1673}
1674
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001675// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1676const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1677 // Short branches.
1678 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1679 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1680 // Exception: kOffset23 for beqzc/bnezc
1681 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1682 // Long branches.
1683 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1684 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1685 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1686};
1687
1688// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1689void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1690 CHECK(overwriting_);
1691 overwrite_location_ = branch->GetLocation();
1692 uint32_t offset = branch->GetOffset();
1693 BranchCondition condition = branch->GetCondition();
1694 GpuRegister lhs = branch->GetLeftRegister();
1695 GpuRegister rhs = branch->GetRightRegister();
1696 switch (branch->GetType()) {
1697 // Short branches.
1698 case Branch::kUncondBranch:
1699 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1700 Bc(offset);
1701 break;
1702 case Branch::kCondBranch:
1703 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1704 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001705 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001706 break;
1707 case Branch::kCall:
1708 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1709 Addiupc(lhs, offset);
1710 Jialc(lhs, 0);
1711 break;
1712
1713 // Long branches.
1714 case Branch::kLongUncondBranch:
1715 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1716 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1717 Auipc(AT, High16Bits(offset));
1718 Jic(AT, Low16Bits(offset));
1719 break;
1720 case Branch::kLongCondBranch:
1721 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1722 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1723 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1724 Auipc(AT, High16Bits(offset));
1725 Jic(AT, Low16Bits(offset));
1726 break;
1727 case Branch::kLongCall:
1728 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1729 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1730 Auipc(lhs, High16Bits(offset));
1731 Daddiu(lhs, lhs, Low16Bits(offset));
1732 Jialc(lhs, 0);
1733 break;
1734 }
1735 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1736 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001737}
1738
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001739void Mips64Assembler::Bc(Mips64Label* label) {
1740 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001741}
1742
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001743void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1744 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001745}
1746
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001747void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1748 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001749}
1750
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001751void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1752 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001753}
1754
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001755void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1756 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001757}
1758
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001759void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1760 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001761}
1762
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001763void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1764 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001765}
1766
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001767void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1768 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001769}
1770
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001771void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1772 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001773}
1774
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001775void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1776 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001777}
1778
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001779void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1780 Bcond(label, kCondEQ, rs, rt);
1781}
1782
1783void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1784 Bcond(label, kCondNE, rs, rt);
1785}
1786
1787void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1788 Bcond(label, kCondEQZ, rs);
1789}
1790
1791void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1792 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001793}
1794
Alexey Frunze299a9392015-12-08 16:08:02 -08001795void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1796 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1797}
1798
1799void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1800 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1801}
1802
Andreas Gampe57b34292015-01-14 15:45:59 -08001803void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1804 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001805 if (!IsInt<16>(offset) ||
1806 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1807 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1808 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001809 Daddu(AT, AT, base);
1810 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001811 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001812 }
1813
Andreas Gampe57b34292015-01-14 15:45:59 -08001814 switch (type) {
1815 case kLoadSignedByte:
1816 Lb(reg, base, offset);
1817 break;
1818 case kLoadUnsignedByte:
1819 Lbu(reg, base, offset);
1820 break;
1821 case kLoadSignedHalfword:
1822 Lh(reg, base, offset);
1823 break;
1824 case kLoadUnsignedHalfword:
1825 Lhu(reg, base, offset);
1826 break;
1827 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001828 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001829 Lw(reg, base, offset);
1830 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001831 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001832 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07001833 Lwu(reg, base, offset);
1834 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001835 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001836 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1837 CHECK_ALIGNED(offset, kMips64WordSize);
1838 Lwu(reg, base, offset);
1839 Lwu(TMP2, base, offset + kMips64WordSize);
1840 Dinsu(reg, TMP2, 32, 32);
1841 } else {
1842 Ld(reg, base, offset);
1843 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001844 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001845 }
1846}
1847
1848void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1849 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001850 if (!IsInt<16>(offset) ||
1851 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1852 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1853 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001854 Daddu(AT, AT, base);
1855 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001856 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001857 }
1858
Andreas Gampe57b34292015-01-14 15:45:59 -08001859 switch (type) {
1860 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001861 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001862 Lwc1(reg, base, offset);
1863 break;
1864 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001865 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1866 CHECK_ALIGNED(offset, kMips64WordSize);
1867 Lwc1(reg, base, offset);
1868 Lw(TMP2, base, offset + kMips64WordSize);
1869 Mthc1(TMP2, reg);
1870 } else {
1871 Ldc1(reg, base, offset);
1872 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001873 break;
1874 default:
1875 LOG(FATAL) << "UNREACHABLE";
1876 }
1877}
1878
1879void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1880 size_t size) {
1881 Mips64ManagedRegister dst = m_dst.AsMips64();
1882 if (dst.IsNoRegister()) {
1883 CHECK_EQ(0u, size) << dst;
1884 } else if (dst.IsGpuRegister()) {
1885 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001886 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1887 } else if (size == 8) {
1888 CHECK_EQ(8u, size) << dst;
1889 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1890 } else {
1891 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1892 }
1893 } else if (dst.IsFpuRegister()) {
1894 if (size == 4) {
1895 CHECK_EQ(4u, size) << dst;
1896 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1897 } else if (size == 8) {
1898 CHECK_EQ(8u, size) << dst;
1899 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1900 } else {
1901 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1902 }
1903 }
1904}
1905
1906void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1907 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001908 if (!IsInt<16>(offset) ||
1909 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1910 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1911 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001912 Daddu(AT, AT, base);
1913 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001914 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001915 }
1916
Andreas Gampe57b34292015-01-14 15:45:59 -08001917 switch (type) {
1918 case kStoreByte:
1919 Sb(reg, base, offset);
1920 break;
1921 case kStoreHalfword:
1922 Sh(reg, base, offset);
1923 break;
1924 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001925 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001926 Sw(reg, base, offset);
1927 break;
1928 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001929 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1930 CHECK_ALIGNED(offset, kMips64WordSize);
1931 Sw(reg, base, offset);
1932 Dsrl32(TMP2, reg, 0);
1933 Sw(TMP2, base, offset + kMips64WordSize);
1934 } else {
1935 Sd(reg, base, offset);
1936 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001937 break;
1938 default:
1939 LOG(FATAL) << "UNREACHABLE";
1940 }
1941}
1942
1943void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1944 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001945 if (!IsInt<16>(offset) ||
1946 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1947 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1948 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001949 Daddu(AT, AT, base);
1950 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001951 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001952 }
1953
Andreas Gampe57b34292015-01-14 15:45:59 -08001954 switch (type) {
1955 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001956 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001957 Swc1(reg, base, offset);
1958 break;
1959 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001960 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1961 CHECK_ALIGNED(offset, kMips64WordSize);
1962 Mfhc1(TMP2, reg);
1963 Swc1(reg, base, offset);
1964 Sw(TMP2, base, offset + kMips64WordSize);
1965 } else {
1966 Sdc1(reg, base, offset);
1967 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001968 break;
1969 default:
1970 LOG(FATAL) << "UNREACHABLE";
1971 }
1972}
1973
David Srbeckydd973932015-04-07 20:29:48 +01001974static dwarf::Reg DWARFReg(GpuRegister reg) {
1975 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1976}
1977
Andreas Gampe57b34292015-01-14 15:45:59 -08001978constexpr size_t kFramePointerSize = 8;
1979
Vladimir Marko32248382016-05-19 10:37:24 +01001980void Mips64Assembler::BuildFrame(size_t frame_size,
1981 ManagedRegister method_reg,
1982 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08001983 const ManagedRegisterEntrySpills& entry_spills) {
1984 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001985 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001986
1987 // Increase frame to required size.
1988 IncreaseFrameSize(frame_size);
1989
1990 // Push callee saves and return address
1991 int stack_offset = frame_size - kFramePointerSize;
1992 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001993 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001994 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1995 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01001996 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08001997 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001998 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001999 }
2000
2001 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002002 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002003
2004 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002005 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002006 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002007 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002008 ManagedRegisterSpill spill = entry_spills.at(i);
2009 int32_t size = spill.getSize();
2010 if (reg.IsNoRegister()) {
2011 // only increment stack offset.
2012 offset += size;
2013 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002014 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2015 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002016 offset += size;
2017 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002018 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2019 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002020 offset += size;
2021 }
2022 }
2023}
2024
2025void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002026 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002027 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002028 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002029 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002030
2031 // Pop callee saves and return address
2032 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2033 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002034 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002035 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002036 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002037 stack_offset += kFramePointerSize;
2038 }
2039 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002040 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002041
2042 // Decrease frame to required size.
2043 DecreaseFrameSize(frame_size);
2044
2045 // Then jump to the return address.
2046 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002047 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002048
2049 // The CFI should be restored for any code that follows the exit block.
2050 cfi_.RestoreState();
2051 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002052}
2053
2054void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002055 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002056 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002057 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002058 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002059}
2060
2061void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002062 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002063 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002064 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002065 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002066}
2067
2068void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2069 Mips64ManagedRegister src = msrc.AsMips64();
2070 if (src.IsNoRegister()) {
2071 CHECK_EQ(0u, size);
2072 } else if (src.IsGpuRegister()) {
2073 CHECK(size == 4 || size == 8) << size;
2074 if (size == 8) {
2075 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2076 } else if (size == 4) {
2077 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2078 } else {
2079 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2080 }
2081 } else if (src.IsFpuRegister()) {
2082 CHECK(size == 4 || size == 8) << size;
2083 if (size == 8) {
2084 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2085 } else if (size == 4) {
2086 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2087 } else {
2088 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2089 }
2090 }
2091}
2092
2093void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2094 Mips64ManagedRegister src = msrc.AsMips64();
2095 CHECK(src.IsGpuRegister());
2096 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2097}
2098
2099void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2100 Mips64ManagedRegister src = msrc.AsMips64();
2101 CHECK(src.IsGpuRegister());
2102 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2103}
2104
2105void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2106 ManagedRegister mscratch) {
2107 Mips64ManagedRegister scratch = mscratch.AsMips64();
2108 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002109 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002110 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2111}
2112
Lazar Trsicd9672662015-09-03 17:33:01 +02002113void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002114 FrameOffset fr_offs,
2115 ManagedRegister mscratch) {
2116 Mips64ManagedRegister scratch = mscratch.AsMips64();
2117 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002118 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002119 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2120}
2121
Lazar Trsicd9672662015-09-03 17:33:01 +02002122void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002123 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2124}
2125
2126void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2127 FrameOffset in_off, ManagedRegister mscratch) {
2128 Mips64ManagedRegister src = msrc.AsMips64();
2129 Mips64ManagedRegister scratch = mscratch.AsMips64();
2130 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2131 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2132 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2133}
2134
2135void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2136 return EmitLoad(mdest, SP, src.Int32Value(), size);
2137}
2138
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002139void Mips64Assembler::LoadFromThread64(ManagedRegister mdest,
Lazar Trsicd9672662015-09-03 17:33:01 +02002140 ThreadOffset<kMips64DoublewordSize> src,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002141 size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002142 return EmitLoad(mdest, S1, src.Int32Value(), size);
2143}
2144
2145void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2146 Mips64ManagedRegister dest = mdest.AsMips64();
2147 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002148 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002149}
2150
Mathieu Chartiere401d142015-04-22 13:56:20 -07002151void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002152 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002153 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002154 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2155 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002156 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002157 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002158 // TODO: review
2159 // Negate the 32-bit ref
2160 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2161 // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
Lazar Trsicd9672662015-09-03 17:33:01 +02002162 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002163 }
2164}
2165
2166void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002167 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002168 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002169 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002170 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2171 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2172}
2173
2174void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
Lazar Trsicd9672662015-09-03 17:33:01 +02002175 ThreadOffset<kMips64DoublewordSize> offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002176 Mips64ManagedRegister dest = mdest.AsMips64();
2177 CHECK(dest.IsGpuRegister());
2178 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2179}
2180
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002181void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2182 size_t size ATTRIBUTE_UNUSED) {
2183 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002184}
2185
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002186void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2187 size_t size ATTRIBUTE_UNUSED) {
2188 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002189}
2190
2191void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2192 Mips64ManagedRegister dest = mdest.AsMips64();
2193 Mips64ManagedRegister src = msrc.AsMips64();
2194 if (!dest.Equals(src)) {
2195 if (dest.IsGpuRegister()) {
2196 CHECK(src.IsGpuRegister()) << src;
2197 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2198 } else if (dest.IsFpuRegister()) {
2199 CHECK(src.IsFpuRegister()) << src;
2200 if (size == 4) {
2201 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2202 } else if (size == 8) {
2203 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2204 } else {
2205 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2206 }
2207 }
2208 }
2209}
2210
2211void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2212 ManagedRegister mscratch) {
2213 Mips64ManagedRegister scratch = mscratch.AsMips64();
2214 CHECK(scratch.IsGpuRegister()) << scratch;
2215 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2216 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2217}
2218
2219void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
Lazar Trsicd9672662015-09-03 17:33:01 +02002220 ThreadOffset<kMips64DoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002221 ManagedRegister mscratch) {
2222 Mips64ManagedRegister scratch = mscratch.AsMips64();
2223 CHECK(scratch.IsGpuRegister()) << scratch;
2224 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2225 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2226}
2227
Lazar Trsicd9672662015-09-03 17:33:01 +02002228void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002229 FrameOffset fr_offs,
2230 ManagedRegister mscratch) {
2231 Mips64ManagedRegister scratch = mscratch.AsMips64();
2232 CHECK(scratch.IsGpuRegister()) << scratch;
2233 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2234 SP, fr_offs.Int32Value());
2235 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2236 S1, thr_offs.Int32Value());
2237}
2238
2239void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2240 ManagedRegister mscratch, size_t size) {
2241 Mips64ManagedRegister scratch = mscratch.AsMips64();
2242 CHECK(scratch.IsGpuRegister()) << scratch;
2243 CHECK(size == 4 || size == 8) << size;
2244 if (size == 4) {
2245 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002246 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002247 } else if (size == 8) {
2248 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2249 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2250 } else {
2251 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2252 }
2253}
2254
2255void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002256 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002257 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2258 CHECK(size == 4 || size == 8) << size;
2259 if (size == 4) {
2260 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2261 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002262 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002263 } else if (size == 8) {
2264 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2265 src_offset.Int32Value());
2266 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2267 } else {
2268 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2269 }
2270}
2271
2272void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002273 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002274 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2275 CHECK(size == 4 || size == 8) << size;
2276 if (size == 4) {
2277 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002278 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002279 dest_offset.Int32Value());
2280 } else if (size == 8) {
2281 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2282 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2283 dest_offset.Int32Value());
2284 } else {
2285 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2286 }
2287}
2288
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002289void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2290 FrameOffset src_base ATTRIBUTE_UNUSED,
2291 Offset src_offset ATTRIBUTE_UNUSED,
2292 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2293 size_t size ATTRIBUTE_UNUSED) {
2294 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002295}
2296
2297void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002298 ManagedRegister src, Offset src_offset,
2299 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002300 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2301 CHECK(size == 4 || size == 8) << size;
2302 if (size == 4) {
2303 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002304 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002305 } else if (size == 8) {
2306 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2307 src_offset.Int32Value());
2308 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2309 dest_offset.Int32Value());
2310 } else {
2311 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2312 }
2313}
2314
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002315void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2316 Offset dest_offset ATTRIBUTE_UNUSED,
2317 FrameOffset src ATTRIBUTE_UNUSED,
2318 Offset src_offset ATTRIBUTE_UNUSED,
2319 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2320 size_t size ATTRIBUTE_UNUSED) {
2321 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002322}
2323
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002324void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002325 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002326 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002327}
2328
2329void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002330 FrameOffset handle_scope_offset,
2331 ManagedRegister min_reg,
2332 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002333 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2334 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2335 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2336 CHECK(out_reg.IsGpuRegister()) << out_reg;
2337 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002338 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002339 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2340 // the address in the handle scope holding the reference.
2341 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2342 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002343 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002344 SP, handle_scope_offset.Int32Value());
2345 in_reg = out_reg;
2346 }
2347 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002348 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002349 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002350 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2351 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2352 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002353 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002354 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002355 }
2356}
2357
2358void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002359 FrameOffset handle_scope_offset,
2360 ManagedRegister mscratch,
2361 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002362 Mips64ManagedRegister scratch = mscratch.AsMips64();
2363 CHECK(scratch.IsGpuRegister()) << scratch;
2364 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002365 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002366 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002367 handle_scope_offset.Int32Value());
2368 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2369 // the address in the handle scope holding the reference.
2370 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002371 Beqzc(scratch.AsGpuRegister(), &null_arg);
2372 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2373 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002374 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002375 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002376 }
2377 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2378}
2379
2380// Given a handle scope entry, load the associated reference.
2381void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002382 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002383 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2384 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2385 CHECK(out_reg.IsGpuRegister()) << out_reg;
2386 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002387 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002388 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002389 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002390 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002391 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002392 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2393 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002394 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002395}
2396
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002397void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2398 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002399 // TODO: not validating references
2400}
2401
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002402void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2403 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002404 // TODO: not validating references
2405}
2406
2407void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2408 Mips64ManagedRegister base = mbase.AsMips64();
2409 Mips64ManagedRegister scratch = mscratch.AsMips64();
2410 CHECK(base.IsGpuRegister()) << base;
2411 CHECK(scratch.IsGpuRegister()) << scratch;
2412 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2413 base.AsGpuRegister(), offset.Int32Value());
2414 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002415 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002416 // TODO: place reference map on call
2417}
2418
2419void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2420 Mips64ManagedRegister scratch = mscratch.AsMips64();
2421 CHECK(scratch.IsGpuRegister()) << scratch;
2422 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002423 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002424 SP, base.Int32Value());
2425 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2426 scratch.AsGpuRegister(), offset.Int32Value());
2427 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002428 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002429 // TODO: place reference map on call
2430}
2431
Lazar Trsicd9672662015-09-03 17:33:01 +02002432void Mips64Assembler::CallFromThread64(ThreadOffset<kMips64DoublewordSize> offset ATTRIBUTE_UNUSED,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002433 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
2434 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002435}
2436
2437void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2438 Move(tr.AsMips64().AsGpuRegister(), S1);
2439}
2440
2441void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002442 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002443 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2444}
2445
2446void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2447 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002448 exception_blocks_.emplace_back(scratch, stack_adjust);
2449 LoadFromOffset(kLoadDoubleword,
2450 scratch.AsGpuRegister(),
2451 S1,
Lazar Trsicd9672662015-09-03 17:33:01 +02002452 Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002453 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002454}
2455
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002456void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2457 Bind(exception->Entry());
2458 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2459 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002460 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002461 // Pass exception object as argument.
2462 // Don't care about preserving A0 as this call won't return.
2463 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2464 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002465 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002466 LoadFromOffset(kLoadDoubleword,
2467 T9,
2468 S1,
Lazar Trsicd9672662015-09-03 17:33:01 +02002469 QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002470 Jr(T9);
2471 Nop();
2472
Andreas Gampe57b34292015-01-14 15:45:59 -08002473 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002474 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002475}
2476
2477} // namespace mips64
2478} // namespace art