blob: 998f2c709b57e3cc8782c9501f5504c6a14644a9 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
Alexey Frunze0960ac52016-12-20 17:24:59 -080038 ReserveJumpTableSpace();
Alexey Frunze19f6c692016-11-30 19:19:55 -080039 EmitLiterals();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070040 PromoteBranches();
41}
42
43void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
44 EmitBranches();
Alexey Frunze0960ac52016-12-20 17:24:59 -080045 EmitJumpTables();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070046 Assembler::FinalizeInstructions(region);
47 PatchCFI();
48}
49
50void Mips64Assembler::PatchCFI() {
51 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
52 return;
53 }
54
55 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
56 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
57 const std::vector<uint8_t>& old_stream = data.first;
58 const std::vector<DelayedAdvancePC>& advances = data.second;
59
60 // Refill our data buffer with patched opcodes.
61 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
62 size_t stream_pos = 0;
63 for (const DelayedAdvancePC& advance : advances) {
64 DCHECK_GE(advance.stream_pos, stream_pos);
65 // Copy old data up to the point where advance was issued.
66 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
67 stream_pos = advance.stream_pos;
68 // Insert the advance command with its final offset.
69 size_t final_pc = GetAdjustedPosition(advance.pc);
70 cfi().AdvancePC(final_pc);
71 }
72 // Copy the final segment if any.
73 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
74}
75
76void Mips64Assembler::EmitBranches() {
77 CHECK(!overwriting_);
78 // Switch from appending instructions at the end of the buffer to overwriting
79 // existing instructions (branch placeholders) in the buffer.
80 overwriting_ = true;
81 for (auto& branch : branches_) {
82 EmitBranch(&branch);
83 }
84 overwriting_ = false;
85}
86
Alexey Frunze4dda3372015-06-01 18:31:49 -070087void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070088 if (overwriting_) {
89 // Branches to labels are emitted into their placeholders here.
90 buffer_.Store<uint32_t>(overwrite_location_, value);
91 overwrite_location_ += sizeof(uint32_t);
92 } else {
93 // Other instructions are simply appended at the end here.
94 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
95 buffer_.Emit<uint32_t>(value);
96 }
Andreas Gampe57b34292015-01-14 15:45:59 -080097}
98
99void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
100 int shamt, int funct) {
101 CHECK_NE(rs, kNoGpuRegister);
102 CHECK_NE(rt, kNoGpuRegister);
103 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700104 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
105 static_cast<uint32_t>(rs) << kRsShift |
106 static_cast<uint32_t>(rt) << kRtShift |
107 static_cast<uint32_t>(rd) << kRdShift |
108 shamt << kShamtShift |
109 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800110 Emit(encoding);
111}
112
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700113void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
114 int shamt, int funct) {
115 CHECK_NE(rs, kNoGpuRegister);
116 CHECK_NE(rd, kNoGpuRegister);
117 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
118 static_cast<uint32_t>(rs) << kRsShift |
119 static_cast<uint32_t>(ZERO) << kRtShift |
120 static_cast<uint32_t>(rd) << kRdShift |
121 shamt << kShamtShift |
122 funct;
123 Emit(encoding);
124}
125
126void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
127 int shamt, int funct) {
128 CHECK_NE(rt, kNoGpuRegister);
129 CHECK_NE(rd, kNoGpuRegister);
130 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
131 static_cast<uint32_t>(ZERO) << kRsShift |
132 static_cast<uint32_t>(rt) << kRtShift |
133 static_cast<uint32_t>(rd) << kRdShift |
134 shamt << kShamtShift |
135 funct;
136 Emit(encoding);
137}
138
Andreas Gampe57b34292015-01-14 15:45:59 -0800139void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
140 CHECK_NE(rs, kNoGpuRegister);
141 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700142 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
143 static_cast<uint32_t>(rs) << kRsShift |
144 static_cast<uint32_t>(rt) << kRtShift |
145 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800146 Emit(encoding);
147}
148
Alexey Frunze4dda3372015-06-01 18:31:49 -0700149void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
150 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700151 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700152 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
153 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700154 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700155 Emit(encoding);
156}
157
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700158void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
159 CHECK(IsUint<26>(imm26)) << imm26;
160 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800161 Emit(encoding);
162}
163
164void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700165 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800166 CHECK_NE(ft, kNoFpuRegister);
167 CHECK_NE(fs, kNoFpuRegister);
168 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700169 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
170 fmt << kFmtShift |
171 static_cast<uint32_t>(ft) << kFtShift |
172 static_cast<uint32_t>(fs) << kFsShift |
173 static_cast<uint32_t>(fd) << kFdShift |
174 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800175 Emit(encoding);
176}
177
Alexey Frunze4dda3372015-06-01 18:31:49 -0700178void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
179 CHECK_NE(ft, kNoFpuRegister);
180 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
181 fmt << kFmtShift |
182 static_cast<uint32_t>(ft) << kFtShift |
183 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800184 Emit(encoding);
185}
186
Andreas Gampe57b34292015-01-14 15:45:59 -0800187void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
188 EmitR(0, rs, rt, rd, 0, 0x21);
189}
190
191void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
192 EmitI(0x9, rs, rt, imm16);
193}
194
Alexey Frunze4dda3372015-06-01 18:31:49 -0700195void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
196 EmitR(0, rs, rt, rd, 0, 0x2d);
197}
198
Andreas Gampe57b34292015-01-14 15:45:59 -0800199void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
200 EmitI(0x19, rs, rt, imm16);
201}
202
Andreas Gampe57b34292015-01-14 15:45:59 -0800203void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
204 EmitR(0, rs, rt, rd, 0, 0x23);
205}
206
Alexey Frunze4dda3372015-06-01 18:31:49 -0700207void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
208 EmitR(0, rs, rt, rd, 0, 0x2f);
209}
210
Alexey Frunze4dda3372015-06-01 18:31:49 -0700211void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
212 EmitR(0, rs, rt, rd, 2, 0x18);
213}
214
Alexey Frunzec857c742015-09-23 15:12:39 -0700215void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
216 EmitR(0, rs, rt, rd, 3, 0x18);
217}
218
Alexey Frunze4dda3372015-06-01 18:31:49 -0700219void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
220 EmitR(0, rs, rt, rd, 2, 0x1a);
221}
222
223void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
224 EmitR(0, rs, rt, rd, 3, 0x1a);
225}
226
227void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
228 EmitR(0, rs, rt, rd, 2, 0x1b);
229}
230
231void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
232 EmitR(0, rs, rt, rd, 3, 0x1b);
233}
234
235void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
236 EmitR(0, rs, rt, rd, 2, 0x1c);
237}
238
Alexey Frunzec857c742015-09-23 15:12:39 -0700239void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
240 EmitR(0, rs, rt, rd, 3, 0x1c);
241}
242
Alexey Frunze4dda3372015-06-01 18:31:49 -0700243void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
244 EmitR(0, rs, rt, rd, 2, 0x1e);
245}
246
247void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
248 EmitR(0, rs, rt, rd, 3, 0x1e);
249}
250
251void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
252 EmitR(0, rs, rt, rd, 2, 0x1f);
253}
254
255void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
256 EmitR(0, rs, rt, rd, 3, 0x1f);
257}
258
Andreas Gampe57b34292015-01-14 15:45:59 -0800259void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
260 EmitR(0, rs, rt, rd, 0, 0x24);
261}
262
263void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
264 EmitI(0xc, rs, rt, imm16);
265}
266
267void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
268 EmitR(0, rs, rt, rd, 0, 0x25);
269}
270
271void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
272 EmitI(0xd, rs, rt, imm16);
273}
274
275void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
276 EmitR(0, rs, rt, rd, 0, 0x26);
277}
278
279void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
280 EmitI(0xe, rs, rt, imm16);
281}
282
283void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
284 EmitR(0, rs, rt, rd, 0, 0x27);
285}
286
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700287void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
288 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
289}
290
291void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
292 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
293}
294
Alexey Frunze4dda3372015-06-01 18:31:49 -0700295void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
296 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800297}
298
Alexey Frunze4dda3372015-06-01 18:31:49 -0700299void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
300 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800301}
302
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700303void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
304 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
305}
306
307void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
308 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
309}
310
Lazar Trsicd9672662015-09-03 17:33:01 +0200311void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
312 CHECK(IsUint<5>(pos)) << pos;
313 CHECK(IsUint<5>(size - 1)) << size;
314 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
315}
316
317void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
318 CHECK(IsUint<5>(pos - 32)) << pos;
319 CHECK(IsUint<5>(size - 1)) << size;
320 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
321 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800322}
323
Chris Larsene3660592016-11-09 11:13:42 -0800324void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
325 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
326 int sa = saPlusOne - 1;
327 EmitR(0x0, rs, rt, rd, sa, 0x05);
328}
329
330void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
331 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
332 int sa = saPlusOne - 1;
333 EmitR(0x0, rs, rt, rd, sa, 0x15);
334}
335
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700336void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
337 EmitRtd(0x1f, rt, rd, 2, 0x20);
338}
339
340void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200341 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700342 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
343}
344
345void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200346 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700347 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
348}
349
350void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200351 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700352 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
353}
354
355void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200356 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700357 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
358}
359
Alexey Frunze4dda3372015-06-01 18:31:49 -0700360void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
361 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
362}
363
364void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
365 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
366}
367
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700368void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
369 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
370}
371
Alexey Frunze4dda3372015-06-01 18:31:49 -0700372void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
373 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
374}
375
376void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800377 EmitR(0, rs, rt, rd, 0, 0x04);
378}
379
Chris Larsen9aebff22015-09-22 17:54:15 -0700380void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
381 EmitR(0, rs, rt, rd, 1, 0x06);
382}
383
Alexey Frunze4dda3372015-06-01 18:31:49 -0700384void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800385 EmitR(0, rs, rt, rd, 0, 0x06);
386}
387
Alexey Frunze4dda3372015-06-01 18:31:49 -0700388void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800389 EmitR(0, rs, rt, rd, 0, 0x07);
390}
391
Alexey Frunze4dda3372015-06-01 18:31:49 -0700392void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
393 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
394}
395
396void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
397 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
398}
399
Chris Larsen9aebff22015-09-22 17:54:15 -0700400void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
401 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
402}
403
Alexey Frunze4dda3372015-06-01 18:31:49 -0700404void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
405 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
406}
407
408void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
409 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
410}
411
412void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
413 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
414}
415
Chris Larsen9aebff22015-09-22 17:54:15 -0700416void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
417 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
418}
419
Alexey Frunze4dda3372015-06-01 18:31:49 -0700420void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
421 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
422}
423
424void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
425 EmitR(0, rs, rt, rd, 0, 0x14);
426}
427
428void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
429 EmitR(0, rs, rt, rd, 0, 0x16);
430}
431
Chris Larsen9aebff22015-09-22 17:54:15 -0700432void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
433 EmitR(0, rs, rt, rd, 1, 0x16);
434}
435
Alexey Frunze4dda3372015-06-01 18:31:49 -0700436void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
437 EmitR(0, rs, rt, rd, 0, 0x17);
438}
439
Andreas Gampe57b34292015-01-14 15:45:59 -0800440void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
441 EmitI(0x20, rs, rt, imm16);
442}
443
444void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
445 EmitI(0x21, rs, rt, imm16);
446}
447
448void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
449 EmitI(0x23, rs, rt, imm16);
450}
451
452void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
453 EmitI(0x37, rs, rt, imm16);
454}
455
456void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
457 EmitI(0x24, rs, rt, imm16);
458}
459
460void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
461 EmitI(0x25, rs, rt, imm16);
462}
463
Douglas Leungd90957f2015-04-30 19:22:49 -0700464void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
465 EmitI(0x27, rs, rt, imm16);
466}
467
Alexey Frunze19f6c692016-11-30 19:19:55 -0800468void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
469 CHECK(IsUint<19>(imm19)) << imm19;
470 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
471}
472
473void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
474 CHECK(IsUint<19>(imm19)) << imm19;
475 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
476}
477
478void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
479 CHECK(IsUint<18>(imm18)) << imm18;
480 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
481}
482
Andreas Gampe57b34292015-01-14 15:45:59 -0800483void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
484 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
485}
486
Alexey Frunze0960ac52016-12-20 17:24:59 -0800487void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
488 EmitI(0xf, rs, rt, imm16);
489}
490
Alexey Frunze4dda3372015-06-01 18:31:49 -0700491void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
492 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
493}
494
495void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
496 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
497}
498
499void Mips64Assembler::Sync(uint32_t stype) {
500 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
501 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
502}
503
Andreas Gampe57b34292015-01-14 15:45:59 -0800504void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
505 EmitI(0x28, rs, rt, imm16);
506}
507
508void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
509 EmitI(0x29, rs, rt, imm16);
510}
511
512void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
513 EmitI(0x2b, rs, rt, imm16);
514}
515
516void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
517 EmitI(0x3f, rs, rt, imm16);
518}
519
520void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
521 EmitR(0, rs, rt, rd, 0, 0x2a);
522}
523
524void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
525 EmitR(0, rs, rt, rd, 0, 0x2b);
526}
527
528void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
529 EmitI(0xa, rs, rt, imm16);
530}
531
532void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
533 EmitI(0xb, rs, rt, imm16);
534}
535
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700536void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
537 EmitR(0, rs, rt, rd, 0, 0x35);
538}
539
540void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
541 EmitR(0, rs, rt, rd, 0, 0x37);
542}
543
544void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
545 EmitRsd(0, rs, rd, 0x01, 0x10);
546}
547
548void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
549 EmitRsd(0, rs, rd, 0x01, 0x11);
550}
551
552void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
553 EmitRsd(0, rs, rd, 0x01, 0x12);
554}
555
556void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
557 EmitRsd(0, rs, rd, 0x01, 0x13);
558}
559
Alexey Frunze4dda3372015-06-01 18:31:49 -0700560void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
561 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800562}
563
564void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700565 Jalr(RA, rs);
566}
567
568void Mips64Assembler::Jr(GpuRegister rs) {
569 Jalr(ZERO, rs);
570}
571
572void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
573 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
574}
575
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700576void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
577 CHECK(IsUint<19>(imm19)) << imm19;
578 EmitI21(0x3B, rs, imm19);
579}
580
581void Mips64Assembler::Bc(uint32_t imm26) {
582 EmitI26(0x32, imm26);
583}
584
Alexey Frunze19f6c692016-11-30 19:19:55 -0800585void Mips64Assembler::Balc(uint32_t imm26) {
586 EmitI26(0x3A, imm26);
587}
588
Alexey Frunze4dda3372015-06-01 18:31:49 -0700589void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
590 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
591}
592
593void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
594 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
595}
596
597void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
598 CHECK_NE(rs, ZERO);
599 CHECK_NE(rt, ZERO);
600 CHECK_NE(rs, rt);
601 EmitI(0x17, rs, rt, imm16);
602}
603
604void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
605 CHECK_NE(rt, ZERO);
606 EmitI(0x17, rt, rt, imm16);
607}
608
609void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
610 CHECK_NE(rt, ZERO);
611 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
612}
613
614void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
615 CHECK_NE(rs, ZERO);
616 CHECK_NE(rt, ZERO);
617 CHECK_NE(rs, rt);
618 EmitI(0x16, rs, rt, imm16);
619}
620
621void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
622 CHECK_NE(rt, ZERO);
623 EmitI(0x16, rt, rt, imm16);
624}
625
626void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
627 CHECK_NE(rt, ZERO);
628 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
629}
630
631void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
632 CHECK_NE(rs, ZERO);
633 CHECK_NE(rt, ZERO);
634 CHECK_NE(rs, rt);
635 EmitI(0x7, rs, rt, imm16);
636}
637
638void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
639 CHECK_NE(rs, ZERO);
640 CHECK_NE(rt, ZERO);
641 CHECK_NE(rs, rt);
642 EmitI(0x6, rs, rt, imm16);
643}
644
645void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
646 CHECK_NE(rs, ZERO);
647 CHECK_NE(rt, ZERO);
648 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700649 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700650}
651
652void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
653 CHECK_NE(rs, ZERO);
654 CHECK_NE(rt, ZERO);
655 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700656 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700657}
658
659void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
660 CHECK_NE(rs, ZERO);
661 EmitI21(0x36, rs, imm21);
662}
663
664void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
665 CHECK_NE(rs, ZERO);
666 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800667}
668
Alexey Frunze299a9392015-12-08 16:08:02 -0800669void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
670 EmitFI(0x11, 0x9, ft, imm16);
671}
672
673void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
674 EmitFI(0x11, 0xD, ft, imm16);
675}
676
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700677void Mips64Assembler::EmitBcondc(BranchCondition cond,
678 GpuRegister rs,
679 GpuRegister rt,
680 uint32_t imm16_21) {
681 switch (cond) {
682 case kCondLT:
683 Bltc(rs, rt, imm16_21);
684 break;
685 case kCondGE:
686 Bgec(rs, rt, imm16_21);
687 break;
688 case kCondLE:
689 Bgec(rt, rs, imm16_21);
690 break;
691 case kCondGT:
692 Bltc(rt, rs, imm16_21);
693 break;
694 case kCondLTZ:
695 CHECK_EQ(rt, ZERO);
696 Bltzc(rs, imm16_21);
697 break;
698 case kCondGEZ:
699 CHECK_EQ(rt, ZERO);
700 Bgezc(rs, imm16_21);
701 break;
702 case kCondLEZ:
703 CHECK_EQ(rt, ZERO);
704 Blezc(rs, imm16_21);
705 break;
706 case kCondGTZ:
707 CHECK_EQ(rt, ZERO);
708 Bgtzc(rs, imm16_21);
709 break;
710 case kCondEQ:
711 Beqc(rs, rt, imm16_21);
712 break;
713 case kCondNE:
714 Bnec(rs, rt, imm16_21);
715 break;
716 case kCondEQZ:
717 CHECK_EQ(rt, ZERO);
718 Beqzc(rs, imm16_21);
719 break;
720 case kCondNEZ:
721 CHECK_EQ(rt, ZERO);
722 Bnezc(rs, imm16_21);
723 break;
724 case kCondLTU:
725 Bltuc(rs, rt, imm16_21);
726 break;
727 case kCondGEU:
728 Bgeuc(rs, rt, imm16_21);
729 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800730 case kCondF:
731 CHECK_EQ(rt, ZERO);
732 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
733 break;
734 case kCondT:
735 CHECK_EQ(rt, ZERO);
736 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
737 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700738 case kUncond:
739 LOG(FATAL) << "Unexpected branch condition " << cond;
740 UNREACHABLE();
741 }
742}
743
Andreas Gampe57b34292015-01-14 15:45:59 -0800744void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
745 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
746}
747
748void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
749 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
750}
751
752void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
753 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
754}
755
756void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
757 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
758}
759
760void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700761 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800762}
763
764void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700765 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800766}
767
768void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700769 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800770}
771
772void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700773 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800774}
775
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700776void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
777 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
778}
779
780void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
781 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
782}
783
784void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
785 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
786}
787
788void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
789 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
790}
791
Andreas Gampe57b34292015-01-14 15:45:59 -0800792void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
793 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
794}
795
796void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700797 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
798}
799
800void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
801 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
802}
803
804void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
805 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
806}
807
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700808void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
809 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
810}
811
812void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
813 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
814}
815
816void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
817 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
818}
819
820void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
821 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
822}
823
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800824void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
825 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
826}
827
828void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
829 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
830}
831
832void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
833 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
834}
835
836void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
837 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
838}
839
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700840void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
841 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
842}
843
844void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
845 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
846}
847
848void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
849 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
850}
851
852void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
853 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
854}
855
856void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
857 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
858}
859
860void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
861 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
862}
863
864void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
865 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
866}
867
868void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
869 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
870}
871
872void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
873 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
874}
875
876void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
877 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
878}
879
880void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
881 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
882}
883
884void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
885 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
886}
887
888void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
889 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
890}
891
892void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
893 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
894}
895
896void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
897 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
898}
899
900void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
901 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
902}
903
904void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
905 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
906}
907
908void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
909 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
910}
911
Alexey Frunze299a9392015-12-08 16:08:02 -0800912void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
913 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
914}
915
916void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
917 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
918}
919
920void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
921 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
922}
923
924void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
925 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
926}
927
928void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
929 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
930}
931
932void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
933 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
934}
935
936void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
937 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
938}
939
940void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
941 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
942}
943
944void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
945 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
946}
947
948void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
949 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
950}
951
952void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
953 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
954}
955
956void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
957 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
958}
959
960void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
961 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
962}
963
964void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
965 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
966}
967
968void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
969 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
970}
971
972void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
973 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
974}
975
976void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
977 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
978}
979
980void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
981 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
982}
983
984void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
985 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
986}
987
988void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
989 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
990}
991
Alexey Frunze4dda3372015-06-01 18:31:49 -0700992void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
993 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
994}
995
996void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
997 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
998}
999
1000void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
1001 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
1002}
1003
1004void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
1005 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -08001006}
1007
Chris Larsen51417632015-10-02 13:24:25 -07001008void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
1009 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
1010}
1011
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001012void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
1013 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
1014}
1015
Andreas Gampe57b34292015-01-14 15:45:59 -08001016void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
1017 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1018}
1019
Lazar Trsicd9672662015-09-03 17:33:01 +02001020void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1021 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1022}
1023
Alexey Frunze4dda3372015-06-01 18:31:49 -07001024void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1025 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1026}
1027
Lazar Trsicd9672662015-09-03 17:33:01 +02001028void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1029 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1030}
1031
Alexey Frunze4dda3372015-06-01 18:31:49 -07001032void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1033 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1034}
1035
1036void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1037 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001038}
1039
1040void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1041 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1042}
1043
1044void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1045 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1046}
1047
1048void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1049 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1050}
1051
1052void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1053 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1054}
1055
1056void Mips64Assembler::Break() {
1057 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1058 static_cast<GpuRegister>(0), 0, 0xD);
1059}
1060
1061void Mips64Assembler::Nop() {
1062 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1063 static_cast<GpuRegister>(0), 0, 0x0);
1064}
1065
Alexey Frunze4dda3372015-06-01 18:31:49 -07001066void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1067 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001068}
1069
Alexey Frunze4dda3372015-06-01 18:31:49 -07001070void Mips64Assembler::Clear(GpuRegister rd) {
1071 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001072}
1073
Alexey Frunze4dda3372015-06-01 18:31:49 -07001074void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1075 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001076}
1077
Alexey Frunze4dda3372015-06-01 18:31:49 -07001078void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001079 TemplateLoadConst32(this, rd, value);
1080}
1081
1082// This function is only used for testing purposes.
1083void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001084}
1085
Alexey Frunze4dda3372015-06-01 18:31:49 -07001086void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001087 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001088}
1089
Alexey Frunze0960ac52016-12-20 17:24:59 -08001090void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) {
1091 if (IsInt<16>(value)) {
1092 Addiu(rt, rs, value);
1093 } else {
1094 int16_t high = High16Bits(value);
1095 int16_t low = Low16Bits(value);
1096 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
1097 Aui(rt, rs, high);
1098 if (low != 0) {
1099 Addiu(rt, rt, low);
1100 }
1101 }
1102}
1103
Alexey Frunze4dda3372015-06-01 18:31:49 -07001104void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1105 if (IsInt<16>(value)) {
1106 Daddiu(rt, rs, value);
1107 } else {
1108 LoadConst64(rtmp, value);
1109 Daddu(rt, rs, rtmp);
1110 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001111}
1112
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001113void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1114 Mips64Assembler::Branch::Type short_type,
1115 Mips64Assembler::Branch::Type long_type) {
1116 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1117}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001118
Alexey Frunze19f6c692016-11-30 19:19:55 -08001119void Mips64Assembler::Branch::InitializeType(Type initial_type) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001120 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001121 switch (initial_type) {
1122 case kLabel:
1123 case kLiteral:
1124 case kLiteralUnsigned:
1125 case kLiteralLong:
1126 CHECK(!IsResolved());
1127 type_ = initial_type;
1128 break;
1129 case kCall:
1130 InitShortOrLong(offset_size, kCall, kLongCall);
1131 break;
1132 case kCondBranch:
1133 switch (condition_) {
1134 case kUncond:
1135 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1136 break;
1137 case kCondEQZ:
1138 case kCondNEZ:
1139 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1140 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1141 break;
1142 default:
1143 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1144 break;
1145 }
1146 break;
1147 default:
1148 LOG(FATAL) << "Unexpected branch type " << initial_type;
1149 UNREACHABLE();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001150 }
1151 old_type_ = type_;
1152}
1153
1154bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1155 switch (condition) {
1156 case kCondLT:
1157 case kCondGT:
1158 case kCondNE:
1159 case kCondLTU:
1160 return lhs == rhs;
1161 default:
1162 return false;
1163 }
1164}
1165
1166bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1167 GpuRegister lhs,
1168 GpuRegister rhs) {
1169 switch (condition) {
1170 case kUncond:
1171 return true;
1172 case kCondGE:
1173 case kCondLE:
1174 case kCondEQ:
1175 case kCondGEU:
1176 return lhs == rhs;
1177 default:
1178 return false;
1179 }
1180}
1181
Alexey Frunze19f6c692016-11-30 19:19:55 -08001182Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001183 : old_location_(location),
1184 location_(location),
1185 target_(target),
1186 lhs_reg_(ZERO),
1187 rhs_reg_(ZERO),
1188 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001189 InitializeType(is_call ? kCall : kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001190}
1191
1192Mips64Assembler::Branch::Branch(uint32_t location,
1193 uint32_t target,
1194 Mips64Assembler::BranchCondition condition,
1195 GpuRegister lhs_reg,
1196 GpuRegister rhs_reg)
1197 : old_location_(location),
1198 location_(location),
1199 target_(target),
1200 lhs_reg_(lhs_reg),
1201 rhs_reg_(rhs_reg),
1202 condition_(condition) {
1203 CHECK_NE(condition, kUncond);
1204 switch (condition) {
1205 case kCondEQ:
1206 case kCondNE:
1207 case kCondLT:
1208 case kCondGE:
1209 case kCondLE:
1210 case kCondGT:
1211 case kCondLTU:
1212 case kCondGEU:
1213 CHECK_NE(lhs_reg, ZERO);
1214 CHECK_NE(rhs_reg, ZERO);
1215 break;
1216 case kCondLTZ:
1217 case kCondGEZ:
1218 case kCondLEZ:
1219 case kCondGTZ:
1220 case kCondEQZ:
1221 case kCondNEZ:
1222 CHECK_NE(lhs_reg, ZERO);
1223 CHECK_EQ(rhs_reg, ZERO);
1224 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001225 case kCondF:
1226 case kCondT:
1227 CHECK_EQ(rhs_reg, ZERO);
1228 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001229 case kUncond:
1230 UNREACHABLE();
1231 }
1232 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1233 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1234 // Branch condition is always true, make the branch unconditional.
1235 condition_ = kUncond;
1236 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001237 InitializeType(kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001238}
1239
Alexey Frunze19f6c692016-11-30 19:19:55 -08001240Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001241 : old_location_(location),
1242 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08001243 target_(kUnresolved),
1244 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001245 rhs_reg_(ZERO),
1246 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001247 CHECK_NE(dest_reg, ZERO);
1248 InitializeType(label_or_literal_type);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001249}
1250
1251Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1252 Mips64Assembler::BranchCondition cond) {
1253 switch (cond) {
1254 case kCondLT:
1255 return kCondGE;
1256 case kCondGE:
1257 return kCondLT;
1258 case kCondLE:
1259 return kCondGT;
1260 case kCondGT:
1261 return kCondLE;
1262 case kCondLTZ:
1263 return kCondGEZ;
1264 case kCondGEZ:
1265 return kCondLTZ;
1266 case kCondLEZ:
1267 return kCondGTZ;
1268 case kCondGTZ:
1269 return kCondLEZ;
1270 case kCondEQ:
1271 return kCondNE;
1272 case kCondNE:
1273 return kCondEQ;
1274 case kCondEQZ:
1275 return kCondNEZ;
1276 case kCondNEZ:
1277 return kCondEQZ;
1278 case kCondLTU:
1279 return kCondGEU;
1280 case kCondGEU:
1281 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001282 case kCondF:
1283 return kCondT;
1284 case kCondT:
1285 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001286 case kUncond:
1287 LOG(FATAL) << "Unexpected branch condition " << cond;
1288 }
1289 UNREACHABLE();
1290}
1291
1292Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1293 return type_;
1294}
1295
1296Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1297 return condition_;
1298}
1299
1300GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1301 return lhs_reg_;
1302}
1303
1304GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1305 return rhs_reg_;
1306}
1307
1308uint32_t Mips64Assembler::Branch::GetTarget() const {
1309 return target_;
1310}
1311
1312uint32_t Mips64Assembler::Branch::GetLocation() const {
1313 return location_;
1314}
1315
1316uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1317 return old_location_;
1318}
1319
1320uint32_t Mips64Assembler::Branch::GetLength() const {
1321 return branch_info_[type_].length;
1322}
1323
1324uint32_t Mips64Assembler::Branch::GetOldLength() const {
1325 return branch_info_[old_type_].length;
1326}
1327
1328uint32_t Mips64Assembler::Branch::GetSize() const {
1329 return GetLength() * sizeof(uint32_t);
1330}
1331
1332uint32_t Mips64Assembler::Branch::GetOldSize() const {
1333 return GetOldLength() * sizeof(uint32_t);
1334}
1335
1336uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1337 return GetLocation() + GetSize();
1338}
1339
1340uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1341 return GetOldLocation() + GetOldSize();
1342}
1343
1344bool Mips64Assembler::Branch::IsLong() const {
1345 switch (type_) {
1346 // Short branches.
1347 case kUncondBranch:
1348 case kCondBranch:
1349 case kCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001350 // Near label.
1351 case kLabel:
1352 // Near literals.
1353 case kLiteral:
1354 case kLiteralUnsigned:
1355 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001356 return false;
1357 // Long branches.
1358 case kLongUncondBranch:
1359 case kLongCondBranch:
1360 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001361 // Far label.
1362 case kFarLabel:
1363 // Far literals.
1364 case kFarLiteral:
1365 case kFarLiteralUnsigned:
1366 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001367 return true;
1368 }
1369 UNREACHABLE();
1370}
1371
1372bool Mips64Assembler::Branch::IsResolved() const {
1373 return target_ != kUnresolved;
1374}
1375
1376Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1377 OffsetBits offset_size =
1378 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1379 ? kOffset23
1380 : branch_info_[type_].offset_size;
1381 return offset_size;
1382}
1383
1384Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1385 uint32_t target) {
1386 // For unresolved targets assume the shortest encoding
1387 // (later it will be made longer if needed).
1388 if (target == kUnresolved)
1389 return kOffset16;
1390 int64_t distance = static_cast<int64_t>(target) - location;
1391 // To simplify calculations in composite branches consisting of multiple instructions
1392 // bump up the distance by a value larger than the max byte size of a composite branch.
1393 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1394 if (IsInt<kOffset16>(distance))
1395 return kOffset16;
1396 else if (IsInt<kOffset18>(distance))
1397 return kOffset18;
1398 else if (IsInt<kOffset21>(distance))
1399 return kOffset21;
1400 else if (IsInt<kOffset23>(distance))
1401 return kOffset23;
1402 else if (IsInt<kOffset28>(distance))
1403 return kOffset28;
1404 return kOffset32;
1405}
1406
1407void Mips64Assembler::Branch::Resolve(uint32_t target) {
1408 target_ = target;
1409}
1410
1411void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1412 if (location_ > expand_location) {
1413 location_ += delta;
1414 }
1415 if (!IsResolved()) {
1416 return; // Don't know the target yet.
1417 }
1418 if (target_ > expand_location) {
1419 target_ += delta;
1420 }
1421}
1422
1423void Mips64Assembler::Branch::PromoteToLong() {
1424 switch (type_) {
1425 // Short branches.
1426 case kUncondBranch:
1427 type_ = kLongUncondBranch;
1428 break;
1429 case kCondBranch:
1430 type_ = kLongCondBranch;
1431 break;
1432 case kCall:
1433 type_ = kLongCall;
1434 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001435 // Near label.
1436 case kLabel:
1437 type_ = kFarLabel;
1438 break;
1439 // Near literals.
1440 case kLiteral:
1441 type_ = kFarLiteral;
1442 break;
1443 case kLiteralUnsigned:
1444 type_ = kFarLiteralUnsigned;
1445 break;
1446 case kLiteralLong:
1447 type_ = kFarLiteralLong;
1448 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001449 default:
1450 // Note: 'type_' is already long.
1451 break;
1452 }
1453 CHECK(IsLong());
1454}
1455
1456uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1457 // If the branch is still unresolved or already long, nothing to do.
1458 if (IsLong() || !IsResolved()) {
1459 return 0;
1460 }
1461 // Promote the short branch to long if the offset size is too small
1462 // to hold the distance between location_ and target_.
1463 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1464 PromoteToLong();
1465 uint32_t old_size = GetOldSize();
1466 uint32_t new_size = GetSize();
1467 CHECK_GT(new_size, old_size);
1468 return new_size - old_size;
1469 }
1470 // The following logic is for debugging/testing purposes.
1471 // Promote some short branches to long when it's not really required.
1472 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1473 int64_t distance = static_cast<int64_t>(target_) - location_;
1474 distance = (distance >= 0) ? distance : -distance;
1475 if (distance >= max_short_distance) {
1476 PromoteToLong();
1477 uint32_t old_size = GetOldSize();
1478 uint32_t new_size = GetSize();
1479 CHECK_GT(new_size, old_size);
1480 return new_size - old_size;
1481 }
1482 }
1483 return 0;
1484}
1485
1486uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1487 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1488}
1489
1490uint32_t Mips64Assembler::Branch::GetOffset() const {
1491 CHECK(IsResolved());
1492 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1493 // Calculate the byte distance between instructions and also account for
1494 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001495 uint32_t offset_location = GetOffsetLocation();
1496 if (type_ == kLiteralLong) {
1497 // Special case for the ldpc instruction, whose address (PC) is rounded down to
1498 // a multiple of 8 before adding the offset.
1499 // Note, branch promotion has already taken care of aligning `target_` to an
1500 // address that's a multiple of 8.
1501 offset_location = RoundDown(offset_location, sizeof(uint64_t));
1502 }
1503 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001504 // Prepare the offset for encoding into the instruction(s).
1505 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1506 return offset;
1507}
1508
1509Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1510 CHECK_LT(branch_id, branches_.size());
1511 return &branches_[branch_id];
1512}
1513
1514const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1515 CHECK_LT(branch_id, branches_.size());
1516 return &branches_[branch_id];
1517}
1518
1519void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001520 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001521 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001522
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001523 // Walk the list of branches referring to and preceding this label.
1524 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001525 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001526 uint32_t branch_id = label->Position();
1527 Branch* branch = GetBranch(branch_id);
1528 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001529
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001530 uint32_t branch_location = branch->GetLocation();
1531 // Extract the location of the previous branch in the list (walking the list backwards;
1532 // the previous branch ID was stored in the space reserved for this branch).
1533 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001534
1535 // On to the previous branch in the list...
1536 label->position_ = prev;
1537 }
1538
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001539 // Now make the label object contain its own location (relative to the end of the preceding
1540 // branch, if any; it will be used by the branches referring to and following this label).
1541 label->prev_branch_id_plus_one_ = branches_.size();
1542 if (label->prev_branch_id_plus_one_) {
1543 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1544 const Branch* branch = GetBranch(branch_id);
1545 bound_pc -= branch->GetEndLocation();
1546 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001547 label->BindTo(bound_pc);
1548}
1549
Alexey Frunze19f6c692016-11-30 19:19:55 -08001550uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001551 CHECK(label->IsBound());
1552 uint32_t target = label->Position();
1553 if (label->prev_branch_id_plus_one_) {
1554 // Get label location based on the branch preceding it.
1555 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1556 const Branch* branch = GetBranch(branch_id);
1557 target += branch->GetEndLocation();
1558 }
1559 return target;
1560}
1561
1562uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1563 // We can reconstruct the adjustment by going through all the branches from the beginning
1564 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1565 // with increasing old_position, we can use the data from last AdjustedPosition() to
1566 // continue where we left off and the whole loop should be O(m+n) where m is the number
1567 // of positions to adjust and n is the number of branches.
1568 if (old_position < last_old_position_) {
1569 last_position_adjustment_ = 0;
1570 last_old_position_ = 0;
1571 last_branch_id_ = 0;
1572 }
1573 while (last_branch_id_ != branches_.size()) {
1574 const Branch* branch = GetBranch(last_branch_id_);
1575 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1576 break;
1577 }
1578 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1579 ++last_branch_id_;
1580 }
1581 last_old_position_ = old_position;
1582 return old_position + last_position_adjustment_;
1583}
1584
1585void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1586 uint32_t length = branches_.back().GetLength();
1587 if (!label->IsBound()) {
1588 // Branch forward (to a following label), distance is unknown.
1589 // The first branch forward will contain 0, serving as the terminator of
1590 // the list of forward-reaching branches.
1591 Emit(label->position_);
1592 length--;
1593 // Now make the label object point to this branch
1594 // (this forms a linked list of branches preceding this label).
1595 uint32_t branch_id = branches_.size() - 1;
1596 label->LinkTo(branch_id);
1597 }
1598 // Reserve space for the branch.
1599 while (length--) {
1600 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001601 }
1602}
1603
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001604void Mips64Assembler::Buncond(Mips64Label* label) {
1605 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001606 branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001607 FinalizeLabeledBranch(label);
1608}
1609
1610void Mips64Assembler::Bcond(Mips64Label* label,
1611 BranchCondition condition,
1612 GpuRegister lhs,
1613 GpuRegister rhs) {
1614 // If lhs = rhs, this can be a NOP.
1615 if (Branch::IsNop(condition, lhs, rhs)) {
1616 return;
1617 }
1618 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1619 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1620 FinalizeLabeledBranch(label);
1621}
1622
Alexey Frunze19f6c692016-11-30 19:19:55 -08001623void Mips64Assembler::Call(Mips64Label* label) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001624 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001625 branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001626 FinalizeLabeledBranch(label);
1627}
1628
Alexey Frunze19f6c692016-11-30 19:19:55 -08001629void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
1630 // Label address loads are treated as pseudo branches since they require very similar handling.
1631 DCHECK(!label->IsBound());
1632 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
1633 FinalizeLabeledBranch(label);
1634}
1635
1636Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
1637 // We don't support byte and half-word literals.
1638 if (size == 4u) {
1639 literals_.emplace_back(size, data);
1640 return &literals_.back();
1641 } else {
1642 DCHECK_EQ(size, 8u);
1643 long_literals_.emplace_back(size, data);
1644 return &long_literals_.back();
1645 }
1646}
1647
1648void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
1649 LoadOperandType load_type,
1650 Literal* literal) {
1651 // Literal loads are treated as pseudo branches since they require very similar handling.
1652 Branch::Type literal_type;
1653 switch (load_type) {
1654 case kLoadWord:
1655 DCHECK_EQ(literal->GetSize(), 4u);
1656 literal_type = Branch::kLiteral;
1657 break;
1658 case kLoadUnsignedWord:
1659 DCHECK_EQ(literal->GetSize(), 4u);
1660 literal_type = Branch::kLiteralUnsigned;
1661 break;
1662 case kLoadDoubleword:
1663 DCHECK_EQ(literal->GetSize(), 8u);
1664 literal_type = Branch::kLiteralLong;
1665 break;
1666 default:
1667 LOG(FATAL) << "Unexpected literal load type " << load_type;
1668 UNREACHABLE();
1669 }
1670 Mips64Label* label = literal->GetLabel();
1671 DCHECK(!label->IsBound());
1672 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
1673 FinalizeLabeledBranch(label);
1674}
1675
Alexey Frunze0960ac52016-12-20 17:24:59 -08001676JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) {
1677 jump_tables_.emplace_back(std::move(labels));
1678 JumpTable* table = &jump_tables_.back();
1679 DCHECK(!table->GetLabel()->IsBound());
1680 return table;
1681}
1682
1683void Mips64Assembler::ReserveJumpTableSpace() {
1684 if (!jump_tables_.empty()) {
1685 for (JumpTable& table : jump_tables_) {
1686 Mips64Label* label = table.GetLabel();
1687 Bind(label);
1688
1689 // Bulk ensure capacity, as this may be large.
1690 size_t orig_size = buffer_.Size();
1691 size_t required_capacity = orig_size + table.GetSize();
1692 if (required_capacity > buffer_.Capacity()) {
1693 buffer_.ExtendCapacity(required_capacity);
1694 }
1695#ifndef NDEBUG
1696 buffer_.has_ensured_capacity_ = true;
1697#endif
1698
1699 // Fill the space with dummy data as the data is not final
1700 // until the branches have been promoted. And we shouldn't
1701 // be moving uninitialized data during branch promotion.
1702 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
1703 buffer_.Emit<uint32_t>(0x1abe1234u);
1704 }
1705
1706#ifndef NDEBUG
1707 buffer_.has_ensured_capacity_ = false;
1708#endif
1709 }
1710 }
1711}
1712
1713void Mips64Assembler::EmitJumpTables() {
1714 if (!jump_tables_.empty()) {
1715 CHECK(!overwriting_);
1716 // Switch from appending instructions at the end of the buffer to overwriting
1717 // existing instructions (here, jump tables) in the buffer.
1718 overwriting_ = true;
1719
1720 for (JumpTable& table : jump_tables_) {
1721 Mips64Label* table_label = table.GetLabel();
1722 uint32_t start = GetLabelLocation(table_label);
1723 overwrite_location_ = start;
1724
1725 for (Mips64Label* target : table.GetData()) {
1726 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
1727 // The table will contain target addresses relative to the table start.
1728 uint32_t offset = GetLabelLocation(target) - start;
1729 Emit(offset);
1730 }
1731 }
1732
1733 overwriting_ = false;
1734 }
1735}
1736
Alexey Frunze19f6c692016-11-30 19:19:55 -08001737void Mips64Assembler::EmitLiterals() {
1738 if (!literals_.empty()) {
1739 for (Literal& literal : literals_) {
1740 Mips64Label* label = literal.GetLabel();
1741 Bind(label);
1742 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1743 DCHECK_EQ(literal.GetSize(), 4u);
1744 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1745 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1746 }
1747 }
1748 }
1749 if (!long_literals_.empty()) {
1750 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
1751 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
1752 Emit(0); // NOP.
1753 for (Literal& literal : long_literals_) {
1754 Mips64Label* label = literal.GetLabel();
1755 Bind(label);
1756 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1757 DCHECK_EQ(literal.GetSize(), 8u);
1758 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1759 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1760 }
1761 }
1762 }
1763}
1764
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001765void Mips64Assembler::PromoteBranches() {
1766 // Promote short branches to long as necessary.
1767 bool changed;
1768 do {
1769 changed = false;
1770 for (auto& branch : branches_) {
1771 CHECK(branch.IsResolved());
1772 uint32_t delta = branch.PromoteIfNeeded();
1773 // If this branch has been promoted and needs to expand in size,
1774 // relocate all branches by the expansion size.
1775 if (delta) {
1776 changed = true;
1777 uint32_t expand_location = branch.GetLocation();
1778 for (auto& branch2 : branches_) {
1779 branch2.Relocate(expand_location, delta);
1780 }
1781 }
1782 }
1783 } while (changed);
1784
1785 // Account for branch expansion by resizing the code buffer
1786 // and moving the code in it to its final location.
1787 size_t branch_count = branches_.size();
1788 if (branch_count > 0) {
1789 // Resize.
1790 Branch& last_branch = branches_[branch_count - 1];
1791 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1792 uint32_t old_size = buffer_.Size();
1793 buffer_.Resize(old_size + size_delta);
1794 // Move the code residing between branch placeholders.
1795 uint32_t end = old_size;
1796 for (size_t i = branch_count; i > 0; ) {
1797 Branch& branch = branches_[--i];
1798 uint32_t size = end - branch.GetOldEndLocation();
1799 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1800 end = branch.GetOldLocation();
1801 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001802 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001803
1804 // Align 64-bit literals by moving them down by 4 bytes if needed.
1805 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
1806 if (!long_literals_.empty()) {
1807 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
1808 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
1809 size_t buf_size = buffer_.Size();
1810 // 64-bit literals must be at the very end of the buffer.
1811 CHECK_EQ(first_literal_location + lit_size, buf_size);
1812 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
1813 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
1814 // The 4 reserved bytes proved useless, reduce the buffer size.
1815 buffer_.Resize(buf_size - sizeof(uint32_t));
1816 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
1817 // offsets from PC to be generated.
1818 for (auto& branch : branches_) {
1819 uint32_t target = branch.GetTarget();
1820 if (target >= first_literal_location) {
1821 branch.Resolve(target - sizeof(uint32_t));
1822 }
1823 }
1824 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
1825 // we need to adjust the location of the literal's label as well.
1826 for (Literal& literal : long_literals_) {
1827 // Bound label's position is negative, hence incrementing it instead of decrementing.
1828 literal.GetLabel()->position_ += sizeof(uint32_t);
1829 }
1830 }
1831 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001832}
1833
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001834// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1835const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1836 // Short branches.
1837 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1838 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1839 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08001840 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
1841 // Near label.
1842 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
1843 // Near literals.
1844 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
1845 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
1846 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001847 // Long branches.
1848 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1849 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08001850 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1851 // Far label.
1852 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
1853 // Far literals.
1854 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
1855 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
1856 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001857};
1858
1859// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1860void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1861 CHECK(overwriting_);
1862 overwrite_location_ = branch->GetLocation();
1863 uint32_t offset = branch->GetOffset();
1864 BranchCondition condition = branch->GetCondition();
1865 GpuRegister lhs = branch->GetLeftRegister();
1866 GpuRegister rhs = branch->GetRightRegister();
1867 switch (branch->GetType()) {
1868 // Short branches.
1869 case Branch::kUncondBranch:
1870 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1871 Bc(offset);
1872 break;
1873 case Branch::kCondBranch:
1874 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1875 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001876 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001877 break;
1878 case Branch::kCall:
1879 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001880 Balc(offset);
1881 break;
1882
1883 // Near label.
1884 case Branch::kLabel:
1885 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001886 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001887 break;
1888 // Near literals.
1889 case Branch::kLiteral:
1890 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1891 Lwpc(lhs, offset);
1892 break;
1893 case Branch::kLiteralUnsigned:
1894 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1895 Lwupc(lhs, offset);
1896 break;
1897 case Branch::kLiteralLong:
1898 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1899 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001900 break;
1901
1902 // Long branches.
1903 case Branch::kLongUncondBranch:
1904 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1905 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1906 Auipc(AT, High16Bits(offset));
1907 Jic(AT, Low16Bits(offset));
1908 break;
1909 case Branch::kLongCondBranch:
1910 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1911 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1912 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1913 Auipc(AT, High16Bits(offset));
1914 Jic(AT, Low16Bits(offset));
1915 break;
1916 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001917 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001918 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001919 Auipc(AT, High16Bits(offset));
1920 Jialc(AT, Low16Bits(offset));
1921 break;
1922
1923 // Far label.
1924 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08001925 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001926 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1927 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08001928 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08001929 break;
1930 // Far literals.
1931 case Branch::kFarLiteral:
1932 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
1933 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1934 Auipc(AT, High16Bits(offset));
1935 Lw(lhs, AT, Low16Bits(offset));
1936 break;
1937 case Branch::kFarLiteralUnsigned:
1938 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
1939 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1940 Auipc(AT, High16Bits(offset));
1941 Lwu(lhs, AT, Low16Bits(offset));
1942 break;
1943 case Branch::kFarLiteralLong:
1944 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
1945 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1946 Auipc(AT, High16Bits(offset));
1947 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001948 break;
1949 }
1950 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1951 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001952}
1953
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001954void Mips64Assembler::Bc(Mips64Label* label) {
1955 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001956}
1957
Alexey Frunze19f6c692016-11-30 19:19:55 -08001958void Mips64Assembler::Balc(Mips64Label* label) {
1959 Call(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001960}
1961
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001962void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1963 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001964}
1965
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001966void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1967 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001968}
1969
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001970void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1971 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001972}
1973
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001974void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1975 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001976}
1977
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001978void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1979 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001980}
1981
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001982void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1983 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001984}
1985
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001986void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1987 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001988}
1989
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001990void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1991 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001992}
1993
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001994void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1995 Bcond(label, kCondEQ, rs, rt);
1996}
1997
1998void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1999 Bcond(label, kCondNE, rs, rt);
2000}
2001
2002void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
2003 Bcond(label, kCondEQZ, rs);
2004}
2005
2006void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
2007 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08002008}
2009
Alexey Frunze299a9392015-12-08 16:08:02 -08002010void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
2011 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
2012}
2013
2014void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
2015 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
2016}
2017
Andreas Gampe57b34292015-01-14 15:45:59 -08002018void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
2019 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002020 if (!IsInt<16>(offset) ||
2021 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2022 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2023 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002024 Daddu(AT, AT, base);
2025 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002026 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002027 }
2028
Andreas Gampe57b34292015-01-14 15:45:59 -08002029 switch (type) {
2030 case kLoadSignedByte:
2031 Lb(reg, base, offset);
2032 break;
2033 case kLoadUnsignedByte:
2034 Lbu(reg, base, offset);
2035 break;
2036 case kLoadSignedHalfword:
2037 Lh(reg, base, offset);
2038 break;
2039 case kLoadUnsignedHalfword:
2040 Lhu(reg, base, offset);
2041 break;
2042 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002043 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002044 Lw(reg, base, offset);
2045 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07002046 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002047 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07002048 Lwu(reg, base, offset);
2049 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08002050 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002051 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2052 CHECK_ALIGNED(offset, kMips64WordSize);
2053 Lwu(reg, base, offset);
2054 Lwu(TMP2, base, offset + kMips64WordSize);
2055 Dinsu(reg, TMP2, 32, 32);
2056 } else {
2057 Ld(reg, base, offset);
2058 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002059 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08002060 }
2061}
2062
2063void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
2064 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002065 if (!IsInt<16>(offset) ||
2066 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2067 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2068 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002069 Daddu(AT, AT, base);
2070 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002071 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002072 }
2073
Andreas Gampe57b34292015-01-14 15:45:59 -08002074 switch (type) {
2075 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002076 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002077 Lwc1(reg, base, offset);
2078 break;
2079 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002080 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2081 CHECK_ALIGNED(offset, kMips64WordSize);
2082 Lwc1(reg, base, offset);
2083 Lw(TMP2, base, offset + kMips64WordSize);
2084 Mthc1(TMP2, reg);
2085 } else {
2086 Ldc1(reg, base, offset);
2087 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002088 break;
2089 default:
2090 LOG(FATAL) << "UNREACHABLE";
2091 }
2092}
2093
2094void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
2095 size_t size) {
2096 Mips64ManagedRegister dst = m_dst.AsMips64();
2097 if (dst.IsNoRegister()) {
2098 CHECK_EQ(0u, size) << dst;
2099 } else if (dst.IsGpuRegister()) {
2100 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002101 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
2102 } else if (size == 8) {
2103 CHECK_EQ(8u, size) << dst;
2104 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
2105 } else {
2106 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2107 }
2108 } else if (dst.IsFpuRegister()) {
2109 if (size == 4) {
2110 CHECK_EQ(4u, size) << dst;
2111 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
2112 } else if (size == 8) {
2113 CHECK_EQ(8u, size) << dst;
2114 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
2115 } else {
2116 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2117 }
2118 }
2119}
2120
2121void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
2122 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002123 if (!IsInt<16>(offset) ||
2124 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2125 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2126 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002127 Daddu(AT, AT, base);
2128 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002129 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002130 }
2131
Andreas Gampe57b34292015-01-14 15:45:59 -08002132 switch (type) {
2133 case kStoreByte:
2134 Sb(reg, base, offset);
2135 break;
2136 case kStoreHalfword:
2137 Sh(reg, base, offset);
2138 break;
2139 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002140 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002141 Sw(reg, base, offset);
2142 break;
2143 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002144 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2145 CHECK_ALIGNED(offset, kMips64WordSize);
2146 Sw(reg, base, offset);
2147 Dsrl32(TMP2, reg, 0);
2148 Sw(TMP2, base, offset + kMips64WordSize);
2149 } else {
2150 Sd(reg, base, offset);
2151 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002152 break;
2153 default:
2154 LOG(FATAL) << "UNREACHABLE";
2155 }
2156}
2157
2158void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
2159 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002160 if (!IsInt<16>(offset) ||
2161 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2162 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2163 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002164 Daddu(AT, AT, base);
2165 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002166 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002167 }
2168
Andreas Gampe57b34292015-01-14 15:45:59 -08002169 switch (type) {
2170 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002171 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002172 Swc1(reg, base, offset);
2173 break;
2174 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002175 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2176 CHECK_ALIGNED(offset, kMips64WordSize);
2177 Mfhc1(TMP2, reg);
2178 Swc1(reg, base, offset);
2179 Sw(TMP2, base, offset + kMips64WordSize);
2180 } else {
2181 Sdc1(reg, base, offset);
2182 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002183 break;
2184 default:
2185 LOG(FATAL) << "UNREACHABLE";
2186 }
2187}
2188
David Srbeckydd973932015-04-07 20:29:48 +01002189static dwarf::Reg DWARFReg(GpuRegister reg) {
2190 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
2191}
2192
Andreas Gampe57b34292015-01-14 15:45:59 -08002193constexpr size_t kFramePointerSize = 8;
2194
Vladimir Marko32248382016-05-19 10:37:24 +01002195void Mips64Assembler::BuildFrame(size_t frame_size,
2196 ManagedRegister method_reg,
2197 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002198 const ManagedRegisterEntrySpills& entry_spills) {
2199 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002200 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002201
2202 // Increase frame to required size.
2203 IncreaseFrameSize(frame_size);
2204
2205 // Push callee saves and return address
2206 int stack_offset = frame_size - kFramePointerSize;
2207 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002208 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002209 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2210 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002211 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002212 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002213 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002214 }
2215
2216 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002217 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002218
2219 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002220 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002221 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002222 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002223 ManagedRegisterSpill spill = entry_spills.at(i);
2224 int32_t size = spill.getSize();
2225 if (reg.IsNoRegister()) {
2226 // only increment stack offset.
2227 offset += size;
2228 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002229 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2230 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002231 offset += size;
2232 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002233 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2234 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002235 offset += size;
2236 }
2237 }
2238}
2239
2240void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002241 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002242 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002243 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002244 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002245
2246 // Pop callee saves and return address
2247 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2248 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002249 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002250 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002251 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002252 stack_offset += kFramePointerSize;
2253 }
2254 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002255 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002256
2257 // Decrease frame to required size.
2258 DecreaseFrameSize(frame_size);
2259
2260 // Then jump to the return address.
2261 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002262 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002263
2264 // The CFI should be restored for any code that follows the exit block.
2265 cfi_.RestoreState();
2266 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002267}
2268
2269void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002270 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002271 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002272 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002273 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002274}
2275
2276void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002277 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002278 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002279 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002280 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002281}
2282
2283void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2284 Mips64ManagedRegister src = msrc.AsMips64();
2285 if (src.IsNoRegister()) {
2286 CHECK_EQ(0u, size);
2287 } else if (src.IsGpuRegister()) {
2288 CHECK(size == 4 || size == 8) << size;
2289 if (size == 8) {
2290 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2291 } else if (size == 4) {
2292 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2293 } else {
2294 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2295 }
2296 } else if (src.IsFpuRegister()) {
2297 CHECK(size == 4 || size == 8) << size;
2298 if (size == 8) {
2299 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2300 } else if (size == 4) {
2301 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2302 } else {
2303 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2304 }
2305 }
2306}
2307
2308void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2309 Mips64ManagedRegister src = msrc.AsMips64();
2310 CHECK(src.IsGpuRegister());
2311 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2312}
2313
2314void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2315 Mips64ManagedRegister src = msrc.AsMips64();
2316 CHECK(src.IsGpuRegister());
2317 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2318}
2319
2320void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2321 ManagedRegister mscratch) {
2322 Mips64ManagedRegister scratch = mscratch.AsMips64();
2323 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002324 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002325 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2326}
2327
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002328void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2329 FrameOffset fr_offs,
2330 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002331 Mips64ManagedRegister scratch = mscratch.AsMips64();
2332 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002333 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002334 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2335}
2336
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002337void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002338 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2339}
2340
2341void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2342 FrameOffset in_off, ManagedRegister mscratch) {
2343 Mips64ManagedRegister src = msrc.AsMips64();
2344 Mips64ManagedRegister scratch = mscratch.AsMips64();
2345 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2346 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2347 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2348}
2349
2350void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2351 return EmitLoad(mdest, SP, src.Int32Value(), size);
2352}
2353
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002354void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002355 return EmitLoad(mdest, S1, src.Int32Value(), size);
2356}
2357
2358void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2359 Mips64ManagedRegister dest = mdest.AsMips64();
2360 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002361 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002362}
2363
Mathieu Chartiere401d142015-04-22 13:56:20 -07002364void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002365 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002366 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002367 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2368 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002369 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002370 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002371 // TODO: review
2372 // Negate the 32-bit ref
2373 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2374 // 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 +02002375 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002376 }
2377}
2378
2379void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002380 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002381 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002382 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002383 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2384 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2385}
2386
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002387void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002388 Mips64ManagedRegister dest = mdest.AsMips64();
2389 CHECK(dest.IsGpuRegister());
2390 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2391}
2392
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002393void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2394 size_t size ATTRIBUTE_UNUSED) {
2395 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002396}
2397
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002398void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2399 size_t size ATTRIBUTE_UNUSED) {
2400 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002401}
2402
2403void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2404 Mips64ManagedRegister dest = mdest.AsMips64();
2405 Mips64ManagedRegister src = msrc.AsMips64();
2406 if (!dest.Equals(src)) {
2407 if (dest.IsGpuRegister()) {
2408 CHECK(src.IsGpuRegister()) << src;
2409 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2410 } else if (dest.IsFpuRegister()) {
2411 CHECK(src.IsFpuRegister()) << src;
2412 if (size == 4) {
2413 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2414 } else if (size == 8) {
2415 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2416 } else {
2417 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2418 }
2419 }
2420 }
2421}
2422
2423void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2424 ManagedRegister mscratch) {
2425 Mips64ManagedRegister scratch = mscratch.AsMips64();
2426 CHECK(scratch.IsGpuRegister()) << scratch;
2427 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2428 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2429}
2430
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002431void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2432 ThreadOffset64 thr_offs,
2433 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002434 Mips64ManagedRegister scratch = mscratch.AsMips64();
2435 CHECK(scratch.IsGpuRegister()) << scratch;
2436 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2437 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2438}
2439
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002440void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2441 FrameOffset fr_offs,
2442 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002443 Mips64ManagedRegister scratch = mscratch.AsMips64();
2444 CHECK(scratch.IsGpuRegister()) << scratch;
2445 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2446 SP, fr_offs.Int32Value());
2447 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2448 S1, thr_offs.Int32Value());
2449}
2450
2451void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2452 ManagedRegister mscratch, size_t size) {
2453 Mips64ManagedRegister scratch = mscratch.AsMips64();
2454 CHECK(scratch.IsGpuRegister()) << scratch;
2455 CHECK(size == 4 || size == 8) << size;
2456 if (size == 4) {
2457 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002458 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002459 } else if (size == 8) {
2460 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2461 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2462 } else {
2463 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2464 }
2465}
2466
2467void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002468 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002469 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2470 CHECK(size == 4 || size == 8) << size;
2471 if (size == 4) {
2472 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2473 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002474 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002475 } else if (size == 8) {
2476 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2477 src_offset.Int32Value());
2478 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2479 } else {
2480 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2481 }
2482}
2483
2484void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002485 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002486 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2487 CHECK(size == 4 || size == 8) << size;
2488 if (size == 4) {
2489 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002490 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002491 dest_offset.Int32Value());
2492 } else if (size == 8) {
2493 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2494 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2495 dest_offset.Int32Value());
2496 } else {
2497 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2498 }
2499}
2500
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002501void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2502 FrameOffset src_base ATTRIBUTE_UNUSED,
2503 Offset src_offset ATTRIBUTE_UNUSED,
2504 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2505 size_t size ATTRIBUTE_UNUSED) {
2506 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002507}
2508
2509void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002510 ManagedRegister src, Offset src_offset,
2511 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002512 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2513 CHECK(size == 4 || size == 8) << size;
2514 if (size == 4) {
2515 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002516 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002517 } else if (size == 8) {
2518 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2519 src_offset.Int32Value());
2520 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2521 dest_offset.Int32Value());
2522 } else {
2523 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2524 }
2525}
2526
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002527void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2528 Offset dest_offset ATTRIBUTE_UNUSED,
2529 FrameOffset src ATTRIBUTE_UNUSED,
2530 Offset src_offset ATTRIBUTE_UNUSED,
2531 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2532 size_t size ATTRIBUTE_UNUSED) {
2533 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002534}
2535
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002536void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002537 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002538 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002539}
2540
2541void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002542 FrameOffset handle_scope_offset,
2543 ManagedRegister min_reg,
2544 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002545 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2546 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2547 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2548 CHECK(out_reg.IsGpuRegister()) << out_reg;
2549 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002550 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002551 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2552 // the address in the handle scope holding the reference.
2553 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2554 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002555 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002556 SP, handle_scope_offset.Int32Value());
2557 in_reg = out_reg;
2558 }
2559 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002560 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002561 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002562 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2563 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2564 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002565 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002566 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002567 }
2568}
2569
2570void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002571 FrameOffset handle_scope_offset,
2572 ManagedRegister mscratch,
2573 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002574 Mips64ManagedRegister scratch = mscratch.AsMips64();
2575 CHECK(scratch.IsGpuRegister()) << scratch;
2576 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002577 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002578 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002579 handle_scope_offset.Int32Value());
2580 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2581 // the address in the handle scope holding the reference.
2582 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002583 Beqzc(scratch.AsGpuRegister(), &null_arg);
2584 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2585 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002586 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002587 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002588 }
2589 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2590}
2591
2592// Given a handle scope entry, load the associated reference.
2593void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002594 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002595 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2596 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2597 CHECK(out_reg.IsGpuRegister()) << out_reg;
2598 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002599 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002600 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002601 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002602 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002603 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002604 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2605 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002606 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002607}
2608
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002609void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2610 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002611 // TODO: not validating references
2612}
2613
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002614void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2615 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002616 // TODO: not validating references
2617}
2618
2619void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2620 Mips64ManagedRegister base = mbase.AsMips64();
2621 Mips64ManagedRegister scratch = mscratch.AsMips64();
2622 CHECK(base.IsGpuRegister()) << base;
2623 CHECK(scratch.IsGpuRegister()) << scratch;
2624 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2625 base.AsGpuRegister(), offset.Int32Value());
2626 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002627 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002628 // TODO: place reference map on call
2629}
2630
2631void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2632 Mips64ManagedRegister scratch = mscratch.AsMips64();
2633 CHECK(scratch.IsGpuRegister()) << scratch;
2634 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002635 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002636 SP, base.Int32Value());
2637 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2638 scratch.AsGpuRegister(), offset.Int32Value());
2639 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002640 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002641 // TODO: place reference map on call
2642}
2643
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002644void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2645 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002646 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002647}
2648
2649void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2650 Move(tr.AsMips64().AsGpuRegister(), S1);
2651}
2652
2653void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002654 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002655 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2656}
2657
2658void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2659 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002660 exception_blocks_.emplace_back(scratch, stack_adjust);
2661 LoadFromOffset(kLoadDoubleword,
2662 scratch.AsGpuRegister(),
2663 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002664 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002665 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002666}
2667
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002668void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2669 Bind(exception->Entry());
2670 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2671 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002672 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002673 // Pass exception object as argument.
2674 // Don't care about preserving A0 as this call won't return.
2675 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2676 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002677 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002678 LoadFromOffset(kLoadDoubleword,
2679 T9,
2680 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002681 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002682 Jr(T9);
2683 Nop();
2684
Andreas Gampe57b34292015-01-14 15:45:59 -08002685 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002686 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002687}
2688
2689} // namespace mips64
2690} // namespace art