blob: a2621cbb30296ac4b86af73598d23d2c8b3c7f42 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
38 PromoteBranches();
39}
40
41void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
42 EmitBranches();
43 Assembler::FinalizeInstructions(region);
44 PatchCFI();
45}
46
47void Mips64Assembler::PatchCFI() {
48 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
49 return;
50 }
51
52 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
53 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
54 const std::vector<uint8_t>& old_stream = data.first;
55 const std::vector<DelayedAdvancePC>& advances = data.second;
56
57 // Refill our data buffer with patched opcodes.
58 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
59 size_t stream_pos = 0;
60 for (const DelayedAdvancePC& advance : advances) {
61 DCHECK_GE(advance.stream_pos, stream_pos);
62 // Copy old data up to the point where advance was issued.
63 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
64 stream_pos = advance.stream_pos;
65 // Insert the advance command with its final offset.
66 size_t final_pc = GetAdjustedPosition(advance.pc);
67 cfi().AdvancePC(final_pc);
68 }
69 // Copy the final segment if any.
70 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
71}
72
73void Mips64Assembler::EmitBranches() {
74 CHECK(!overwriting_);
75 // Switch from appending instructions at the end of the buffer to overwriting
76 // existing instructions (branch placeholders) in the buffer.
77 overwriting_ = true;
78 for (auto& branch : branches_) {
79 EmitBranch(&branch);
80 }
81 overwriting_ = false;
82}
83
Alexey Frunze4dda3372015-06-01 18:31:49 -070084void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070085 if (overwriting_) {
86 // Branches to labels are emitted into their placeholders here.
87 buffer_.Store<uint32_t>(overwrite_location_, value);
88 overwrite_location_ += sizeof(uint32_t);
89 } else {
90 // Other instructions are simply appended at the end here.
91 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
92 buffer_.Emit<uint32_t>(value);
93 }
Andreas Gampe57b34292015-01-14 15:45:59 -080094}
95
96void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
97 int shamt, int funct) {
98 CHECK_NE(rs, kNoGpuRegister);
99 CHECK_NE(rt, kNoGpuRegister);
100 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700101 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
102 static_cast<uint32_t>(rs) << kRsShift |
103 static_cast<uint32_t>(rt) << kRtShift |
104 static_cast<uint32_t>(rd) << kRdShift |
105 shamt << kShamtShift |
106 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800107 Emit(encoding);
108}
109
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700110void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
111 int shamt, int funct) {
112 CHECK_NE(rs, kNoGpuRegister);
113 CHECK_NE(rd, kNoGpuRegister);
114 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
115 static_cast<uint32_t>(rs) << kRsShift |
116 static_cast<uint32_t>(ZERO) << kRtShift |
117 static_cast<uint32_t>(rd) << kRdShift |
118 shamt << kShamtShift |
119 funct;
120 Emit(encoding);
121}
122
123void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
124 int shamt, int funct) {
125 CHECK_NE(rt, kNoGpuRegister);
126 CHECK_NE(rd, kNoGpuRegister);
127 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
128 static_cast<uint32_t>(ZERO) << kRsShift |
129 static_cast<uint32_t>(rt) << kRtShift |
130 static_cast<uint32_t>(rd) << kRdShift |
131 shamt << kShamtShift |
132 funct;
133 Emit(encoding);
134}
135
Andreas Gampe57b34292015-01-14 15:45:59 -0800136void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
137 CHECK_NE(rs, kNoGpuRegister);
138 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700139 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
140 static_cast<uint32_t>(rs) << kRsShift |
141 static_cast<uint32_t>(rt) << kRtShift |
142 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800143 Emit(encoding);
144}
145
Alexey Frunze4dda3372015-06-01 18:31:49 -0700146void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
147 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700148 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700149 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
150 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700151 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700152 Emit(encoding);
153}
154
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700155void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
156 CHECK(IsUint<26>(imm26)) << imm26;
157 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800158 Emit(encoding);
159}
160
161void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700162 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800163 CHECK_NE(ft, kNoFpuRegister);
164 CHECK_NE(fs, kNoFpuRegister);
165 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700166 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
167 fmt << kFmtShift |
168 static_cast<uint32_t>(ft) << kFtShift |
169 static_cast<uint32_t>(fs) << kFsShift |
170 static_cast<uint32_t>(fd) << kFdShift |
171 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800172 Emit(encoding);
173}
174
Alexey Frunze4dda3372015-06-01 18:31:49 -0700175void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
176 CHECK_NE(ft, kNoFpuRegister);
177 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
178 fmt << kFmtShift |
179 static_cast<uint32_t>(ft) << kFtShift |
180 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800181 Emit(encoding);
182}
183
Andreas Gampe57b34292015-01-14 15:45:59 -0800184void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
185 EmitR(0, rs, rt, rd, 0, 0x21);
186}
187
188void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
189 EmitI(0x9, rs, rt, imm16);
190}
191
Alexey Frunze4dda3372015-06-01 18:31:49 -0700192void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
193 EmitR(0, rs, rt, rd, 0, 0x2d);
194}
195
Andreas Gampe57b34292015-01-14 15:45:59 -0800196void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
197 EmitI(0x19, rs, rt, imm16);
198}
199
Andreas Gampe57b34292015-01-14 15:45:59 -0800200void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
201 EmitR(0, rs, rt, rd, 0, 0x23);
202}
203
Alexey Frunze4dda3372015-06-01 18:31:49 -0700204void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
205 EmitR(0, rs, rt, rd, 0, 0x2f);
206}
207
Alexey Frunze4dda3372015-06-01 18:31:49 -0700208void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
209 EmitR(0, rs, rt, rd, 2, 0x18);
210}
211
Alexey Frunzec857c742015-09-23 15:12:39 -0700212void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
213 EmitR(0, rs, rt, rd, 3, 0x18);
214}
215
Alexey Frunze4dda3372015-06-01 18:31:49 -0700216void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
217 EmitR(0, rs, rt, rd, 2, 0x1a);
218}
219
220void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
221 EmitR(0, rs, rt, rd, 3, 0x1a);
222}
223
224void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
225 EmitR(0, rs, rt, rd, 2, 0x1b);
226}
227
228void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
229 EmitR(0, rs, rt, rd, 3, 0x1b);
230}
231
232void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
233 EmitR(0, rs, rt, rd, 2, 0x1c);
234}
235
Alexey Frunzec857c742015-09-23 15:12:39 -0700236void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
237 EmitR(0, rs, rt, rd, 3, 0x1c);
238}
239
Alexey Frunze4dda3372015-06-01 18:31:49 -0700240void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
241 EmitR(0, rs, rt, rd, 2, 0x1e);
242}
243
244void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
245 EmitR(0, rs, rt, rd, 3, 0x1e);
246}
247
248void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
249 EmitR(0, rs, rt, rd, 2, 0x1f);
250}
251
252void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
253 EmitR(0, rs, rt, rd, 3, 0x1f);
254}
255
Andreas Gampe57b34292015-01-14 15:45:59 -0800256void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
257 EmitR(0, rs, rt, rd, 0, 0x24);
258}
259
260void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
261 EmitI(0xc, rs, rt, imm16);
262}
263
264void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
265 EmitR(0, rs, rt, rd, 0, 0x25);
266}
267
268void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
269 EmitI(0xd, rs, rt, imm16);
270}
271
272void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
273 EmitR(0, rs, rt, rd, 0, 0x26);
274}
275
276void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
277 EmitI(0xe, rs, rt, imm16);
278}
279
280void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
281 EmitR(0, rs, rt, rd, 0, 0x27);
282}
283
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700284void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
285 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
286}
287
288void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
289 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
290}
291
Alexey Frunze4dda3372015-06-01 18:31:49 -0700292void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
293 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800294}
295
Alexey Frunze4dda3372015-06-01 18:31:49 -0700296void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
297 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800298}
299
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700300void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
301 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
302}
303
304void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
305 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
306}
307
Lazar Trsicd9672662015-09-03 17:33:01 +0200308void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
309 CHECK(IsUint<5>(pos)) << pos;
310 CHECK(IsUint<5>(size - 1)) << size;
311 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
312}
313
314void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
315 CHECK(IsUint<5>(pos - 32)) << pos;
316 CHECK(IsUint<5>(size - 1)) << size;
317 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
318 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800319}
320
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700321void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
322 EmitRtd(0x1f, rt, rd, 2, 0x20);
323}
324
325void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200326 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700327 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
328}
329
330void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200331 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700332 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
333}
334
335void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200336 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700337 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
338}
339
340void Mips64Assembler::Lld(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) | 0x37);
343}
344
Alexey Frunze4dda3372015-06-01 18:31:49 -0700345void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
346 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
347}
348
349void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
350 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
351}
352
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700353void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
354 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
355}
356
Alexey Frunze4dda3372015-06-01 18:31:49 -0700357void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
358 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
359}
360
361void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800362 EmitR(0, rs, rt, rd, 0, 0x04);
363}
364
Chris Larsen9aebff22015-09-22 17:54:15 -0700365void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
366 EmitR(0, rs, rt, rd, 1, 0x06);
367}
368
Alexey Frunze4dda3372015-06-01 18:31:49 -0700369void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800370 EmitR(0, rs, rt, rd, 0, 0x06);
371}
372
Alexey Frunze4dda3372015-06-01 18:31:49 -0700373void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800374 EmitR(0, rs, rt, rd, 0, 0x07);
375}
376
Alexey Frunze4dda3372015-06-01 18:31:49 -0700377void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
378 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
379}
380
381void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
382 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
383}
384
Chris Larsen9aebff22015-09-22 17:54:15 -0700385void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
386 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
387}
388
Alexey Frunze4dda3372015-06-01 18:31:49 -0700389void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
390 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
391}
392
393void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
394 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
395}
396
397void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
398 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
399}
400
Chris Larsen9aebff22015-09-22 17:54:15 -0700401void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
402 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
403}
404
Alexey Frunze4dda3372015-06-01 18:31:49 -0700405void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
406 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
407}
408
409void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
410 EmitR(0, rs, rt, rd, 0, 0x14);
411}
412
413void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
414 EmitR(0, rs, rt, rd, 0, 0x16);
415}
416
Chris Larsen9aebff22015-09-22 17:54:15 -0700417void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
418 EmitR(0, rs, rt, rd, 1, 0x16);
419}
420
Alexey Frunze4dda3372015-06-01 18:31:49 -0700421void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
422 EmitR(0, rs, rt, rd, 0, 0x17);
423}
424
Andreas Gampe57b34292015-01-14 15:45:59 -0800425void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
426 EmitI(0x20, rs, rt, imm16);
427}
428
429void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
430 EmitI(0x21, rs, rt, imm16);
431}
432
433void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
434 EmitI(0x23, rs, rt, imm16);
435}
436
437void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
438 EmitI(0x37, rs, rt, imm16);
439}
440
441void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
442 EmitI(0x24, rs, rt, imm16);
443}
444
445void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
446 EmitI(0x25, rs, rt, imm16);
447}
448
Douglas Leungd90957f2015-04-30 19:22:49 -0700449void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
450 EmitI(0x27, rs, rt, imm16);
451}
452
Andreas Gampe57b34292015-01-14 15:45:59 -0800453void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
454 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
455}
456
Alexey Frunze4dda3372015-06-01 18:31:49 -0700457void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
458 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
459}
460
461void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
462 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
463}
464
465void Mips64Assembler::Sync(uint32_t stype) {
466 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
467 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
468}
469
Andreas Gampe57b34292015-01-14 15:45:59 -0800470void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
471 EmitI(0x28, rs, rt, imm16);
472}
473
474void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
475 EmitI(0x29, rs, rt, imm16);
476}
477
478void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
479 EmitI(0x2b, rs, rt, imm16);
480}
481
482void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
483 EmitI(0x3f, rs, rt, imm16);
484}
485
486void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
487 EmitR(0, rs, rt, rd, 0, 0x2a);
488}
489
490void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
491 EmitR(0, rs, rt, rd, 0, 0x2b);
492}
493
494void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
495 EmitI(0xa, rs, rt, imm16);
496}
497
498void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
499 EmitI(0xb, rs, rt, imm16);
500}
501
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700502void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
503 EmitR(0, rs, rt, rd, 0, 0x35);
504}
505
506void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
507 EmitR(0, rs, rt, rd, 0, 0x37);
508}
509
510void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
511 EmitRsd(0, rs, rd, 0x01, 0x10);
512}
513
514void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
515 EmitRsd(0, rs, rd, 0x01, 0x11);
516}
517
518void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
519 EmitRsd(0, rs, rd, 0x01, 0x12);
520}
521
522void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
523 EmitRsd(0, rs, rd, 0x01, 0x13);
524}
525
Alexey Frunze4dda3372015-06-01 18:31:49 -0700526void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
527 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800528}
529
530void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700531 Jalr(RA, rs);
532}
533
534void Mips64Assembler::Jr(GpuRegister rs) {
535 Jalr(ZERO, rs);
536}
537
538void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
539 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
540}
541
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700542void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
543 CHECK(IsUint<19>(imm19)) << imm19;
544 EmitI21(0x3B, rs, imm19);
545}
546
547void Mips64Assembler::Bc(uint32_t imm26) {
548 EmitI26(0x32, imm26);
549}
550
Alexey Frunze4dda3372015-06-01 18:31:49 -0700551void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
552 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
553}
554
555void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
556 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
557}
558
559void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
560 CHECK_NE(rs, ZERO);
561 CHECK_NE(rt, ZERO);
562 CHECK_NE(rs, rt);
563 EmitI(0x17, rs, rt, imm16);
564}
565
566void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
567 CHECK_NE(rt, ZERO);
568 EmitI(0x17, rt, rt, imm16);
569}
570
571void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
572 CHECK_NE(rt, ZERO);
573 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
574}
575
576void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
577 CHECK_NE(rs, ZERO);
578 CHECK_NE(rt, ZERO);
579 CHECK_NE(rs, rt);
580 EmitI(0x16, rs, rt, imm16);
581}
582
583void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
584 CHECK_NE(rt, ZERO);
585 EmitI(0x16, rt, rt, imm16);
586}
587
588void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
589 CHECK_NE(rt, ZERO);
590 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
591}
592
593void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
594 CHECK_NE(rs, ZERO);
595 CHECK_NE(rt, ZERO);
596 CHECK_NE(rs, rt);
597 EmitI(0x7, rs, rt, imm16);
598}
599
600void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
601 CHECK_NE(rs, ZERO);
602 CHECK_NE(rt, ZERO);
603 CHECK_NE(rs, rt);
604 EmitI(0x6, rs, rt, imm16);
605}
606
607void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
608 CHECK_NE(rs, ZERO);
609 CHECK_NE(rt, ZERO);
610 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700611 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700612}
613
614void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
615 CHECK_NE(rs, ZERO);
616 CHECK_NE(rt, ZERO);
617 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700618 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700619}
620
621void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
622 CHECK_NE(rs, ZERO);
623 EmitI21(0x36, rs, imm21);
624}
625
626void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
627 CHECK_NE(rs, ZERO);
628 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800629}
630
Alexey Frunze299a9392015-12-08 16:08:02 -0800631void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
632 EmitFI(0x11, 0x9, ft, imm16);
633}
634
635void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
636 EmitFI(0x11, 0xD, ft, imm16);
637}
638
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700639void Mips64Assembler::EmitBcondc(BranchCondition cond,
640 GpuRegister rs,
641 GpuRegister rt,
642 uint32_t imm16_21) {
643 switch (cond) {
644 case kCondLT:
645 Bltc(rs, rt, imm16_21);
646 break;
647 case kCondGE:
648 Bgec(rs, rt, imm16_21);
649 break;
650 case kCondLE:
651 Bgec(rt, rs, imm16_21);
652 break;
653 case kCondGT:
654 Bltc(rt, rs, imm16_21);
655 break;
656 case kCondLTZ:
657 CHECK_EQ(rt, ZERO);
658 Bltzc(rs, imm16_21);
659 break;
660 case kCondGEZ:
661 CHECK_EQ(rt, ZERO);
662 Bgezc(rs, imm16_21);
663 break;
664 case kCondLEZ:
665 CHECK_EQ(rt, ZERO);
666 Blezc(rs, imm16_21);
667 break;
668 case kCondGTZ:
669 CHECK_EQ(rt, ZERO);
670 Bgtzc(rs, imm16_21);
671 break;
672 case kCondEQ:
673 Beqc(rs, rt, imm16_21);
674 break;
675 case kCondNE:
676 Bnec(rs, rt, imm16_21);
677 break;
678 case kCondEQZ:
679 CHECK_EQ(rt, ZERO);
680 Beqzc(rs, imm16_21);
681 break;
682 case kCondNEZ:
683 CHECK_EQ(rt, ZERO);
684 Bnezc(rs, imm16_21);
685 break;
686 case kCondLTU:
687 Bltuc(rs, rt, imm16_21);
688 break;
689 case kCondGEU:
690 Bgeuc(rs, rt, imm16_21);
691 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800692 case kCondF:
693 CHECK_EQ(rt, ZERO);
694 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
695 break;
696 case kCondT:
697 CHECK_EQ(rt, ZERO);
698 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
699 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700700 case kUncond:
701 LOG(FATAL) << "Unexpected branch condition " << cond;
702 UNREACHABLE();
703 }
704}
705
Andreas Gampe57b34292015-01-14 15:45:59 -0800706void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
707 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
708}
709
710void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
711 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
712}
713
714void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
715 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
716}
717
718void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
719 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
720}
721
722void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700723 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800724}
725
726void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700727 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800728}
729
730void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700731 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800732}
733
734void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700735 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800736}
737
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700738void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
739 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
740}
741
742void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
743 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
744}
745
746void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
747 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
748}
749
750void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
751 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
752}
753
Andreas Gampe57b34292015-01-14 15:45:59 -0800754void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
755 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
756}
757
758void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700759 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
760}
761
762void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
763 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
764}
765
766void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
767 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
768}
769
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700770void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
771 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
772}
773
774void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
775 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
776}
777
778void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
779 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
780}
781
782void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
783 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
784}
785
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800786void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
787 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
788}
789
790void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
791 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
792}
793
794void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
795 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
796}
797
798void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
799 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
800}
801
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700802void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
803 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
804}
805
806void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
807 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
808}
809
810void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
811 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
812}
813
814void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
815 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
816}
817
818void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
819 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
820}
821
822void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
823 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
824}
825
826void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
827 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
828}
829
830void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
831 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
832}
833
834void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
835 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
836}
837
838void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
839 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
840}
841
842void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
843 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
844}
845
846void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
847 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
848}
849
850void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
851 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
852}
853
854void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
855 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
856}
857
858void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
859 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
860}
861
862void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
863 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
864}
865
866void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
867 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
868}
869
870void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
871 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
872}
873
Alexey Frunze299a9392015-12-08 16:08:02 -0800874void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
875 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
876}
877
878void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
879 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
880}
881
882void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
883 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
884}
885
886void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
887 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
888}
889
890void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
891 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
892}
893
894void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
895 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
896}
897
898void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
899 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
900}
901
902void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
903 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
904}
905
906void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
907 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
908}
909
910void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
911 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
912}
913
914void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
915 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
916}
917
918void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
919 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
920}
921
922void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
923 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
924}
925
926void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
927 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
928}
929
930void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
931 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
932}
933
934void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
935 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
936}
937
938void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
939 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
940}
941
942void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
943 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
944}
945
946void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
947 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
948}
949
950void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
951 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
952}
953
Alexey Frunze4dda3372015-06-01 18:31:49 -0700954void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
955 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
956}
957
958void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
959 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
960}
961
962void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
963 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
964}
965
966void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
967 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800968}
969
Chris Larsen51417632015-10-02 13:24:25 -0700970void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
971 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
972}
973
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700974void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
975 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
976}
977
Andreas Gampe57b34292015-01-14 15:45:59 -0800978void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
979 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
980}
981
Lazar Trsicd9672662015-09-03 17:33:01 +0200982void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
983 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
984}
985
Alexey Frunze4dda3372015-06-01 18:31:49 -0700986void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
987 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
988}
989
Lazar Trsicd9672662015-09-03 17:33:01 +0200990void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
991 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
992}
993
Alexey Frunze4dda3372015-06-01 18:31:49 -0700994void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
995 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
996}
997
998void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
999 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001000}
1001
1002void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1003 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1004}
1005
1006void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1007 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1008}
1009
1010void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1011 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1012}
1013
1014void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1015 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1016}
1017
1018void Mips64Assembler::Break() {
1019 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1020 static_cast<GpuRegister>(0), 0, 0xD);
1021}
1022
1023void Mips64Assembler::Nop() {
1024 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1025 static_cast<GpuRegister>(0), 0, 0x0);
1026}
1027
Alexey Frunze4dda3372015-06-01 18:31:49 -07001028void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1029 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001030}
1031
Alexey Frunze4dda3372015-06-01 18:31:49 -07001032void Mips64Assembler::Clear(GpuRegister rd) {
1033 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001034}
1035
Alexey Frunze4dda3372015-06-01 18:31:49 -07001036void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1037 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001038}
1039
Alexey Frunze4dda3372015-06-01 18:31:49 -07001040void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
1041 if (IsUint<16>(value)) {
1042 // Use OR with (unsigned) immediate to encode 16b unsigned int.
1043 Ori(rd, ZERO, value);
1044 } else if (IsInt<16>(value)) {
1045 // Use ADD with (signed) immediate to encode 16b signed int.
1046 Addiu(rd, ZERO, value);
1047 } else {
1048 Lui(rd, value >> 16);
1049 if (value & 0xFFFF)
1050 Ori(rd, rd, value);
1051 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001052}
1053
Alexey Frunze4dda3372015-06-01 18:31:49 -07001054void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
1055 int bit31 = (value & UINT64_C(0x80000000)) != 0;
1056
1057 // Loads with 1 instruction.
1058 if (IsUint<16>(value)) {
1059 Ori(rd, ZERO, value);
1060 } else if (IsInt<16>(value)) {
1061 Daddiu(rd, ZERO, value);
1062 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
1063 Lui(rd, value >> 16);
1064 } else if (IsInt<32>(value)) {
1065 // Loads with 2 instructions.
1066 Lui(rd, value >> 16);
1067 Ori(rd, rd, value);
1068 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
1069 Ori(rd, ZERO, value);
1070 Dahi(rd, value >> 32);
1071 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
1072 Ori(rd, ZERO, value);
1073 Dati(rd, value >> 48);
1074 } else if ((value & 0xFFFF) == 0 &&
1075 (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
1076 Lui(rd, value >> 16);
1077 Dahi(rd, (value >> 32) + bit31);
1078 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
1079 Lui(rd, value >> 16);
1080 Dati(rd, (value >> 48) + bit31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001081 } else if (IsPowerOfTwo(value + UINT64_C(1))) {
1082 int shift_cnt = 64 - CTZ(value + UINT64_C(1));
1083 Daddiu(rd, ZERO, -1);
1084 if (shift_cnt < 32) {
1085 Dsrl(rd, rd, shift_cnt);
1086 } else {
1087 Dsrl32(rd, rd, shift_cnt & 31);
1088 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001089 } else {
1090 int shift_cnt = CTZ(value);
1091 int64_t tmp = value >> shift_cnt;
1092 if (IsUint<16>(tmp)) {
1093 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001094 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001095 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001096 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001097 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001098 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001099 } else if (IsInt<16>(tmp)) {
1100 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001101 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001102 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001103 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001104 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001105 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001106 } else if (IsInt<32>(tmp)) {
1107 // Loads with 3 instructions.
1108 Lui(rd, tmp >> 16);
1109 Ori(rd, rd, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001110 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001111 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001112 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001113 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001114 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001115 } else {
1116 shift_cnt = 16 + CTZ(value >> 16);
1117 tmp = value >> shift_cnt;
1118 if (IsUint<16>(tmp)) {
1119 Ori(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001120 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001121 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001122 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001123 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001124 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001125 Ori(rd, rd, value);
1126 } else if (IsInt<16>(tmp)) {
1127 Daddiu(rd, ZERO, tmp);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001128 if (shift_cnt < 32) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001129 Dsll(rd, rd, shift_cnt);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001130 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001131 Dsll32(rd, rd, shift_cnt & 31);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001132 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001133 Ori(rd, rd, value);
1134 } else {
1135 // Loads with 3-4 instructions.
1136 uint64_t tmp2 = value;
1137 bool used_lui = false;
1138 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
1139 Lui(rd, tmp2 >> 16);
1140 used_lui = true;
1141 }
1142 if ((tmp2 & 0xFFFF) != 0) {
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001143 if (used_lui) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001144 Ori(rd, rd, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001145 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001146 Ori(rd, ZERO, tmp2);
Alexey Frunze5c75ffa2015-09-24 14:41:59 -07001147 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001148 }
1149 if (bit31) {
1150 tmp2 += UINT64_C(0x100000000);
1151 }
1152 if (((tmp2 >> 32) & 0xFFFF) != 0) {
1153 Dahi(rd, tmp2 >> 32);
1154 }
1155 if (tmp2 & UINT64_C(0x800000000000)) {
1156 tmp2 += UINT64_C(0x1000000000000);
1157 }
1158 if ((tmp2 >> 48) != 0) {
1159 Dati(rd, tmp2 >> 48);
1160 }
1161 }
1162 }
1163 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001164}
1165
Alexey Frunze4dda3372015-06-01 18:31:49 -07001166void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1167 if (IsInt<16>(value)) {
1168 Daddiu(rt, rs, value);
1169 } else {
1170 LoadConst64(rtmp, value);
1171 Daddu(rt, rs, rtmp);
1172 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001173}
1174
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001175void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1176 Mips64Assembler::Branch::Type short_type,
1177 Mips64Assembler::Branch::Type long_type) {
1178 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1179}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001180
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001181void Mips64Assembler::Branch::InitializeType(bool is_call) {
1182 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1183 if (is_call) {
1184 InitShortOrLong(offset_size, kCall, kLongCall);
1185 } else if (condition_ == kUncond) {
1186 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1187 } else {
1188 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1189 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1190 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1191 } else {
1192 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1193 }
1194 }
1195 old_type_ = type_;
1196}
1197
1198bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1199 switch (condition) {
1200 case kCondLT:
1201 case kCondGT:
1202 case kCondNE:
1203 case kCondLTU:
1204 return lhs == rhs;
1205 default:
1206 return false;
1207 }
1208}
1209
1210bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1211 GpuRegister lhs,
1212 GpuRegister rhs) {
1213 switch (condition) {
1214 case kUncond:
1215 return true;
1216 case kCondGE:
1217 case kCondLE:
1218 case kCondEQ:
1219 case kCondGEU:
1220 return lhs == rhs;
1221 default:
1222 return false;
1223 }
1224}
1225
1226Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1227 : old_location_(location),
1228 location_(location),
1229 target_(target),
1230 lhs_reg_(ZERO),
1231 rhs_reg_(ZERO),
1232 condition_(kUncond) {
1233 InitializeType(false);
1234}
1235
1236Mips64Assembler::Branch::Branch(uint32_t location,
1237 uint32_t target,
1238 Mips64Assembler::BranchCondition condition,
1239 GpuRegister lhs_reg,
1240 GpuRegister rhs_reg)
1241 : old_location_(location),
1242 location_(location),
1243 target_(target),
1244 lhs_reg_(lhs_reg),
1245 rhs_reg_(rhs_reg),
1246 condition_(condition) {
1247 CHECK_NE(condition, kUncond);
1248 switch (condition) {
1249 case kCondEQ:
1250 case kCondNE:
1251 case kCondLT:
1252 case kCondGE:
1253 case kCondLE:
1254 case kCondGT:
1255 case kCondLTU:
1256 case kCondGEU:
1257 CHECK_NE(lhs_reg, ZERO);
1258 CHECK_NE(rhs_reg, ZERO);
1259 break;
1260 case kCondLTZ:
1261 case kCondGEZ:
1262 case kCondLEZ:
1263 case kCondGTZ:
1264 case kCondEQZ:
1265 case kCondNEZ:
1266 CHECK_NE(lhs_reg, ZERO);
1267 CHECK_EQ(rhs_reg, ZERO);
1268 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001269 case kCondF:
1270 case kCondT:
1271 CHECK_EQ(rhs_reg, ZERO);
1272 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001273 case kUncond:
1274 UNREACHABLE();
1275 }
1276 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1277 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1278 // Branch condition is always true, make the branch unconditional.
1279 condition_ = kUncond;
1280 }
1281 InitializeType(false);
1282}
1283
1284Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1285 : old_location_(location),
1286 location_(location),
1287 target_(target),
1288 lhs_reg_(indirect_reg),
1289 rhs_reg_(ZERO),
1290 condition_(kUncond) {
1291 CHECK_NE(indirect_reg, ZERO);
1292 CHECK_NE(indirect_reg, AT);
1293 InitializeType(true);
1294}
1295
1296Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1297 Mips64Assembler::BranchCondition cond) {
1298 switch (cond) {
1299 case kCondLT:
1300 return kCondGE;
1301 case kCondGE:
1302 return kCondLT;
1303 case kCondLE:
1304 return kCondGT;
1305 case kCondGT:
1306 return kCondLE;
1307 case kCondLTZ:
1308 return kCondGEZ;
1309 case kCondGEZ:
1310 return kCondLTZ;
1311 case kCondLEZ:
1312 return kCondGTZ;
1313 case kCondGTZ:
1314 return kCondLEZ;
1315 case kCondEQ:
1316 return kCondNE;
1317 case kCondNE:
1318 return kCondEQ;
1319 case kCondEQZ:
1320 return kCondNEZ;
1321 case kCondNEZ:
1322 return kCondEQZ;
1323 case kCondLTU:
1324 return kCondGEU;
1325 case kCondGEU:
1326 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001327 case kCondF:
1328 return kCondT;
1329 case kCondT:
1330 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001331 case kUncond:
1332 LOG(FATAL) << "Unexpected branch condition " << cond;
1333 }
1334 UNREACHABLE();
1335}
1336
1337Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1338 return type_;
1339}
1340
1341Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1342 return condition_;
1343}
1344
1345GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1346 return lhs_reg_;
1347}
1348
1349GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1350 return rhs_reg_;
1351}
1352
1353uint32_t Mips64Assembler::Branch::GetTarget() const {
1354 return target_;
1355}
1356
1357uint32_t Mips64Assembler::Branch::GetLocation() const {
1358 return location_;
1359}
1360
1361uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1362 return old_location_;
1363}
1364
1365uint32_t Mips64Assembler::Branch::GetLength() const {
1366 return branch_info_[type_].length;
1367}
1368
1369uint32_t Mips64Assembler::Branch::GetOldLength() const {
1370 return branch_info_[old_type_].length;
1371}
1372
1373uint32_t Mips64Assembler::Branch::GetSize() const {
1374 return GetLength() * sizeof(uint32_t);
1375}
1376
1377uint32_t Mips64Assembler::Branch::GetOldSize() const {
1378 return GetOldLength() * sizeof(uint32_t);
1379}
1380
1381uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1382 return GetLocation() + GetSize();
1383}
1384
1385uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1386 return GetOldLocation() + GetOldSize();
1387}
1388
1389bool Mips64Assembler::Branch::IsLong() const {
1390 switch (type_) {
1391 // Short branches.
1392 case kUncondBranch:
1393 case kCondBranch:
1394 case kCall:
1395 return false;
1396 // Long branches.
1397 case kLongUncondBranch:
1398 case kLongCondBranch:
1399 case kLongCall:
1400 return true;
1401 }
1402 UNREACHABLE();
1403}
1404
1405bool Mips64Assembler::Branch::IsResolved() const {
1406 return target_ != kUnresolved;
1407}
1408
1409Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1410 OffsetBits offset_size =
1411 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1412 ? kOffset23
1413 : branch_info_[type_].offset_size;
1414 return offset_size;
1415}
1416
1417Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1418 uint32_t target) {
1419 // For unresolved targets assume the shortest encoding
1420 // (later it will be made longer if needed).
1421 if (target == kUnresolved)
1422 return kOffset16;
1423 int64_t distance = static_cast<int64_t>(target) - location;
1424 // To simplify calculations in composite branches consisting of multiple instructions
1425 // bump up the distance by a value larger than the max byte size of a composite branch.
1426 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1427 if (IsInt<kOffset16>(distance))
1428 return kOffset16;
1429 else if (IsInt<kOffset18>(distance))
1430 return kOffset18;
1431 else if (IsInt<kOffset21>(distance))
1432 return kOffset21;
1433 else if (IsInt<kOffset23>(distance))
1434 return kOffset23;
1435 else if (IsInt<kOffset28>(distance))
1436 return kOffset28;
1437 return kOffset32;
1438}
1439
1440void Mips64Assembler::Branch::Resolve(uint32_t target) {
1441 target_ = target;
1442}
1443
1444void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1445 if (location_ > expand_location) {
1446 location_ += delta;
1447 }
1448 if (!IsResolved()) {
1449 return; // Don't know the target yet.
1450 }
1451 if (target_ > expand_location) {
1452 target_ += delta;
1453 }
1454}
1455
1456void Mips64Assembler::Branch::PromoteToLong() {
1457 switch (type_) {
1458 // Short branches.
1459 case kUncondBranch:
1460 type_ = kLongUncondBranch;
1461 break;
1462 case kCondBranch:
1463 type_ = kLongCondBranch;
1464 break;
1465 case kCall:
1466 type_ = kLongCall;
1467 break;
1468 default:
1469 // Note: 'type_' is already long.
1470 break;
1471 }
1472 CHECK(IsLong());
1473}
1474
1475uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1476 // If the branch is still unresolved or already long, nothing to do.
1477 if (IsLong() || !IsResolved()) {
1478 return 0;
1479 }
1480 // Promote the short branch to long if the offset size is too small
1481 // to hold the distance between location_ and target_.
1482 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1483 PromoteToLong();
1484 uint32_t old_size = GetOldSize();
1485 uint32_t new_size = GetSize();
1486 CHECK_GT(new_size, old_size);
1487 return new_size - old_size;
1488 }
1489 // The following logic is for debugging/testing purposes.
1490 // Promote some short branches to long when it's not really required.
1491 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1492 int64_t distance = static_cast<int64_t>(target_) - location_;
1493 distance = (distance >= 0) ? distance : -distance;
1494 if (distance >= max_short_distance) {
1495 PromoteToLong();
1496 uint32_t old_size = GetOldSize();
1497 uint32_t new_size = GetSize();
1498 CHECK_GT(new_size, old_size);
1499 return new_size - old_size;
1500 }
1501 }
1502 return 0;
1503}
1504
1505uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1506 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1507}
1508
1509uint32_t Mips64Assembler::Branch::GetOffset() const {
1510 CHECK(IsResolved());
1511 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1512 // Calculate the byte distance between instructions and also account for
1513 // different PC-relative origins.
1514 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1515 // Prepare the offset for encoding into the instruction(s).
1516 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1517 return offset;
1518}
1519
1520Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1521 CHECK_LT(branch_id, branches_.size());
1522 return &branches_[branch_id];
1523}
1524
1525const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1526 CHECK_LT(branch_id, branches_.size());
1527 return &branches_[branch_id];
1528}
1529
1530void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001531 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001532 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001533
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001534 // Walk the list of branches referring to and preceding this label.
1535 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001536 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001537 uint32_t branch_id = label->Position();
1538 Branch* branch = GetBranch(branch_id);
1539 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001540
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001541 uint32_t branch_location = branch->GetLocation();
1542 // Extract the location of the previous branch in the list (walking the list backwards;
1543 // the previous branch ID was stored in the space reserved for this branch).
1544 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001545
1546 // On to the previous branch in the list...
1547 label->position_ = prev;
1548 }
1549
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001550 // Now make the label object contain its own location (relative to the end of the preceding
1551 // branch, if any; it will be used by the branches referring to and following this label).
1552 label->prev_branch_id_plus_one_ = branches_.size();
1553 if (label->prev_branch_id_plus_one_) {
1554 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1555 const Branch* branch = GetBranch(branch_id);
1556 bound_pc -= branch->GetEndLocation();
1557 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001558 label->BindTo(bound_pc);
1559}
1560
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001561uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1562 CHECK(label->IsBound());
1563 uint32_t target = label->Position();
1564 if (label->prev_branch_id_plus_one_) {
1565 // Get label location based on the branch preceding it.
1566 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1567 const Branch* branch = GetBranch(branch_id);
1568 target += branch->GetEndLocation();
1569 }
1570 return target;
1571}
1572
1573uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1574 // We can reconstruct the adjustment by going through all the branches from the beginning
1575 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1576 // with increasing old_position, we can use the data from last AdjustedPosition() to
1577 // continue where we left off and the whole loop should be O(m+n) where m is the number
1578 // of positions to adjust and n is the number of branches.
1579 if (old_position < last_old_position_) {
1580 last_position_adjustment_ = 0;
1581 last_old_position_ = 0;
1582 last_branch_id_ = 0;
1583 }
1584 while (last_branch_id_ != branches_.size()) {
1585 const Branch* branch = GetBranch(last_branch_id_);
1586 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1587 break;
1588 }
1589 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1590 ++last_branch_id_;
1591 }
1592 last_old_position_ = old_position;
1593 return old_position + last_position_adjustment_;
1594}
1595
1596void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1597 uint32_t length = branches_.back().GetLength();
1598 if (!label->IsBound()) {
1599 // Branch forward (to a following label), distance is unknown.
1600 // The first branch forward will contain 0, serving as the terminator of
1601 // the list of forward-reaching branches.
1602 Emit(label->position_);
1603 length--;
1604 // Now make the label object point to this branch
1605 // (this forms a linked list of branches preceding this label).
1606 uint32_t branch_id = branches_.size() - 1;
1607 label->LinkTo(branch_id);
1608 }
1609 // Reserve space for the branch.
1610 while (length--) {
1611 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001612 }
1613}
1614
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001615void Mips64Assembler::Buncond(Mips64Label* label) {
1616 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1617 branches_.emplace_back(buffer_.Size(), target);
1618 FinalizeLabeledBranch(label);
1619}
1620
1621void Mips64Assembler::Bcond(Mips64Label* label,
1622 BranchCondition condition,
1623 GpuRegister lhs,
1624 GpuRegister rhs) {
1625 // If lhs = rhs, this can be a NOP.
1626 if (Branch::IsNop(condition, lhs, rhs)) {
1627 return;
1628 }
1629 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1630 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1631 FinalizeLabeledBranch(label);
1632}
1633
1634void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1635 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1636 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1637 FinalizeLabeledBranch(label);
1638}
1639
1640void Mips64Assembler::PromoteBranches() {
1641 // Promote short branches to long as necessary.
1642 bool changed;
1643 do {
1644 changed = false;
1645 for (auto& branch : branches_) {
1646 CHECK(branch.IsResolved());
1647 uint32_t delta = branch.PromoteIfNeeded();
1648 // If this branch has been promoted and needs to expand in size,
1649 // relocate all branches by the expansion size.
1650 if (delta) {
1651 changed = true;
1652 uint32_t expand_location = branch.GetLocation();
1653 for (auto& branch2 : branches_) {
1654 branch2.Relocate(expand_location, delta);
1655 }
1656 }
1657 }
1658 } while (changed);
1659
1660 // Account for branch expansion by resizing the code buffer
1661 // and moving the code in it to its final location.
1662 size_t branch_count = branches_.size();
1663 if (branch_count > 0) {
1664 // Resize.
1665 Branch& last_branch = branches_[branch_count - 1];
1666 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1667 uint32_t old_size = buffer_.Size();
1668 buffer_.Resize(old_size + size_delta);
1669 // Move the code residing between branch placeholders.
1670 uint32_t end = old_size;
1671 for (size_t i = branch_count; i > 0; ) {
1672 Branch& branch = branches_[--i];
1673 uint32_t size = end - branch.GetOldEndLocation();
1674 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1675 end = branch.GetOldLocation();
1676 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001677 }
1678}
1679
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001680// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1681const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1682 // Short branches.
1683 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1684 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1685 // Exception: kOffset23 for beqzc/bnezc
1686 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1687 // Long branches.
1688 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1689 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1690 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1691};
1692
1693// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1694void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1695 CHECK(overwriting_);
1696 overwrite_location_ = branch->GetLocation();
1697 uint32_t offset = branch->GetOffset();
1698 BranchCondition condition = branch->GetCondition();
1699 GpuRegister lhs = branch->GetLeftRegister();
1700 GpuRegister rhs = branch->GetRightRegister();
1701 switch (branch->GetType()) {
1702 // Short branches.
1703 case Branch::kUncondBranch:
1704 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1705 Bc(offset);
1706 break;
1707 case Branch::kCondBranch:
1708 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1709 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001710 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001711 break;
1712 case Branch::kCall:
1713 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1714 Addiupc(lhs, offset);
1715 Jialc(lhs, 0);
1716 break;
1717
1718 // Long branches.
1719 case Branch::kLongUncondBranch:
1720 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1721 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1722 Auipc(AT, High16Bits(offset));
1723 Jic(AT, Low16Bits(offset));
1724 break;
1725 case Branch::kLongCondBranch:
1726 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1727 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1728 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1729 Auipc(AT, High16Bits(offset));
1730 Jic(AT, Low16Bits(offset));
1731 break;
1732 case Branch::kLongCall:
1733 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1734 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1735 Auipc(lhs, High16Bits(offset));
1736 Daddiu(lhs, lhs, Low16Bits(offset));
1737 Jialc(lhs, 0);
1738 break;
1739 }
1740 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1741 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001742}
1743
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001744void Mips64Assembler::Bc(Mips64Label* label) {
1745 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001746}
1747
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001748void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1749 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001750}
1751
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001752void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1753 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001754}
1755
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001756void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1757 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001758}
1759
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001760void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1761 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001762}
1763
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001764void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1765 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001766}
1767
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001768void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1769 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001770}
1771
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001772void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1773 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001774}
1775
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001776void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1777 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001778}
1779
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001780void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1781 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001782}
1783
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001784void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1785 Bcond(label, kCondEQ, rs, rt);
1786}
1787
1788void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1789 Bcond(label, kCondNE, rs, rt);
1790}
1791
1792void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1793 Bcond(label, kCondEQZ, rs);
1794}
1795
1796void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1797 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001798}
1799
Alexey Frunze299a9392015-12-08 16:08:02 -08001800void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1801 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1802}
1803
1804void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1805 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1806}
1807
Andreas Gampe57b34292015-01-14 15:45:59 -08001808void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1809 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001810 if (!IsInt<16>(offset) ||
1811 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1812 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1813 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001814 Daddu(AT, AT, base);
1815 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001816 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001817 }
1818
Andreas Gampe57b34292015-01-14 15:45:59 -08001819 switch (type) {
1820 case kLoadSignedByte:
1821 Lb(reg, base, offset);
1822 break;
1823 case kLoadUnsignedByte:
1824 Lbu(reg, base, offset);
1825 break;
1826 case kLoadSignedHalfword:
1827 Lh(reg, base, offset);
1828 break;
1829 case kLoadUnsignedHalfword:
1830 Lhu(reg, base, offset);
1831 break;
1832 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001833 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001834 Lw(reg, base, offset);
1835 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001836 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001837 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07001838 Lwu(reg, base, offset);
1839 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001840 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001841 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1842 CHECK_ALIGNED(offset, kMips64WordSize);
1843 Lwu(reg, base, offset);
1844 Lwu(TMP2, base, offset + kMips64WordSize);
1845 Dinsu(reg, TMP2, 32, 32);
1846 } else {
1847 Ld(reg, base, offset);
1848 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001849 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001850 }
1851}
1852
1853void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1854 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001855 if (!IsInt<16>(offset) ||
1856 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1857 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1858 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001859 Daddu(AT, AT, base);
1860 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001861 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001862 }
1863
Andreas Gampe57b34292015-01-14 15:45:59 -08001864 switch (type) {
1865 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001866 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001867 Lwc1(reg, base, offset);
1868 break;
1869 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001870 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1871 CHECK_ALIGNED(offset, kMips64WordSize);
1872 Lwc1(reg, base, offset);
1873 Lw(TMP2, base, offset + kMips64WordSize);
1874 Mthc1(TMP2, reg);
1875 } else {
1876 Ldc1(reg, base, offset);
1877 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001878 break;
1879 default:
1880 LOG(FATAL) << "UNREACHABLE";
1881 }
1882}
1883
1884void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1885 size_t size) {
1886 Mips64ManagedRegister dst = m_dst.AsMips64();
1887 if (dst.IsNoRegister()) {
1888 CHECK_EQ(0u, size) << dst;
1889 } else if (dst.IsGpuRegister()) {
1890 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001891 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1892 } else if (size == 8) {
1893 CHECK_EQ(8u, size) << dst;
1894 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1895 } else {
1896 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1897 }
1898 } else if (dst.IsFpuRegister()) {
1899 if (size == 4) {
1900 CHECK_EQ(4u, size) << dst;
1901 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1902 } else if (size == 8) {
1903 CHECK_EQ(8u, size) << dst;
1904 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1905 } else {
1906 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1907 }
1908 }
1909}
1910
1911void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1912 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001913 if (!IsInt<16>(offset) ||
1914 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1915 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1916 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001917 Daddu(AT, AT, base);
1918 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001919 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001920 }
1921
Andreas Gampe57b34292015-01-14 15:45:59 -08001922 switch (type) {
1923 case kStoreByte:
1924 Sb(reg, base, offset);
1925 break;
1926 case kStoreHalfword:
1927 Sh(reg, base, offset);
1928 break;
1929 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001930 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001931 Sw(reg, base, offset);
1932 break;
1933 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001934 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1935 CHECK_ALIGNED(offset, kMips64WordSize);
1936 Sw(reg, base, offset);
1937 Dsrl32(TMP2, reg, 0);
1938 Sw(TMP2, base, offset + kMips64WordSize);
1939 } else {
1940 Sd(reg, base, offset);
1941 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001942 break;
1943 default:
1944 LOG(FATAL) << "UNREACHABLE";
1945 }
1946}
1947
1948void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1949 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001950 if (!IsInt<16>(offset) ||
1951 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1952 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1953 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001954 Daddu(AT, AT, base);
1955 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001956 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001957 }
1958
Andreas Gampe57b34292015-01-14 15:45:59 -08001959 switch (type) {
1960 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001961 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001962 Swc1(reg, base, offset);
1963 break;
1964 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001965 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1966 CHECK_ALIGNED(offset, kMips64WordSize);
1967 Mfhc1(TMP2, reg);
1968 Swc1(reg, base, offset);
1969 Sw(TMP2, base, offset + kMips64WordSize);
1970 } else {
1971 Sdc1(reg, base, offset);
1972 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001973 break;
1974 default:
1975 LOG(FATAL) << "UNREACHABLE";
1976 }
1977}
1978
David Srbeckydd973932015-04-07 20:29:48 +01001979static dwarf::Reg DWARFReg(GpuRegister reg) {
1980 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1981}
1982
Andreas Gampe57b34292015-01-14 15:45:59 -08001983constexpr size_t kFramePointerSize = 8;
1984
Vladimir Marko32248382016-05-19 10:37:24 +01001985void Mips64Assembler::BuildFrame(size_t frame_size,
1986 ManagedRegister method_reg,
1987 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08001988 const ManagedRegisterEntrySpills& entry_spills) {
1989 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001990 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001991
1992 // Increase frame to required size.
1993 IncreaseFrameSize(frame_size);
1994
1995 // Push callee saves and return address
1996 int stack_offset = frame_size - kFramePointerSize;
1997 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001998 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001999 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2000 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002001 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002002 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002003 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002004 }
2005
2006 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002007 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002008
2009 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002010 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002011 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002012 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002013 ManagedRegisterSpill spill = entry_spills.at(i);
2014 int32_t size = spill.getSize();
2015 if (reg.IsNoRegister()) {
2016 // only increment stack offset.
2017 offset += size;
2018 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002019 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2020 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002021 offset += size;
2022 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002023 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2024 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002025 offset += size;
2026 }
2027 }
2028}
2029
2030void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002031 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002032 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002033 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002034 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002035
2036 // Pop callee saves and return address
2037 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2038 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002039 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002040 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002041 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002042 stack_offset += kFramePointerSize;
2043 }
2044 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002045 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002046
2047 // Decrease frame to required size.
2048 DecreaseFrameSize(frame_size);
2049
2050 // Then jump to the return address.
2051 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002052 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002053
2054 // The CFI should be restored for any code that follows the exit block.
2055 cfi_.RestoreState();
2056 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002057}
2058
2059void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002060 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002061 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002062 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002063 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002064}
2065
2066void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002067 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002068 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002069 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002070 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002071}
2072
2073void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2074 Mips64ManagedRegister src = msrc.AsMips64();
2075 if (src.IsNoRegister()) {
2076 CHECK_EQ(0u, size);
2077 } else if (src.IsGpuRegister()) {
2078 CHECK(size == 4 || size == 8) << size;
2079 if (size == 8) {
2080 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2081 } else if (size == 4) {
2082 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2083 } else {
2084 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2085 }
2086 } else if (src.IsFpuRegister()) {
2087 CHECK(size == 4 || size == 8) << size;
2088 if (size == 8) {
2089 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2090 } else if (size == 4) {
2091 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2092 } else {
2093 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2094 }
2095 }
2096}
2097
2098void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2099 Mips64ManagedRegister src = msrc.AsMips64();
2100 CHECK(src.IsGpuRegister());
2101 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2102}
2103
2104void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2105 Mips64ManagedRegister src = msrc.AsMips64();
2106 CHECK(src.IsGpuRegister());
2107 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2108}
2109
2110void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2111 ManagedRegister mscratch) {
2112 Mips64ManagedRegister scratch = mscratch.AsMips64();
2113 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002114 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002115 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2116}
2117
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002118void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2119 FrameOffset fr_offs,
2120 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002121 Mips64ManagedRegister scratch = mscratch.AsMips64();
2122 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002123 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002124 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2125}
2126
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002127void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002128 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2129}
2130
2131void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2132 FrameOffset in_off, ManagedRegister mscratch) {
2133 Mips64ManagedRegister src = msrc.AsMips64();
2134 Mips64ManagedRegister scratch = mscratch.AsMips64();
2135 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2136 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2137 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2138}
2139
2140void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2141 return EmitLoad(mdest, SP, src.Int32Value(), size);
2142}
2143
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002144void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002145 return EmitLoad(mdest, S1, src.Int32Value(), size);
2146}
2147
2148void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2149 Mips64ManagedRegister dest = mdest.AsMips64();
2150 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002151 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002152}
2153
Mathieu Chartiere401d142015-04-22 13:56:20 -07002154void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002155 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002156 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002157 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2158 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002159 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002160 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002161 // TODO: review
2162 // Negate the 32-bit ref
2163 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2164 // 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 +02002165 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002166 }
2167}
2168
2169void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002170 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002171 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002172 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002173 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2174 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2175}
2176
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002177void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002178 Mips64ManagedRegister dest = mdest.AsMips64();
2179 CHECK(dest.IsGpuRegister());
2180 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2181}
2182
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002183void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2184 size_t size ATTRIBUTE_UNUSED) {
2185 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002186}
2187
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002188void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2189 size_t size ATTRIBUTE_UNUSED) {
2190 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002191}
2192
2193void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2194 Mips64ManagedRegister dest = mdest.AsMips64();
2195 Mips64ManagedRegister src = msrc.AsMips64();
2196 if (!dest.Equals(src)) {
2197 if (dest.IsGpuRegister()) {
2198 CHECK(src.IsGpuRegister()) << src;
2199 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2200 } else if (dest.IsFpuRegister()) {
2201 CHECK(src.IsFpuRegister()) << src;
2202 if (size == 4) {
2203 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2204 } else if (size == 8) {
2205 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2206 } else {
2207 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2208 }
2209 }
2210 }
2211}
2212
2213void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2214 ManagedRegister mscratch) {
2215 Mips64ManagedRegister scratch = mscratch.AsMips64();
2216 CHECK(scratch.IsGpuRegister()) << scratch;
2217 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2218 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2219}
2220
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002221void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2222 ThreadOffset64 thr_offs,
2223 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002224 Mips64ManagedRegister scratch = mscratch.AsMips64();
2225 CHECK(scratch.IsGpuRegister()) << scratch;
2226 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2227 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2228}
2229
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002230void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2231 FrameOffset fr_offs,
2232 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002233 Mips64ManagedRegister scratch = mscratch.AsMips64();
2234 CHECK(scratch.IsGpuRegister()) << scratch;
2235 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2236 SP, fr_offs.Int32Value());
2237 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2238 S1, thr_offs.Int32Value());
2239}
2240
2241void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2242 ManagedRegister mscratch, size_t size) {
2243 Mips64ManagedRegister scratch = mscratch.AsMips64();
2244 CHECK(scratch.IsGpuRegister()) << scratch;
2245 CHECK(size == 4 || size == 8) << size;
2246 if (size == 4) {
2247 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002248 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002249 } else if (size == 8) {
2250 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2251 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2252 } else {
2253 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2254 }
2255}
2256
2257void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002258 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002259 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2260 CHECK(size == 4 || size == 8) << size;
2261 if (size == 4) {
2262 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2263 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002264 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002265 } else if (size == 8) {
2266 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2267 src_offset.Int32Value());
2268 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2269 } else {
2270 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2271 }
2272}
2273
2274void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002275 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2277 CHECK(size == 4 || size == 8) << size;
2278 if (size == 4) {
2279 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002280 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002281 dest_offset.Int32Value());
2282 } else if (size == 8) {
2283 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2284 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2285 dest_offset.Int32Value());
2286 } else {
2287 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2288 }
2289}
2290
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002291void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2292 FrameOffset src_base ATTRIBUTE_UNUSED,
2293 Offset src_offset ATTRIBUTE_UNUSED,
2294 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2295 size_t size ATTRIBUTE_UNUSED) {
2296 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002297}
2298
2299void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002300 ManagedRegister src, Offset src_offset,
2301 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002302 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2303 CHECK(size == 4 || size == 8) << size;
2304 if (size == 4) {
2305 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002306 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002307 } else if (size == 8) {
2308 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2309 src_offset.Int32Value());
2310 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2311 dest_offset.Int32Value());
2312 } else {
2313 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2314 }
2315}
2316
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002317void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2318 Offset dest_offset ATTRIBUTE_UNUSED,
2319 FrameOffset src ATTRIBUTE_UNUSED,
2320 Offset src_offset ATTRIBUTE_UNUSED,
2321 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2322 size_t size ATTRIBUTE_UNUSED) {
2323 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002324}
2325
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002326void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002327 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002328 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002329}
2330
2331void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002332 FrameOffset handle_scope_offset,
2333 ManagedRegister min_reg,
2334 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002335 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2336 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2337 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2338 CHECK(out_reg.IsGpuRegister()) << out_reg;
2339 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002340 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002341 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2342 // the address in the handle scope holding the reference.
2343 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2344 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002345 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002346 SP, handle_scope_offset.Int32Value());
2347 in_reg = out_reg;
2348 }
2349 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002350 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002351 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002352 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2353 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2354 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002355 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002356 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002357 }
2358}
2359
2360void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002361 FrameOffset handle_scope_offset,
2362 ManagedRegister mscratch,
2363 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002364 Mips64ManagedRegister scratch = mscratch.AsMips64();
2365 CHECK(scratch.IsGpuRegister()) << scratch;
2366 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002367 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002368 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002369 handle_scope_offset.Int32Value());
2370 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2371 // the address in the handle scope holding the reference.
2372 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002373 Beqzc(scratch.AsGpuRegister(), &null_arg);
2374 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2375 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002376 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002377 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002378 }
2379 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2380}
2381
2382// Given a handle scope entry, load the associated reference.
2383void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002384 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002385 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2386 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2387 CHECK(out_reg.IsGpuRegister()) << out_reg;
2388 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002389 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002390 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002391 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002392 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002393 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002394 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2395 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002396 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002397}
2398
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002399void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2400 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002401 // TODO: not validating references
2402}
2403
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002404void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2405 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002406 // TODO: not validating references
2407}
2408
2409void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2410 Mips64ManagedRegister base = mbase.AsMips64();
2411 Mips64ManagedRegister scratch = mscratch.AsMips64();
2412 CHECK(base.IsGpuRegister()) << base;
2413 CHECK(scratch.IsGpuRegister()) << scratch;
2414 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2415 base.AsGpuRegister(), offset.Int32Value());
2416 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002417 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002418 // TODO: place reference map on call
2419}
2420
2421void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2422 Mips64ManagedRegister scratch = mscratch.AsMips64();
2423 CHECK(scratch.IsGpuRegister()) << scratch;
2424 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002425 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002426 SP, base.Int32Value());
2427 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2428 scratch.AsGpuRegister(), offset.Int32Value());
2429 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002430 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002431 // TODO: place reference map on call
2432}
2433
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002434void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2435 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002436 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002437}
2438
2439void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2440 Move(tr.AsMips64().AsGpuRegister(), S1);
2441}
2442
2443void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002444 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002445 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2446}
2447
2448void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2449 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002450 exception_blocks_.emplace_back(scratch, stack_adjust);
2451 LoadFromOffset(kLoadDoubleword,
2452 scratch.AsGpuRegister(),
2453 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002454 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002455 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002456}
2457
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002458void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2459 Bind(exception->Entry());
2460 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2461 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002462 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002463 // Pass exception object as argument.
2464 // Don't care about preserving A0 as this call won't return.
2465 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2466 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002467 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002468 LoadFromOffset(kLoadDoubleword,
2469 T9,
2470 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002471 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002472 Jr(T9);
2473 Nop();
2474
Andreas Gampe57b34292015-01-14 15:45:59 -08002475 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002476 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002477}
2478
2479} // namespace mips64
2480} // namespace art