blob: 1a21df939e804896d0e52f525fbef7cff295ec33 [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) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001041 TemplateLoadConst32(this, rd, value);
1042}
1043
1044// This function is only used for testing purposes.
1045void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001046}
1047
Alexey Frunze4dda3372015-06-01 18:31:49 -07001048void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001049 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001050}
1051
Alexey Frunze4dda3372015-06-01 18:31:49 -07001052void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1053 if (IsInt<16>(value)) {
1054 Daddiu(rt, rs, value);
1055 } else {
1056 LoadConst64(rtmp, value);
1057 Daddu(rt, rs, rtmp);
1058 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001059}
1060
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001061void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1062 Mips64Assembler::Branch::Type short_type,
1063 Mips64Assembler::Branch::Type long_type) {
1064 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1065}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001066
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001067void Mips64Assembler::Branch::InitializeType(bool is_call) {
1068 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1069 if (is_call) {
1070 InitShortOrLong(offset_size, kCall, kLongCall);
1071 } else if (condition_ == kUncond) {
1072 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1073 } else {
1074 if (condition_ == kCondEQZ || condition_ == kCondNEZ) {
1075 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1076 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1077 } else {
1078 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1079 }
1080 }
1081 old_type_ = type_;
1082}
1083
1084bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1085 switch (condition) {
1086 case kCondLT:
1087 case kCondGT:
1088 case kCondNE:
1089 case kCondLTU:
1090 return lhs == rhs;
1091 default:
1092 return false;
1093 }
1094}
1095
1096bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1097 GpuRegister lhs,
1098 GpuRegister rhs) {
1099 switch (condition) {
1100 case kUncond:
1101 return true;
1102 case kCondGE:
1103 case kCondLE:
1104 case kCondEQ:
1105 case kCondGEU:
1106 return lhs == rhs;
1107 default:
1108 return false;
1109 }
1110}
1111
1112Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target)
1113 : old_location_(location),
1114 location_(location),
1115 target_(target),
1116 lhs_reg_(ZERO),
1117 rhs_reg_(ZERO),
1118 condition_(kUncond) {
1119 InitializeType(false);
1120}
1121
1122Mips64Assembler::Branch::Branch(uint32_t location,
1123 uint32_t target,
1124 Mips64Assembler::BranchCondition condition,
1125 GpuRegister lhs_reg,
1126 GpuRegister rhs_reg)
1127 : old_location_(location),
1128 location_(location),
1129 target_(target),
1130 lhs_reg_(lhs_reg),
1131 rhs_reg_(rhs_reg),
1132 condition_(condition) {
1133 CHECK_NE(condition, kUncond);
1134 switch (condition) {
1135 case kCondEQ:
1136 case kCondNE:
1137 case kCondLT:
1138 case kCondGE:
1139 case kCondLE:
1140 case kCondGT:
1141 case kCondLTU:
1142 case kCondGEU:
1143 CHECK_NE(lhs_reg, ZERO);
1144 CHECK_NE(rhs_reg, ZERO);
1145 break;
1146 case kCondLTZ:
1147 case kCondGEZ:
1148 case kCondLEZ:
1149 case kCondGTZ:
1150 case kCondEQZ:
1151 case kCondNEZ:
1152 CHECK_NE(lhs_reg, ZERO);
1153 CHECK_EQ(rhs_reg, ZERO);
1154 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001155 case kCondF:
1156 case kCondT:
1157 CHECK_EQ(rhs_reg, ZERO);
1158 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001159 case kUncond:
1160 UNREACHABLE();
1161 }
1162 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1163 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1164 // Branch condition is always true, make the branch unconditional.
1165 condition_ = kUncond;
1166 }
1167 InitializeType(false);
1168}
1169
1170Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg)
1171 : old_location_(location),
1172 location_(location),
1173 target_(target),
1174 lhs_reg_(indirect_reg),
1175 rhs_reg_(ZERO),
1176 condition_(kUncond) {
1177 CHECK_NE(indirect_reg, ZERO);
1178 CHECK_NE(indirect_reg, AT);
1179 InitializeType(true);
1180}
1181
1182Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1183 Mips64Assembler::BranchCondition cond) {
1184 switch (cond) {
1185 case kCondLT:
1186 return kCondGE;
1187 case kCondGE:
1188 return kCondLT;
1189 case kCondLE:
1190 return kCondGT;
1191 case kCondGT:
1192 return kCondLE;
1193 case kCondLTZ:
1194 return kCondGEZ;
1195 case kCondGEZ:
1196 return kCondLTZ;
1197 case kCondLEZ:
1198 return kCondGTZ;
1199 case kCondGTZ:
1200 return kCondLEZ;
1201 case kCondEQ:
1202 return kCondNE;
1203 case kCondNE:
1204 return kCondEQ;
1205 case kCondEQZ:
1206 return kCondNEZ;
1207 case kCondNEZ:
1208 return kCondEQZ;
1209 case kCondLTU:
1210 return kCondGEU;
1211 case kCondGEU:
1212 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001213 case kCondF:
1214 return kCondT;
1215 case kCondT:
1216 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001217 case kUncond:
1218 LOG(FATAL) << "Unexpected branch condition " << cond;
1219 }
1220 UNREACHABLE();
1221}
1222
1223Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1224 return type_;
1225}
1226
1227Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1228 return condition_;
1229}
1230
1231GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1232 return lhs_reg_;
1233}
1234
1235GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1236 return rhs_reg_;
1237}
1238
1239uint32_t Mips64Assembler::Branch::GetTarget() const {
1240 return target_;
1241}
1242
1243uint32_t Mips64Assembler::Branch::GetLocation() const {
1244 return location_;
1245}
1246
1247uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1248 return old_location_;
1249}
1250
1251uint32_t Mips64Assembler::Branch::GetLength() const {
1252 return branch_info_[type_].length;
1253}
1254
1255uint32_t Mips64Assembler::Branch::GetOldLength() const {
1256 return branch_info_[old_type_].length;
1257}
1258
1259uint32_t Mips64Assembler::Branch::GetSize() const {
1260 return GetLength() * sizeof(uint32_t);
1261}
1262
1263uint32_t Mips64Assembler::Branch::GetOldSize() const {
1264 return GetOldLength() * sizeof(uint32_t);
1265}
1266
1267uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1268 return GetLocation() + GetSize();
1269}
1270
1271uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1272 return GetOldLocation() + GetOldSize();
1273}
1274
1275bool Mips64Assembler::Branch::IsLong() const {
1276 switch (type_) {
1277 // Short branches.
1278 case kUncondBranch:
1279 case kCondBranch:
1280 case kCall:
1281 return false;
1282 // Long branches.
1283 case kLongUncondBranch:
1284 case kLongCondBranch:
1285 case kLongCall:
1286 return true;
1287 }
1288 UNREACHABLE();
1289}
1290
1291bool Mips64Assembler::Branch::IsResolved() const {
1292 return target_ != kUnresolved;
1293}
1294
1295Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1296 OffsetBits offset_size =
1297 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1298 ? kOffset23
1299 : branch_info_[type_].offset_size;
1300 return offset_size;
1301}
1302
1303Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1304 uint32_t target) {
1305 // For unresolved targets assume the shortest encoding
1306 // (later it will be made longer if needed).
1307 if (target == kUnresolved)
1308 return kOffset16;
1309 int64_t distance = static_cast<int64_t>(target) - location;
1310 // To simplify calculations in composite branches consisting of multiple instructions
1311 // bump up the distance by a value larger than the max byte size of a composite branch.
1312 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1313 if (IsInt<kOffset16>(distance))
1314 return kOffset16;
1315 else if (IsInt<kOffset18>(distance))
1316 return kOffset18;
1317 else if (IsInt<kOffset21>(distance))
1318 return kOffset21;
1319 else if (IsInt<kOffset23>(distance))
1320 return kOffset23;
1321 else if (IsInt<kOffset28>(distance))
1322 return kOffset28;
1323 return kOffset32;
1324}
1325
1326void Mips64Assembler::Branch::Resolve(uint32_t target) {
1327 target_ = target;
1328}
1329
1330void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1331 if (location_ > expand_location) {
1332 location_ += delta;
1333 }
1334 if (!IsResolved()) {
1335 return; // Don't know the target yet.
1336 }
1337 if (target_ > expand_location) {
1338 target_ += delta;
1339 }
1340}
1341
1342void Mips64Assembler::Branch::PromoteToLong() {
1343 switch (type_) {
1344 // Short branches.
1345 case kUncondBranch:
1346 type_ = kLongUncondBranch;
1347 break;
1348 case kCondBranch:
1349 type_ = kLongCondBranch;
1350 break;
1351 case kCall:
1352 type_ = kLongCall;
1353 break;
1354 default:
1355 // Note: 'type_' is already long.
1356 break;
1357 }
1358 CHECK(IsLong());
1359}
1360
1361uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1362 // If the branch is still unresolved or already long, nothing to do.
1363 if (IsLong() || !IsResolved()) {
1364 return 0;
1365 }
1366 // Promote the short branch to long if the offset size is too small
1367 // to hold the distance between location_ and target_.
1368 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1369 PromoteToLong();
1370 uint32_t old_size = GetOldSize();
1371 uint32_t new_size = GetSize();
1372 CHECK_GT(new_size, old_size);
1373 return new_size - old_size;
1374 }
1375 // The following logic is for debugging/testing purposes.
1376 // Promote some short branches to long when it's not really required.
1377 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1378 int64_t distance = static_cast<int64_t>(target_) - location_;
1379 distance = (distance >= 0) ? distance : -distance;
1380 if (distance >= max_short_distance) {
1381 PromoteToLong();
1382 uint32_t old_size = GetOldSize();
1383 uint32_t new_size = GetSize();
1384 CHECK_GT(new_size, old_size);
1385 return new_size - old_size;
1386 }
1387 }
1388 return 0;
1389}
1390
1391uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1392 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1393}
1394
1395uint32_t Mips64Assembler::Branch::GetOffset() const {
1396 CHECK(IsResolved());
1397 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1398 // Calculate the byte distance between instructions and also account for
1399 // different PC-relative origins.
1400 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t);
1401 // Prepare the offset for encoding into the instruction(s).
1402 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1403 return offset;
1404}
1405
1406Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1407 CHECK_LT(branch_id, branches_.size());
1408 return &branches_[branch_id];
1409}
1410
1411const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1412 CHECK_LT(branch_id, branches_.size());
1413 return &branches_[branch_id];
1414}
1415
1416void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001417 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001418 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001419
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001420 // Walk the list of branches referring to and preceding this label.
1421 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001422 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001423 uint32_t branch_id = label->Position();
1424 Branch* branch = GetBranch(branch_id);
1425 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001426
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001427 uint32_t branch_location = branch->GetLocation();
1428 // Extract the location of the previous branch in the list (walking the list backwards;
1429 // the previous branch ID was stored in the space reserved for this branch).
1430 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001431
1432 // On to the previous branch in the list...
1433 label->position_ = prev;
1434 }
1435
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001436 // Now make the label object contain its own location (relative to the end of the preceding
1437 // branch, if any; it will be used by the branches referring to and following this label).
1438 label->prev_branch_id_plus_one_ = branches_.size();
1439 if (label->prev_branch_id_plus_one_) {
1440 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1441 const Branch* branch = GetBranch(branch_id);
1442 bound_pc -= branch->GetEndLocation();
1443 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001444 label->BindTo(bound_pc);
1445}
1446
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001447uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const {
1448 CHECK(label->IsBound());
1449 uint32_t target = label->Position();
1450 if (label->prev_branch_id_plus_one_) {
1451 // Get label location based on the branch preceding it.
1452 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1453 const Branch* branch = GetBranch(branch_id);
1454 target += branch->GetEndLocation();
1455 }
1456 return target;
1457}
1458
1459uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1460 // We can reconstruct the adjustment by going through all the branches from the beginning
1461 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1462 // with increasing old_position, we can use the data from last AdjustedPosition() to
1463 // continue where we left off and the whole loop should be O(m+n) where m is the number
1464 // of positions to adjust and n is the number of branches.
1465 if (old_position < last_old_position_) {
1466 last_position_adjustment_ = 0;
1467 last_old_position_ = 0;
1468 last_branch_id_ = 0;
1469 }
1470 while (last_branch_id_ != branches_.size()) {
1471 const Branch* branch = GetBranch(last_branch_id_);
1472 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1473 break;
1474 }
1475 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1476 ++last_branch_id_;
1477 }
1478 last_old_position_ = old_position;
1479 return old_position + last_position_adjustment_;
1480}
1481
1482void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1483 uint32_t length = branches_.back().GetLength();
1484 if (!label->IsBound()) {
1485 // Branch forward (to a following label), distance is unknown.
1486 // The first branch forward will contain 0, serving as the terminator of
1487 // the list of forward-reaching branches.
1488 Emit(label->position_);
1489 length--;
1490 // Now make the label object point to this branch
1491 // (this forms a linked list of branches preceding this label).
1492 uint32_t branch_id = branches_.size() - 1;
1493 label->LinkTo(branch_id);
1494 }
1495 // Reserve space for the branch.
1496 while (length--) {
1497 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001498 }
1499}
1500
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001501void Mips64Assembler::Buncond(Mips64Label* label) {
1502 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1503 branches_.emplace_back(buffer_.Size(), target);
1504 FinalizeLabeledBranch(label);
1505}
1506
1507void Mips64Assembler::Bcond(Mips64Label* label,
1508 BranchCondition condition,
1509 GpuRegister lhs,
1510 GpuRegister rhs) {
1511 // If lhs = rhs, this can be a NOP.
1512 if (Branch::IsNop(condition, lhs, rhs)) {
1513 return;
1514 }
1515 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1516 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1517 FinalizeLabeledBranch(label);
1518}
1519
1520void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) {
1521 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1522 branches_.emplace_back(buffer_.Size(), target, indirect_reg);
1523 FinalizeLabeledBranch(label);
1524}
1525
1526void Mips64Assembler::PromoteBranches() {
1527 // Promote short branches to long as necessary.
1528 bool changed;
1529 do {
1530 changed = false;
1531 for (auto& branch : branches_) {
1532 CHECK(branch.IsResolved());
1533 uint32_t delta = branch.PromoteIfNeeded();
1534 // If this branch has been promoted and needs to expand in size,
1535 // relocate all branches by the expansion size.
1536 if (delta) {
1537 changed = true;
1538 uint32_t expand_location = branch.GetLocation();
1539 for (auto& branch2 : branches_) {
1540 branch2.Relocate(expand_location, delta);
1541 }
1542 }
1543 }
1544 } while (changed);
1545
1546 // Account for branch expansion by resizing the code buffer
1547 // and moving the code in it to its final location.
1548 size_t branch_count = branches_.size();
1549 if (branch_count > 0) {
1550 // Resize.
1551 Branch& last_branch = branches_[branch_count - 1];
1552 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1553 uint32_t old_size = buffer_.Size();
1554 buffer_.Resize(old_size + size_delta);
1555 // Move the code residing between branch placeholders.
1556 uint32_t end = old_size;
1557 for (size_t i = branch_count; i > 0; ) {
1558 Branch& branch = branches_[--i];
1559 uint32_t size = end - branch.GetOldEndLocation();
1560 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1561 end = branch.GetOldLocation();
1562 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001563 }
1564}
1565
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001566// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1567const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1568 // Short branches.
1569 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1570 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1571 // Exception: kOffset23 for beqzc/bnezc
1572 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall
1573 // Long branches.
1574 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1575 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
1576 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1577};
1578
1579// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1580void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1581 CHECK(overwriting_);
1582 overwrite_location_ = branch->GetLocation();
1583 uint32_t offset = branch->GetOffset();
1584 BranchCondition condition = branch->GetCondition();
1585 GpuRegister lhs = branch->GetLeftRegister();
1586 GpuRegister rhs = branch->GetRightRegister();
1587 switch (branch->GetType()) {
1588 // Short branches.
1589 case Branch::kUncondBranch:
1590 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1591 Bc(offset);
1592 break;
1593 case Branch::kCondBranch:
1594 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1595 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001596 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001597 break;
1598 case Branch::kCall:
1599 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1600 Addiupc(lhs, offset);
1601 Jialc(lhs, 0);
1602 break;
1603
1604 // Long branches.
1605 case Branch::kLongUncondBranch:
1606 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1607 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1608 Auipc(AT, High16Bits(offset));
1609 Jic(AT, Low16Bits(offset));
1610 break;
1611 case Branch::kLongCondBranch:
1612 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1613 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1614 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1615 Auipc(AT, High16Bits(offset));
1616 Jic(AT, Low16Bits(offset));
1617 break;
1618 case Branch::kLongCall:
1619 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
1620 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1621 Auipc(lhs, High16Bits(offset));
1622 Daddiu(lhs, lhs, Low16Bits(offset));
1623 Jialc(lhs, 0);
1624 break;
1625 }
1626 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1627 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001628}
1629
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001630void Mips64Assembler::Bc(Mips64Label* label) {
1631 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001632}
1633
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001634void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) {
1635 Call(label, indirect_reg);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001636}
1637
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001638void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1639 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001640}
1641
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001642void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1643 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001644}
1645
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001646void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1647 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001648}
1649
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001650void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1651 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001652}
1653
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001654void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1655 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001656}
1657
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001658void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1659 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001660}
1661
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001662void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1663 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001664}
1665
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001666void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1667 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001668}
1669
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001670void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1671 Bcond(label, kCondEQ, rs, rt);
1672}
1673
1674void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1675 Bcond(label, kCondNE, rs, rt);
1676}
1677
1678void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1679 Bcond(label, kCondEQZ, rs);
1680}
1681
1682void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1683 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001684}
1685
Alexey Frunze299a9392015-12-08 16:08:02 -08001686void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1687 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1688}
1689
1690void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1691 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1692}
1693
Andreas Gampe57b34292015-01-14 15:45:59 -08001694void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1695 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001696 if (!IsInt<16>(offset) ||
1697 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1698 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1699 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001700 Daddu(AT, AT, base);
1701 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001702 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001703 }
1704
Andreas Gampe57b34292015-01-14 15:45:59 -08001705 switch (type) {
1706 case kLoadSignedByte:
1707 Lb(reg, base, offset);
1708 break;
1709 case kLoadUnsignedByte:
1710 Lbu(reg, base, offset);
1711 break;
1712 case kLoadSignedHalfword:
1713 Lh(reg, base, offset);
1714 break;
1715 case kLoadUnsignedHalfword:
1716 Lhu(reg, base, offset);
1717 break;
1718 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001719 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001720 Lw(reg, base, offset);
1721 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001722 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001723 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07001724 Lwu(reg, base, offset);
1725 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001726 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001727 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1728 CHECK_ALIGNED(offset, kMips64WordSize);
1729 Lwu(reg, base, offset);
1730 Lwu(TMP2, base, offset + kMips64WordSize);
1731 Dinsu(reg, TMP2, 32, 32);
1732 } else {
1733 Ld(reg, base, offset);
1734 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001735 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001736 }
1737}
1738
1739void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1740 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001741 if (!IsInt<16>(offset) ||
1742 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1743 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1744 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001745 Daddu(AT, AT, base);
1746 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001747 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001748 }
1749
Andreas Gampe57b34292015-01-14 15:45:59 -08001750 switch (type) {
1751 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001752 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001753 Lwc1(reg, base, offset);
1754 break;
1755 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001756 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1757 CHECK_ALIGNED(offset, kMips64WordSize);
1758 Lwc1(reg, base, offset);
1759 Lw(TMP2, base, offset + kMips64WordSize);
1760 Mthc1(TMP2, reg);
1761 } else {
1762 Ldc1(reg, base, offset);
1763 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001764 break;
1765 default:
1766 LOG(FATAL) << "UNREACHABLE";
1767 }
1768}
1769
1770void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
1771 size_t size) {
1772 Mips64ManagedRegister dst = m_dst.AsMips64();
1773 if (dst.IsNoRegister()) {
1774 CHECK_EQ(0u, size) << dst;
1775 } else if (dst.IsGpuRegister()) {
1776 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001777 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
1778 } else if (size == 8) {
1779 CHECK_EQ(8u, size) << dst;
1780 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
1781 } else {
1782 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1783 }
1784 } else if (dst.IsFpuRegister()) {
1785 if (size == 4) {
1786 CHECK_EQ(4u, size) << dst;
1787 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
1788 } else if (size == 8) {
1789 CHECK_EQ(8u, size) << dst;
1790 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
1791 } else {
1792 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
1793 }
1794 }
1795}
1796
1797void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
1798 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001799 if (!IsInt<16>(offset) ||
1800 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1801 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1802 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001803 Daddu(AT, AT, base);
1804 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001805 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001806 }
1807
Andreas Gampe57b34292015-01-14 15:45:59 -08001808 switch (type) {
1809 case kStoreByte:
1810 Sb(reg, base, offset);
1811 break;
1812 case kStoreHalfword:
1813 Sh(reg, base, offset);
1814 break;
1815 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001816 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001817 Sw(reg, base, offset);
1818 break;
1819 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001820 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1821 CHECK_ALIGNED(offset, kMips64WordSize);
1822 Sw(reg, base, offset);
1823 Dsrl32(TMP2, reg, 0);
1824 Sw(TMP2, base, offset + kMips64WordSize);
1825 } else {
1826 Sd(reg, base, offset);
1827 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001828 break;
1829 default:
1830 LOG(FATAL) << "UNREACHABLE";
1831 }
1832}
1833
1834void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
1835 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001836 if (!IsInt<16>(offset) ||
1837 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1838 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1839 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001840 Daddu(AT, AT, base);
1841 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001842 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001843 }
1844
Andreas Gampe57b34292015-01-14 15:45:59 -08001845 switch (type) {
1846 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001847 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001848 Swc1(reg, base, offset);
1849 break;
1850 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001851 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1852 CHECK_ALIGNED(offset, kMips64WordSize);
1853 Mfhc1(TMP2, reg);
1854 Swc1(reg, base, offset);
1855 Sw(TMP2, base, offset + kMips64WordSize);
1856 } else {
1857 Sdc1(reg, base, offset);
1858 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001859 break;
1860 default:
1861 LOG(FATAL) << "UNREACHABLE";
1862 }
1863}
1864
David Srbeckydd973932015-04-07 20:29:48 +01001865static dwarf::Reg DWARFReg(GpuRegister reg) {
1866 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1867}
1868
Andreas Gampe57b34292015-01-14 15:45:59 -08001869constexpr size_t kFramePointerSize = 8;
1870
Vladimir Marko32248382016-05-19 10:37:24 +01001871void Mips64Assembler::BuildFrame(size_t frame_size,
1872 ManagedRegister method_reg,
1873 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08001874 const ManagedRegisterEntrySpills& entry_spills) {
1875 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001876 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08001877
1878 // Increase frame to required size.
1879 IncreaseFrameSize(frame_size);
1880
1881 // Push callee saves and return address
1882 int stack_offset = frame_size - kFramePointerSize;
1883 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001884 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001885 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
1886 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01001887 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08001888 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001889 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001890 }
1891
1892 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001893 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001894
1895 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001896 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08001897 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01001898 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08001899 ManagedRegisterSpill spill = entry_spills.at(i);
1900 int32_t size = spill.getSize();
1901 if (reg.IsNoRegister()) {
1902 // only increment stack offset.
1903 offset += size;
1904 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001905 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1906 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001907 offset += size;
1908 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001909 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
1910 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08001911 offset += size;
1912 }
1913 }
1914}
1915
1916void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01001917 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001918 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001919 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01001920 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08001921
1922 // Pop callee saves and return address
1923 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
1924 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01001925 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08001926 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001927 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08001928 stack_offset += kFramePointerSize;
1929 }
1930 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01001931 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08001932
1933 // Decrease frame to required size.
1934 DecreaseFrameSize(frame_size);
1935
1936 // Then jump to the return address.
1937 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001938 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01001939
1940 // The CFI should be restored for any code that follows the exit block.
1941 cfi_.RestoreState();
1942 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08001943}
1944
1945void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001946 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001947 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001948 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001949 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001950}
1951
1952void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001953 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001954 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001955 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01001956 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08001957}
1958
1959void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
1960 Mips64ManagedRegister src = msrc.AsMips64();
1961 if (src.IsNoRegister()) {
1962 CHECK_EQ(0u, size);
1963 } else if (src.IsGpuRegister()) {
1964 CHECK(size == 4 || size == 8) << size;
1965 if (size == 8) {
1966 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
1967 } else if (size == 4) {
1968 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
1969 } else {
1970 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
1971 }
1972 } else if (src.IsFpuRegister()) {
1973 CHECK(size == 4 || size == 8) << size;
1974 if (size == 8) {
1975 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
1976 } else if (size == 4) {
1977 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
1978 } else {
1979 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
1980 }
1981 }
1982}
1983
1984void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
1985 Mips64ManagedRegister src = msrc.AsMips64();
1986 CHECK(src.IsGpuRegister());
1987 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
1988}
1989
1990void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
1991 Mips64ManagedRegister src = msrc.AsMips64();
1992 CHECK(src.IsGpuRegister());
1993 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
1994}
1995
1996void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
1997 ManagedRegister mscratch) {
1998 Mips64ManagedRegister scratch = mscratch.AsMips64();
1999 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002000 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002001 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2002}
2003
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002004void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2005 FrameOffset fr_offs,
2006 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002007 Mips64ManagedRegister scratch = mscratch.AsMips64();
2008 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002009 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002010 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2011}
2012
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002013void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002014 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2015}
2016
2017void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2018 FrameOffset in_off, ManagedRegister mscratch) {
2019 Mips64ManagedRegister src = msrc.AsMips64();
2020 Mips64ManagedRegister scratch = mscratch.AsMips64();
2021 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2022 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2023 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2024}
2025
2026void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2027 return EmitLoad(mdest, SP, src.Int32Value(), size);
2028}
2029
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002030void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002031 return EmitLoad(mdest, S1, src.Int32Value(), size);
2032}
2033
2034void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2035 Mips64ManagedRegister dest = mdest.AsMips64();
2036 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002037 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002038}
2039
Mathieu Chartiere401d142015-04-22 13:56:20 -07002040void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002041 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002042 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002043 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2044 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002045 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002046 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002047 // TODO: review
2048 // Negate the 32-bit ref
2049 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2050 // 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 +02002051 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002052 }
2053}
2054
2055void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002056 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002057 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002058 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002059 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2060 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2061}
2062
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002063void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002064 Mips64ManagedRegister dest = mdest.AsMips64();
2065 CHECK(dest.IsGpuRegister());
2066 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2067}
2068
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002069void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2070 size_t size ATTRIBUTE_UNUSED) {
2071 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002072}
2073
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002074void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2075 size_t size ATTRIBUTE_UNUSED) {
2076 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002077}
2078
2079void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2080 Mips64ManagedRegister dest = mdest.AsMips64();
2081 Mips64ManagedRegister src = msrc.AsMips64();
2082 if (!dest.Equals(src)) {
2083 if (dest.IsGpuRegister()) {
2084 CHECK(src.IsGpuRegister()) << src;
2085 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2086 } else if (dest.IsFpuRegister()) {
2087 CHECK(src.IsFpuRegister()) << src;
2088 if (size == 4) {
2089 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2090 } else if (size == 8) {
2091 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2092 } else {
2093 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2094 }
2095 }
2096 }
2097}
2098
2099void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2100 ManagedRegister mscratch) {
2101 Mips64ManagedRegister scratch = mscratch.AsMips64();
2102 CHECK(scratch.IsGpuRegister()) << scratch;
2103 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2104 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2105}
2106
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002107void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2108 ThreadOffset64 thr_offs,
2109 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002110 Mips64ManagedRegister scratch = mscratch.AsMips64();
2111 CHECK(scratch.IsGpuRegister()) << scratch;
2112 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2113 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2114}
2115
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002116void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2117 FrameOffset fr_offs,
2118 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002119 Mips64ManagedRegister scratch = mscratch.AsMips64();
2120 CHECK(scratch.IsGpuRegister()) << scratch;
2121 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2122 SP, fr_offs.Int32Value());
2123 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2124 S1, thr_offs.Int32Value());
2125}
2126
2127void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2128 ManagedRegister mscratch, size_t size) {
2129 Mips64ManagedRegister scratch = mscratch.AsMips64();
2130 CHECK(scratch.IsGpuRegister()) << scratch;
2131 CHECK(size == 4 || size == 8) << size;
2132 if (size == 4) {
2133 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002134 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002135 } else if (size == 8) {
2136 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2137 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2138 } else {
2139 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2140 }
2141}
2142
2143void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002144 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002145 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2146 CHECK(size == 4 || size == 8) << size;
2147 if (size == 4) {
2148 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2149 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002150 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002151 } else if (size == 8) {
2152 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2153 src_offset.Int32Value());
2154 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2155 } else {
2156 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2157 }
2158}
2159
2160void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002161 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002162 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2163 CHECK(size == 4 || size == 8) << size;
2164 if (size == 4) {
2165 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002166 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002167 dest_offset.Int32Value());
2168 } else if (size == 8) {
2169 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2170 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2171 dest_offset.Int32Value());
2172 } else {
2173 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2174 }
2175}
2176
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002177void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2178 FrameOffset src_base ATTRIBUTE_UNUSED,
2179 Offset src_offset ATTRIBUTE_UNUSED,
2180 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2181 size_t size ATTRIBUTE_UNUSED) {
2182 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002183}
2184
2185void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002186 ManagedRegister src, Offset src_offset,
2187 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002188 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2189 CHECK(size == 4 || size == 8) << size;
2190 if (size == 4) {
2191 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002192 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002193 } else if (size == 8) {
2194 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2195 src_offset.Int32Value());
2196 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2197 dest_offset.Int32Value());
2198 } else {
2199 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2200 }
2201}
2202
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002203void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2204 Offset dest_offset ATTRIBUTE_UNUSED,
2205 FrameOffset src ATTRIBUTE_UNUSED,
2206 Offset src_offset ATTRIBUTE_UNUSED,
2207 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2208 size_t size ATTRIBUTE_UNUSED) {
2209 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002210}
2211
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002212void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002213 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002214 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002215}
2216
2217void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002218 FrameOffset handle_scope_offset,
2219 ManagedRegister min_reg,
2220 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002221 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2222 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2223 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2224 CHECK(out_reg.IsGpuRegister()) << out_reg;
2225 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002226 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002227 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2228 // the address in the handle scope holding the reference.
2229 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2230 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002231 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002232 SP, handle_scope_offset.Int32Value());
2233 in_reg = out_reg;
2234 }
2235 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002236 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002237 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002238 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2239 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2240 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002241 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002242 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002243 }
2244}
2245
2246void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002247 FrameOffset handle_scope_offset,
2248 ManagedRegister mscratch,
2249 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002250 Mips64ManagedRegister scratch = mscratch.AsMips64();
2251 CHECK(scratch.IsGpuRegister()) << scratch;
2252 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002253 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002254 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002255 handle_scope_offset.Int32Value());
2256 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2257 // the address in the handle scope holding the reference.
2258 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002259 Beqzc(scratch.AsGpuRegister(), &null_arg);
2260 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2261 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002262 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002263 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002264 }
2265 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2266}
2267
2268// Given a handle scope entry, load the associated reference.
2269void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002270 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002271 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2272 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2273 CHECK(out_reg.IsGpuRegister()) << out_reg;
2274 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002275 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002277 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002278 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002279 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002280 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2281 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002282 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002283}
2284
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002285void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2286 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002287 // TODO: not validating references
2288}
2289
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002290void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2291 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002292 // TODO: not validating references
2293}
2294
2295void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2296 Mips64ManagedRegister base = mbase.AsMips64();
2297 Mips64ManagedRegister scratch = mscratch.AsMips64();
2298 CHECK(base.IsGpuRegister()) << base;
2299 CHECK(scratch.IsGpuRegister()) << scratch;
2300 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2301 base.AsGpuRegister(), offset.Int32Value());
2302 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002303 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002304 // TODO: place reference map on call
2305}
2306
2307void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2308 Mips64ManagedRegister scratch = mscratch.AsMips64();
2309 CHECK(scratch.IsGpuRegister()) << scratch;
2310 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002311 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002312 SP, base.Int32Value());
2313 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2314 scratch.AsGpuRegister(), offset.Int32Value());
2315 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002316 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002317 // TODO: place reference map on call
2318}
2319
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002320void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2321 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002322 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002323}
2324
2325void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2326 Move(tr.AsMips64().AsGpuRegister(), S1);
2327}
2328
2329void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002330 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002331 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2332}
2333
2334void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2335 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002336 exception_blocks_.emplace_back(scratch, stack_adjust);
2337 LoadFromOffset(kLoadDoubleword,
2338 scratch.AsGpuRegister(),
2339 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002340 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002341 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002342}
2343
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002344void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2345 Bind(exception->Entry());
2346 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2347 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002348 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002349 // Pass exception object as argument.
2350 // Don't care about preserving A0 as this call won't return.
2351 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2352 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002353 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002354 LoadFromOffset(kLoadDoubleword,
2355 T9,
2356 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002357 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002358 Jr(T9);
2359 Nop();
2360
Andreas Gampe57b34292015-01-14 15:45:59 -08002361 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002362 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002363}
2364
2365} // namespace mips64
2366} // namespace art