blob: 04430b13f141cd093e6cd61879771bd1cd24f171 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
Alexey Frunze19f6c692016-11-30 19:19:55 -080038 EmitLiterals();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070039 PromoteBranches();
40}
41
42void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
43 EmitBranches();
44 Assembler::FinalizeInstructions(region);
45 PatchCFI();
46}
47
48void Mips64Assembler::PatchCFI() {
49 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
50 return;
51 }
52
53 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
54 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
55 const std::vector<uint8_t>& old_stream = data.first;
56 const std::vector<DelayedAdvancePC>& advances = data.second;
57
58 // Refill our data buffer with patched opcodes.
59 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
60 size_t stream_pos = 0;
61 for (const DelayedAdvancePC& advance : advances) {
62 DCHECK_GE(advance.stream_pos, stream_pos);
63 // Copy old data up to the point where advance was issued.
64 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
65 stream_pos = advance.stream_pos;
66 // Insert the advance command with its final offset.
67 size_t final_pc = GetAdjustedPosition(advance.pc);
68 cfi().AdvancePC(final_pc);
69 }
70 // Copy the final segment if any.
71 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
72}
73
74void Mips64Assembler::EmitBranches() {
75 CHECK(!overwriting_);
76 // Switch from appending instructions at the end of the buffer to overwriting
77 // existing instructions (branch placeholders) in the buffer.
78 overwriting_ = true;
79 for (auto& branch : branches_) {
80 EmitBranch(&branch);
81 }
82 overwriting_ = false;
83}
84
Alexey Frunze4dda3372015-06-01 18:31:49 -070085void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070086 if (overwriting_) {
87 // Branches to labels are emitted into their placeholders here.
88 buffer_.Store<uint32_t>(overwrite_location_, value);
89 overwrite_location_ += sizeof(uint32_t);
90 } else {
91 // Other instructions are simply appended at the end here.
92 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
93 buffer_.Emit<uint32_t>(value);
94 }
Andreas Gampe57b34292015-01-14 15:45:59 -080095}
96
97void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
98 int shamt, int funct) {
99 CHECK_NE(rs, kNoGpuRegister);
100 CHECK_NE(rt, kNoGpuRegister);
101 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700102 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
103 static_cast<uint32_t>(rs) << kRsShift |
104 static_cast<uint32_t>(rt) << kRtShift |
105 static_cast<uint32_t>(rd) << kRdShift |
106 shamt << kShamtShift |
107 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800108 Emit(encoding);
109}
110
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700111void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
112 int shamt, int funct) {
113 CHECK_NE(rs, kNoGpuRegister);
114 CHECK_NE(rd, kNoGpuRegister);
115 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
116 static_cast<uint32_t>(rs) << kRsShift |
117 static_cast<uint32_t>(ZERO) << kRtShift |
118 static_cast<uint32_t>(rd) << kRdShift |
119 shamt << kShamtShift |
120 funct;
121 Emit(encoding);
122}
123
124void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
125 int shamt, int funct) {
126 CHECK_NE(rt, kNoGpuRegister);
127 CHECK_NE(rd, kNoGpuRegister);
128 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
129 static_cast<uint32_t>(ZERO) << kRsShift |
130 static_cast<uint32_t>(rt) << kRtShift |
131 static_cast<uint32_t>(rd) << kRdShift |
132 shamt << kShamtShift |
133 funct;
134 Emit(encoding);
135}
136
Andreas Gampe57b34292015-01-14 15:45:59 -0800137void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
138 CHECK_NE(rs, kNoGpuRegister);
139 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700140 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
141 static_cast<uint32_t>(rs) << kRsShift |
142 static_cast<uint32_t>(rt) << kRtShift |
143 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800144 Emit(encoding);
145}
146
Alexey Frunze4dda3372015-06-01 18:31:49 -0700147void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
148 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700149 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700150 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
151 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700152 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700153 Emit(encoding);
154}
155
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700156void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
157 CHECK(IsUint<26>(imm26)) << imm26;
158 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800159 Emit(encoding);
160}
161
162void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700163 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800164 CHECK_NE(ft, kNoFpuRegister);
165 CHECK_NE(fs, kNoFpuRegister);
166 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700167 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
168 fmt << kFmtShift |
169 static_cast<uint32_t>(ft) << kFtShift |
170 static_cast<uint32_t>(fs) << kFsShift |
171 static_cast<uint32_t>(fd) << kFdShift |
172 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800173 Emit(encoding);
174}
175
Alexey Frunze4dda3372015-06-01 18:31:49 -0700176void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
177 CHECK_NE(ft, kNoFpuRegister);
178 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
179 fmt << kFmtShift |
180 static_cast<uint32_t>(ft) << kFtShift |
181 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800182 Emit(encoding);
183}
184
Andreas Gampe57b34292015-01-14 15:45:59 -0800185void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
186 EmitR(0, rs, rt, rd, 0, 0x21);
187}
188
189void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
190 EmitI(0x9, rs, rt, imm16);
191}
192
Alexey Frunze4dda3372015-06-01 18:31:49 -0700193void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
194 EmitR(0, rs, rt, rd, 0, 0x2d);
195}
196
Andreas Gampe57b34292015-01-14 15:45:59 -0800197void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
198 EmitI(0x19, rs, rt, imm16);
199}
200
Andreas Gampe57b34292015-01-14 15:45:59 -0800201void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
202 EmitR(0, rs, rt, rd, 0, 0x23);
203}
204
Alexey Frunze4dda3372015-06-01 18:31:49 -0700205void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
206 EmitR(0, rs, rt, rd, 0, 0x2f);
207}
208
Alexey Frunze4dda3372015-06-01 18:31:49 -0700209void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
210 EmitR(0, rs, rt, rd, 2, 0x18);
211}
212
Alexey Frunzec857c742015-09-23 15:12:39 -0700213void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
214 EmitR(0, rs, rt, rd, 3, 0x18);
215}
216
Alexey Frunze4dda3372015-06-01 18:31:49 -0700217void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
218 EmitR(0, rs, rt, rd, 2, 0x1a);
219}
220
221void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
222 EmitR(0, rs, rt, rd, 3, 0x1a);
223}
224
225void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
226 EmitR(0, rs, rt, rd, 2, 0x1b);
227}
228
229void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
230 EmitR(0, rs, rt, rd, 3, 0x1b);
231}
232
233void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
234 EmitR(0, rs, rt, rd, 2, 0x1c);
235}
236
Alexey Frunzec857c742015-09-23 15:12:39 -0700237void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
238 EmitR(0, rs, rt, rd, 3, 0x1c);
239}
240
Alexey Frunze4dda3372015-06-01 18:31:49 -0700241void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
242 EmitR(0, rs, rt, rd, 2, 0x1e);
243}
244
245void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
246 EmitR(0, rs, rt, rd, 3, 0x1e);
247}
248
249void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
250 EmitR(0, rs, rt, rd, 2, 0x1f);
251}
252
253void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
254 EmitR(0, rs, rt, rd, 3, 0x1f);
255}
256
Andreas Gampe57b34292015-01-14 15:45:59 -0800257void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
258 EmitR(0, rs, rt, rd, 0, 0x24);
259}
260
261void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
262 EmitI(0xc, rs, rt, imm16);
263}
264
265void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
266 EmitR(0, rs, rt, rd, 0, 0x25);
267}
268
269void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
270 EmitI(0xd, rs, rt, imm16);
271}
272
273void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
274 EmitR(0, rs, rt, rd, 0, 0x26);
275}
276
277void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
278 EmitI(0xe, rs, rt, imm16);
279}
280
281void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
282 EmitR(0, rs, rt, rd, 0, 0x27);
283}
284
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700285void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
286 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
287}
288
289void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
290 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
291}
292
Alexey Frunze4dda3372015-06-01 18:31:49 -0700293void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
294 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800295}
296
Alexey Frunze4dda3372015-06-01 18:31:49 -0700297void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
298 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800299}
300
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700301void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
302 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
303}
304
305void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
306 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
307}
308
Lazar Trsicd9672662015-09-03 17:33:01 +0200309void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
310 CHECK(IsUint<5>(pos)) << pos;
311 CHECK(IsUint<5>(size - 1)) << size;
312 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
313}
314
315void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
316 CHECK(IsUint<5>(pos - 32)) << pos;
317 CHECK(IsUint<5>(size - 1)) << size;
318 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
319 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800320}
321
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700322void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
323 EmitRtd(0x1f, rt, rd, 2, 0x20);
324}
325
326void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200327 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700328 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
329}
330
331void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200332 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700333 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
334}
335
336void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200337 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700338 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
339}
340
341void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200342 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700343 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
344}
345
Alexey Frunze4dda3372015-06-01 18:31:49 -0700346void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
347 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
348}
349
350void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
351 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
352}
353
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700354void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
355 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
356}
357
Alexey Frunze4dda3372015-06-01 18:31:49 -0700358void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
359 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
360}
361
362void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800363 EmitR(0, rs, rt, rd, 0, 0x04);
364}
365
Chris Larsen9aebff22015-09-22 17:54:15 -0700366void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
367 EmitR(0, rs, rt, rd, 1, 0x06);
368}
369
Alexey Frunze4dda3372015-06-01 18:31:49 -0700370void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800371 EmitR(0, rs, rt, rd, 0, 0x06);
372}
373
Alexey Frunze4dda3372015-06-01 18:31:49 -0700374void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800375 EmitR(0, rs, rt, rd, 0, 0x07);
376}
377
Alexey Frunze4dda3372015-06-01 18:31:49 -0700378void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
379 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
380}
381
382void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
383 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
384}
385
Chris Larsen9aebff22015-09-22 17:54:15 -0700386void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
387 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
388}
389
Alexey Frunze4dda3372015-06-01 18:31:49 -0700390void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
391 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
392}
393
394void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
395 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
396}
397
398void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
399 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
400}
401
Chris Larsen9aebff22015-09-22 17:54:15 -0700402void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
403 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
404}
405
Alexey Frunze4dda3372015-06-01 18:31:49 -0700406void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
407 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
408}
409
410void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
411 EmitR(0, rs, rt, rd, 0, 0x14);
412}
413
414void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
415 EmitR(0, rs, rt, rd, 0, 0x16);
416}
417
Chris Larsen9aebff22015-09-22 17:54:15 -0700418void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
419 EmitR(0, rs, rt, rd, 1, 0x16);
420}
421
Alexey Frunze4dda3372015-06-01 18:31:49 -0700422void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
423 EmitR(0, rs, rt, rd, 0, 0x17);
424}
425
Andreas Gampe57b34292015-01-14 15:45:59 -0800426void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
427 EmitI(0x20, rs, rt, imm16);
428}
429
430void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
431 EmitI(0x21, rs, rt, imm16);
432}
433
434void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
435 EmitI(0x23, rs, rt, imm16);
436}
437
438void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
439 EmitI(0x37, rs, rt, imm16);
440}
441
442void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
443 EmitI(0x24, rs, rt, imm16);
444}
445
446void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
447 EmitI(0x25, rs, rt, imm16);
448}
449
Douglas Leungd90957f2015-04-30 19:22:49 -0700450void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
451 EmitI(0x27, rs, rt, imm16);
452}
453
Alexey Frunze19f6c692016-11-30 19:19:55 -0800454void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
455 CHECK(IsUint<19>(imm19)) << imm19;
456 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
457}
458
459void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
460 CHECK(IsUint<19>(imm19)) << imm19;
461 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
462}
463
464void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
465 CHECK(IsUint<18>(imm18)) << imm18;
466 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
467}
468
Andreas Gampe57b34292015-01-14 15:45:59 -0800469void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
470 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
471}
472
Alexey Frunze4dda3372015-06-01 18:31:49 -0700473void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
474 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
475}
476
477void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
478 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
479}
480
481void Mips64Assembler::Sync(uint32_t stype) {
482 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
483 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
484}
485
Andreas Gampe57b34292015-01-14 15:45:59 -0800486void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
487 EmitI(0x28, rs, rt, imm16);
488}
489
490void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
491 EmitI(0x29, rs, rt, imm16);
492}
493
494void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
495 EmitI(0x2b, rs, rt, imm16);
496}
497
498void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
499 EmitI(0x3f, rs, rt, imm16);
500}
501
502void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
503 EmitR(0, rs, rt, rd, 0, 0x2a);
504}
505
506void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
507 EmitR(0, rs, rt, rd, 0, 0x2b);
508}
509
510void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
511 EmitI(0xa, rs, rt, imm16);
512}
513
514void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
515 EmitI(0xb, rs, rt, imm16);
516}
517
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700518void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
519 EmitR(0, rs, rt, rd, 0, 0x35);
520}
521
522void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
523 EmitR(0, rs, rt, rd, 0, 0x37);
524}
525
526void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
527 EmitRsd(0, rs, rd, 0x01, 0x10);
528}
529
530void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
531 EmitRsd(0, rs, rd, 0x01, 0x11);
532}
533
534void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
535 EmitRsd(0, rs, rd, 0x01, 0x12);
536}
537
538void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
539 EmitRsd(0, rs, rd, 0x01, 0x13);
540}
541
Alexey Frunze4dda3372015-06-01 18:31:49 -0700542void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
543 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800544}
545
546void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700547 Jalr(RA, rs);
548}
549
550void Mips64Assembler::Jr(GpuRegister rs) {
551 Jalr(ZERO, rs);
552}
553
554void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
555 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
556}
557
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700558void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
559 CHECK(IsUint<19>(imm19)) << imm19;
560 EmitI21(0x3B, rs, imm19);
561}
562
563void Mips64Assembler::Bc(uint32_t imm26) {
564 EmitI26(0x32, imm26);
565}
566
Alexey Frunze19f6c692016-11-30 19:19:55 -0800567void Mips64Assembler::Balc(uint32_t imm26) {
568 EmitI26(0x3A, imm26);
569}
570
Alexey Frunze4dda3372015-06-01 18:31:49 -0700571void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
572 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
573}
574
575void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
576 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
577}
578
579void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
580 CHECK_NE(rs, ZERO);
581 CHECK_NE(rt, ZERO);
582 CHECK_NE(rs, rt);
583 EmitI(0x17, rs, rt, imm16);
584}
585
586void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
587 CHECK_NE(rt, ZERO);
588 EmitI(0x17, rt, rt, imm16);
589}
590
591void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
592 CHECK_NE(rt, ZERO);
593 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
594}
595
596void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
597 CHECK_NE(rs, ZERO);
598 CHECK_NE(rt, ZERO);
599 CHECK_NE(rs, rt);
600 EmitI(0x16, rs, rt, imm16);
601}
602
603void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
604 CHECK_NE(rt, ZERO);
605 EmitI(0x16, rt, rt, imm16);
606}
607
608void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
609 CHECK_NE(rt, ZERO);
610 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
611}
612
613void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
614 CHECK_NE(rs, ZERO);
615 CHECK_NE(rt, ZERO);
616 CHECK_NE(rs, rt);
617 EmitI(0x7, rs, rt, imm16);
618}
619
620void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
621 CHECK_NE(rs, ZERO);
622 CHECK_NE(rt, ZERO);
623 CHECK_NE(rs, rt);
624 EmitI(0x6, rs, rt, imm16);
625}
626
627void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
628 CHECK_NE(rs, ZERO);
629 CHECK_NE(rt, ZERO);
630 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700631 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700632}
633
634void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
635 CHECK_NE(rs, ZERO);
636 CHECK_NE(rt, ZERO);
637 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700638 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700639}
640
641void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
642 CHECK_NE(rs, ZERO);
643 EmitI21(0x36, rs, imm21);
644}
645
646void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
647 CHECK_NE(rs, ZERO);
648 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800649}
650
Alexey Frunze299a9392015-12-08 16:08:02 -0800651void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
652 EmitFI(0x11, 0x9, ft, imm16);
653}
654
655void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
656 EmitFI(0x11, 0xD, ft, imm16);
657}
658
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700659void Mips64Assembler::EmitBcondc(BranchCondition cond,
660 GpuRegister rs,
661 GpuRegister rt,
662 uint32_t imm16_21) {
663 switch (cond) {
664 case kCondLT:
665 Bltc(rs, rt, imm16_21);
666 break;
667 case kCondGE:
668 Bgec(rs, rt, imm16_21);
669 break;
670 case kCondLE:
671 Bgec(rt, rs, imm16_21);
672 break;
673 case kCondGT:
674 Bltc(rt, rs, imm16_21);
675 break;
676 case kCondLTZ:
677 CHECK_EQ(rt, ZERO);
678 Bltzc(rs, imm16_21);
679 break;
680 case kCondGEZ:
681 CHECK_EQ(rt, ZERO);
682 Bgezc(rs, imm16_21);
683 break;
684 case kCondLEZ:
685 CHECK_EQ(rt, ZERO);
686 Blezc(rs, imm16_21);
687 break;
688 case kCondGTZ:
689 CHECK_EQ(rt, ZERO);
690 Bgtzc(rs, imm16_21);
691 break;
692 case kCondEQ:
693 Beqc(rs, rt, imm16_21);
694 break;
695 case kCondNE:
696 Bnec(rs, rt, imm16_21);
697 break;
698 case kCondEQZ:
699 CHECK_EQ(rt, ZERO);
700 Beqzc(rs, imm16_21);
701 break;
702 case kCondNEZ:
703 CHECK_EQ(rt, ZERO);
704 Bnezc(rs, imm16_21);
705 break;
706 case kCondLTU:
707 Bltuc(rs, rt, imm16_21);
708 break;
709 case kCondGEU:
710 Bgeuc(rs, rt, imm16_21);
711 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800712 case kCondF:
713 CHECK_EQ(rt, ZERO);
714 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
715 break;
716 case kCondT:
717 CHECK_EQ(rt, ZERO);
718 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
719 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700720 case kUncond:
721 LOG(FATAL) << "Unexpected branch condition " << cond;
722 UNREACHABLE();
723 }
724}
725
Andreas Gampe57b34292015-01-14 15:45:59 -0800726void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
727 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
728}
729
730void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
731 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
732}
733
734void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
735 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
736}
737
738void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
739 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
740}
741
742void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700743 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800744}
745
746void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700747 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800748}
749
750void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700751 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800752}
753
754void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700755 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800756}
757
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700758void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
759 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
760}
761
762void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
763 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
764}
765
766void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
767 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
768}
769
770void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
771 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
772}
773
Andreas Gampe57b34292015-01-14 15:45:59 -0800774void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
775 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
776}
777
778void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700779 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
780}
781
782void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
783 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
784}
785
786void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
787 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
788}
789
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700790void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
791 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
792}
793
794void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
795 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
796}
797
798void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
799 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
800}
801
802void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
803 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
804}
805
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800806void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
807 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
808}
809
810void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
811 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
812}
813
814void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
815 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
816}
817
818void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
819 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
820}
821
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700822void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
823 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
824}
825
826void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
827 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
828}
829
830void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
831 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
832}
833
834void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
835 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
836}
837
838void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
839 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
840}
841
842void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
843 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
844}
845
846void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
847 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
848}
849
850void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
851 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
852}
853
854void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
855 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
856}
857
858void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
859 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
860}
861
862void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
863 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
864}
865
866void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
867 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
868}
869
870void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
871 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
872}
873
874void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
875 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
876}
877
878void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
879 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
880}
881
882void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
883 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
884}
885
886void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
887 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
888}
889
890void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
891 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
892}
893
Alexey Frunze299a9392015-12-08 16:08:02 -0800894void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
895 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
896}
897
898void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
899 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
900}
901
902void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
903 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
904}
905
906void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
907 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
908}
909
910void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
911 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
912}
913
914void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
915 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
916}
917
918void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
919 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
920}
921
922void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
923 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
924}
925
926void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
927 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
928}
929
930void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
931 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
932}
933
934void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
935 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
936}
937
938void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
939 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
940}
941
942void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
943 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
944}
945
946void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
947 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
948}
949
950void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
951 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
952}
953
954void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
955 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
956}
957
958void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
959 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
960}
961
962void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
963 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
964}
965
966void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
967 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
968}
969
970void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
971 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
972}
973
Alexey Frunze4dda3372015-06-01 18:31:49 -0700974void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
975 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
976}
977
978void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
979 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
980}
981
982void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
983 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
984}
985
986void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
987 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800988}
989
Chris Larsen51417632015-10-02 13:24:25 -0700990void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
991 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
992}
993
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700994void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
995 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
996}
997
Andreas Gampe57b34292015-01-14 15:45:59 -0800998void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
999 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1000}
1001
Lazar Trsicd9672662015-09-03 17:33:01 +02001002void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1003 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1004}
1005
Alexey Frunze4dda3372015-06-01 18:31:49 -07001006void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1007 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1008}
1009
Lazar Trsicd9672662015-09-03 17:33:01 +02001010void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1011 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1012}
1013
Alexey Frunze4dda3372015-06-01 18:31:49 -07001014void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1015 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1016}
1017
1018void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1019 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001020}
1021
1022void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1023 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1024}
1025
1026void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1027 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1028}
1029
1030void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1031 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1032}
1033
1034void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1035 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1036}
1037
1038void Mips64Assembler::Break() {
1039 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1040 static_cast<GpuRegister>(0), 0, 0xD);
1041}
1042
1043void Mips64Assembler::Nop() {
1044 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1045 static_cast<GpuRegister>(0), 0, 0x0);
1046}
1047
Alexey Frunze4dda3372015-06-01 18:31:49 -07001048void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1049 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001050}
1051
Alexey Frunze4dda3372015-06-01 18:31:49 -07001052void Mips64Assembler::Clear(GpuRegister rd) {
1053 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001054}
1055
Alexey Frunze4dda3372015-06-01 18:31:49 -07001056void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1057 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001058}
1059
Alexey Frunze4dda3372015-06-01 18:31:49 -07001060void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001061 TemplateLoadConst32(this, rd, value);
1062}
1063
1064// This function is only used for testing purposes.
1065void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001066}
1067
Alexey Frunze4dda3372015-06-01 18:31:49 -07001068void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001069 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001070}
1071
Alexey Frunze4dda3372015-06-01 18:31:49 -07001072void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1073 if (IsInt<16>(value)) {
1074 Daddiu(rt, rs, value);
1075 } else {
1076 LoadConst64(rtmp, value);
1077 Daddu(rt, rs, rtmp);
1078 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001079}
1080
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001081void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1082 Mips64Assembler::Branch::Type short_type,
1083 Mips64Assembler::Branch::Type long_type) {
1084 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1085}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001086
Alexey Frunze19f6c692016-11-30 19:19:55 -08001087void Mips64Assembler::Branch::InitializeType(Type initial_type) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001088 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001089 switch (initial_type) {
1090 case kLabel:
1091 case kLiteral:
1092 case kLiteralUnsigned:
1093 case kLiteralLong:
1094 CHECK(!IsResolved());
1095 type_ = initial_type;
1096 break;
1097 case kCall:
1098 InitShortOrLong(offset_size, kCall, kLongCall);
1099 break;
1100 case kCondBranch:
1101 switch (condition_) {
1102 case kUncond:
1103 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1104 break;
1105 case kCondEQZ:
1106 case kCondNEZ:
1107 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1108 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1109 break;
1110 default:
1111 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1112 break;
1113 }
1114 break;
1115 default:
1116 LOG(FATAL) << "Unexpected branch type " << initial_type;
1117 UNREACHABLE();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001118 }
1119 old_type_ = type_;
1120}
1121
1122bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1123 switch (condition) {
1124 case kCondLT:
1125 case kCondGT:
1126 case kCondNE:
1127 case kCondLTU:
1128 return lhs == rhs;
1129 default:
1130 return false;
1131 }
1132}
1133
1134bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1135 GpuRegister lhs,
1136 GpuRegister rhs) {
1137 switch (condition) {
1138 case kUncond:
1139 return true;
1140 case kCondGE:
1141 case kCondLE:
1142 case kCondEQ:
1143 case kCondGEU:
1144 return lhs == rhs;
1145 default:
1146 return false;
1147 }
1148}
1149
Alexey Frunze19f6c692016-11-30 19:19:55 -08001150Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001151 : old_location_(location),
1152 location_(location),
1153 target_(target),
1154 lhs_reg_(ZERO),
1155 rhs_reg_(ZERO),
1156 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001157 InitializeType(is_call ? kCall : kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001158}
1159
1160Mips64Assembler::Branch::Branch(uint32_t location,
1161 uint32_t target,
1162 Mips64Assembler::BranchCondition condition,
1163 GpuRegister lhs_reg,
1164 GpuRegister rhs_reg)
1165 : old_location_(location),
1166 location_(location),
1167 target_(target),
1168 lhs_reg_(lhs_reg),
1169 rhs_reg_(rhs_reg),
1170 condition_(condition) {
1171 CHECK_NE(condition, kUncond);
1172 switch (condition) {
1173 case kCondEQ:
1174 case kCondNE:
1175 case kCondLT:
1176 case kCondGE:
1177 case kCondLE:
1178 case kCondGT:
1179 case kCondLTU:
1180 case kCondGEU:
1181 CHECK_NE(lhs_reg, ZERO);
1182 CHECK_NE(rhs_reg, ZERO);
1183 break;
1184 case kCondLTZ:
1185 case kCondGEZ:
1186 case kCondLEZ:
1187 case kCondGTZ:
1188 case kCondEQZ:
1189 case kCondNEZ:
1190 CHECK_NE(lhs_reg, ZERO);
1191 CHECK_EQ(rhs_reg, ZERO);
1192 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001193 case kCondF:
1194 case kCondT:
1195 CHECK_EQ(rhs_reg, ZERO);
1196 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001197 case kUncond:
1198 UNREACHABLE();
1199 }
1200 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1201 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1202 // Branch condition is always true, make the branch unconditional.
1203 condition_ = kUncond;
1204 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001205 InitializeType(kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001206}
1207
Alexey Frunze19f6c692016-11-30 19:19:55 -08001208Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001209 : old_location_(location),
1210 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08001211 target_(kUnresolved),
1212 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001213 rhs_reg_(ZERO),
1214 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001215 CHECK_NE(dest_reg, ZERO);
1216 InitializeType(label_or_literal_type);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001217}
1218
1219Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1220 Mips64Assembler::BranchCondition cond) {
1221 switch (cond) {
1222 case kCondLT:
1223 return kCondGE;
1224 case kCondGE:
1225 return kCondLT;
1226 case kCondLE:
1227 return kCondGT;
1228 case kCondGT:
1229 return kCondLE;
1230 case kCondLTZ:
1231 return kCondGEZ;
1232 case kCondGEZ:
1233 return kCondLTZ;
1234 case kCondLEZ:
1235 return kCondGTZ;
1236 case kCondGTZ:
1237 return kCondLEZ;
1238 case kCondEQ:
1239 return kCondNE;
1240 case kCondNE:
1241 return kCondEQ;
1242 case kCondEQZ:
1243 return kCondNEZ;
1244 case kCondNEZ:
1245 return kCondEQZ;
1246 case kCondLTU:
1247 return kCondGEU;
1248 case kCondGEU:
1249 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001250 case kCondF:
1251 return kCondT;
1252 case kCondT:
1253 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001254 case kUncond:
1255 LOG(FATAL) << "Unexpected branch condition " << cond;
1256 }
1257 UNREACHABLE();
1258}
1259
1260Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1261 return type_;
1262}
1263
1264Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1265 return condition_;
1266}
1267
1268GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1269 return lhs_reg_;
1270}
1271
1272GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1273 return rhs_reg_;
1274}
1275
1276uint32_t Mips64Assembler::Branch::GetTarget() const {
1277 return target_;
1278}
1279
1280uint32_t Mips64Assembler::Branch::GetLocation() const {
1281 return location_;
1282}
1283
1284uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1285 return old_location_;
1286}
1287
1288uint32_t Mips64Assembler::Branch::GetLength() const {
1289 return branch_info_[type_].length;
1290}
1291
1292uint32_t Mips64Assembler::Branch::GetOldLength() const {
1293 return branch_info_[old_type_].length;
1294}
1295
1296uint32_t Mips64Assembler::Branch::GetSize() const {
1297 return GetLength() * sizeof(uint32_t);
1298}
1299
1300uint32_t Mips64Assembler::Branch::GetOldSize() const {
1301 return GetOldLength() * sizeof(uint32_t);
1302}
1303
1304uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1305 return GetLocation() + GetSize();
1306}
1307
1308uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1309 return GetOldLocation() + GetOldSize();
1310}
1311
1312bool Mips64Assembler::Branch::IsLong() const {
1313 switch (type_) {
1314 // Short branches.
1315 case kUncondBranch:
1316 case kCondBranch:
1317 case kCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001318 // Near label.
1319 case kLabel:
1320 // Near literals.
1321 case kLiteral:
1322 case kLiteralUnsigned:
1323 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001324 return false;
1325 // Long branches.
1326 case kLongUncondBranch:
1327 case kLongCondBranch:
1328 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001329 // Far label.
1330 case kFarLabel:
1331 // Far literals.
1332 case kFarLiteral:
1333 case kFarLiteralUnsigned:
1334 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001335 return true;
1336 }
1337 UNREACHABLE();
1338}
1339
1340bool Mips64Assembler::Branch::IsResolved() const {
1341 return target_ != kUnresolved;
1342}
1343
1344Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1345 OffsetBits offset_size =
1346 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1347 ? kOffset23
1348 : branch_info_[type_].offset_size;
1349 return offset_size;
1350}
1351
1352Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1353 uint32_t target) {
1354 // For unresolved targets assume the shortest encoding
1355 // (later it will be made longer if needed).
1356 if (target == kUnresolved)
1357 return kOffset16;
1358 int64_t distance = static_cast<int64_t>(target) - location;
1359 // To simplify calculations in composite branches consisting of multiple instructions
1360 // bump up the distance by a value larger than the max byte size of a composite branch.
1361 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1362 if (IsInt<kOffset16>(distance))
1363 return kOffset16;
1364 else if (IsInt<kOffset18>(distance))
1365 return kOffset18;
1366 else if (IsInt<kOffset21>(distance))
1367 return kOffset21;
1368 else if (IsInt<kOffset23>(distance))
1369 return kOffset23;
1370 else if (IsInt<kOffset28>(distance))
1371 return kOffset28;
1372 return kOffset32;
1373}
1374
1375void Mips64Assembler::Branch::Resolve(uint32_t target) {
1376 target_ = target;
1377}
1378
1379void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1380 if (location_ > expand_location) {
1381 location_ += delta;
1382 }
1383 if (!IsResolved()) {
1384 return; // Don't know the target yet.
1385 }
1386 if (target_ > expand_location) {
1387 target_ += delta;
1388 }
1389}
1390
1391void Mips64Assembler::Branch::PromoteToLong() {
1392 switch (type_) {
1393 // Short branches.
1394 case kUncondBranch:
1395 type_ = kLongUncondBranch;
1396 break;
1397 case kCondBranch:
1398 type_ = kLongCondBranch;
1399 break;
1400 case kCall:
1401 type_ = kLongCall;
1402 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001403 // Near label.
1404 case kLabel:
1405 type_ = kFarLabel;
1406 break;
1407 // Near literals.
1408 case kLiteral:
1409 type_ = kFarLiteral;
1410 break;
1411 case kLiteralUnsigned:
1412 type_ = kFarLiteralUnsigned;
1413 break;
1414 case kLiteralLong:
1415 type_ = kFarLiteralLong;
1416 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001417 default:
1418 // Note: 'type_' is already long.
1419 break;
1420 }
1421 CHECK(IsLong());
1422}
1423
1424uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1425 // If the branch is still unresolved or already long, nothing to do.
1426 if (IsLong() || !IsResolved()) {
1427 return 0;
1428 }
1429 // Promote the short branch to long if the offset size is too small
1430 // to hold the distance between location_ and target_.
1431 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1432 PromoteToLong();
1433 uint32_t old_size = GetOldSize();
1434 uint32_t new_size = GetSize();
1435 CHECK_GT(new_size, old_size);
1436 return new_size - old_size;
1437 }
1438 // The following logic is for debugging/testing purposes.
1439 // Promote some short branches to long when it's not really required.
1440 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1441 int64_t distance = static_cast<int64_t>(target_) - location_;
1442 distance = (distance >= 0) ? distance : -distance;
1443 if (distance >= max_short_distance) {
1444 PromoteToLong();
1445 uint32_t old_size = GetOldSize();
1446 uint32_t new_size = GetSize();
1447 CHECK_GT(new_size, old_size);
1448 return new_size - old_size;
1449 }
1450 }
1451 return 0;
1452}
1453
1454uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1455 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1456}
1457
1458uint32_t Mips64Assembler::Branch::GetOffset() const {
1459 CHECK(IsResolved());
1460 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1461 // Calculate the byte distance between instructions and also account for
1462 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001463 uint32_t offset_location = GetOffsetLocation();
1464 if (type_ == kLiteralLong) {
1465 // Special case for the ldpc instruction, whose address (PC) is rounded down to
1466 // a multiple of 8 before adding the offset.
1467 // Note, branch promotion has already taken care of aligning `target_` to an
1468 // address that's a multiple of 8.
1469 offset_location = RoundDown(offset_location, sizeof(uint64_t));
1470 }
1471 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001472 // Prepare the offset for encoding into the instruction(s).
1473 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1474 return offset;
1475}
1476
1477Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1478 CHECK_LT(branch_id, branches_.size());
1479 return &branches_[branch_id];
1480}
1481
1482const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1483 CHECK_LT(branch_id, branches_.size());
1484 return &branches_[branch_id];
1485}
1486
1487void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001488 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001489 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001490
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001491 // Walk the list of branches referring to and preceding this label.
1492 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001493 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001494 uint32_t branch_id = label->Position();
1495 Branch* branch = GetBranch(branch_id);
1496 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001497
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001498 uint32_t branch_location = branch->GetLocation();
1499 // Extract the location of the previous branch in the list (walking the list backwards;
1500 // the previous branch ID was stored in the space reserved for this branch).
1501 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001502
1503 // On to the previous branch in the list...
1504 label->position_ = prev;
1505 }
1506
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001507 // Now make the label object contain its own location (relative to the end of the preceding
1508 // branch, if any; it will be used by the branches referring to and following this label).
1509 label->prev_branch_id_plus_one_ = branches_.size();
1510 if (label->prev_branch_id_plus_one_) {
1511 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1512 const Branch* branch = GetBranch(branch_id);
1513 bound_pc -= branch->GetEndLocation();
1514 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001515 label->BindTo(bound_pc);
1516}
1517
Alexey Frunze19f6c692016-11-30 19:19:55 -08001518uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001519 CHECK(label->IsBound());
1520 uint32_t target = label->Position();
1521 if (label->prev_branch_id_plus_one_) {
1522 // Get label location based on the branch preceding it.
1523 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1524 const Branch* branch = GetBranch(branch_id);
1525 target += branch->GetEndLocation();
1526 }
1527 return target;
1528}
1529
1530uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1531 // We can reconstruct the adjustment by going through all the branches from the beginning
1532 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1533 // with increasing old_position, we can use the data from last AdjustedPosition() to
1534 // continue where we left off and the whole loop should be O(m+n) where m is the number
1535 // of positions to adjust and n is the number of branches.
1536 if (old_position < last_old_position_) {
1537 last_position_adjustment_ = 0;
1538 last_old_position_ = 0;
1539 last_branch_id_ = 0;
1540 }
1541 while (last_branch_id_ != branches_.size()) {
1542 const Branch* branch = GetBranch(last_branch_id_);
1543 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1544 break;
1545 }
1546 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1547 ++last_branch_id_;
1548 }
1549 last_old_position_ = old_position;
1550 return old_position + last_position_adjustment_;
1551}
1552
1553void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1554 uint32_t length = branches_.back().GetLength();
1555 if (!label->IsBound()) {
1556 // Branch forward (to a following label), distance is unknown.
1557 // The first branch forward will contain 0, serving as the terminator of
1558 // the list of forward-reaching branches.
1559 Emit(label->position_);
1560 length--;
1561 // Now make the label object point to this branch
1562 // (this forms a linked list of branches preceding this label).
1563 uint32_t branch_id = branches_.size() - 1;
1564 label->LinkTo(branch_id);
1565 }
1566 // Reserve space for the branch.
1567 while (length--) {
1568 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001569 }
1570}
1571
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001572void Mips64Assembler::Buncond(Mips64Label* label) {
1573 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001574 branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001575 FinalizeLabeledBranch(label);
1576}
1577
1578void Mips64Assembler::Bcond(Mips64Label* label,
1579 BranchCondition condition,
1580 GpuRegister lhs,
1581 GpuRegister rhs) {
1582 // If lhs = rhs, this can be a NOP.
1583 if (Branch::IsNop(condition, lhs, rhs)) {
1584 return;
1585 }
1586 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1587 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1588 FinalizeLabeledBranch(label);
1589}
1590
Alexey Frunze19f6c692016-11-30 19:19:55 -08001591void Mips64Assembler::Call(Mips64Label* label) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001592 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001593 branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001594 FinalizeLabeledBranch(label);
1595}
1596
Alexey Frunze19f6c692016-11-30 19:19:55 -08001597void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
1598 // Label address loads are treated as pseudo branches since they require very similar handling.
1599 DCHECK(!label->IsBound());
1600 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
1601 FinalizeLabeledBranch(label);
1602}
1603
1604Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
1605 // We don't support byte and half-word literals.
1606 if (size == 4u) {
1607 literals_.emplace_back(size, data);
1608 return &literals_.back();
1609 } else {
1610 DCHECK_EQ(size, 8u);
1611 long_literals_.emplace_back(size, data);
1612 return &long_literals_.back();
1613 }
1614}
1615
1616void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
1617 LoadOperandType load_type,
1618 Literal* literal) {
1619 // Literal loads are treated as pseudo branches since they require very similar handling.
1620 Branch::Type literal_type;
1621 switch (load_type) {
1622 case kLoadWord:
1623 DCHECK_EQ(literal->GetSize(), 4u);
1624 literal_type = Branch::kLiteral;
1625 break;
1626 case kLoadUnsignedWord:
1627 DCHECK_EQ(literal->GetSize(), 4u);
1628 literal_type = Branch::kLiteralUnsigned;
1629 break;
1630 case kLoadDoubleword:
1631 DCHECK_EQ(literal->GetSize(), 8u);
1632 literal_type = Branch::kLiteralLong;
1633 break;
1634 default:
1635 LOG(FATAL) << "Unexpected literal load type " << load_type;
1636 UNREACHABLE();
1637 }
1638 Mips64Label* label = literal->GetLabel();
1639 DCHECK(!label->IsBound());
1640 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
1641 FinalizeLabeledBranch(label);
1642}
1643
1644void Mips64Assembler::EmitLiterals() {
1645 if (!literals_.empty()) {
1646 for (Literal& literal : literals_) {
1647 Mips64Label* label = literal.GetLabel();
1648 Bind(label);
1649 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1650 DCHECK_EQ(literal.GetSize(), 4u);
1651 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1652 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1653 }
1654 }
1655 }
1656 if (!long_literals_.empty()) {
1657 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
1658 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
1659 Emit(0); // NOP.
1660 for (Literal& literal : long_literals_) {
1661 Mips64Label* label = literal.GetLabel();
1662 Bind(label);
1663 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1664 DCHECK_EQ(literal.GetSize(), 8u);
1665 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1666 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1667 }
1668 }
1669 }
1670}
1671
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001672void Mips64Assembler::PromoteBranches() {
1673 // Promote short branches to long as necessary.
1674 bool changed;
1675 do {
1676 changed = false;
1677 for (auto& branch : branches_) {
1678 CHECK(branch.IsResolved());
1679 uint32_t delta = branch.PromoteIfNeeded();
1680 // If this branch has been promoted and needs to expand in size,
1681 // relocate all branches by the expansion size.
1682 if (delta) {
1683 changed = true;
1684 uint32_t expand_location = branch.GetLocation();
1685 for (auto& branch2 : branches_) {
1686 branch2.Relocate(expand_location, delta);
1687 }
1688 }
1689 }
1690 } while (changed);
1691
1692 // Account for branch expansion by resizing the code buffer
1693 // and moving the code in it to its final location.
1694 size_t branch_count = branches_.size();
1695 if (branch_count > 0) {
1696 // Resize.
1697 Branch& last_branch = branches_[branch_count - 1];
1698 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1699 uint32_t old_size = buffer_.Size();
1700 buffer_.Resize(old_size + size_delta);
1701 // Move the code residing between branch placeholders.
1702 uint32_t end = old_size;
1703 for (size_t i = branch_count; i > 0; ) {
1704 Branch& branch = branches_[--i];
1705 uint32_t size = end - branch.GetOldEndLocation();
1706 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1707 end = branch.GetOldLocation();
1708 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001709 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001710
1711 // Align 64-bit literals by moving them down by 4 bytes if needed.
1712 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
1713 if (!long_literals_.empty()) {
1714 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
1715 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
1716 size_t buf_size = buffer_.Size();
1717 // 64-bit literals must be at the very end of the buffer.
1718 CHECK_EQ(first_literal_location + lit_size, buf_size);
1719 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
1720 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
1721 // The 4 reserved bytes proved useless, reduce the buffer size.
1722 buffer_.Resize(buf_size - sizeof(uint32_t));
1723 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
1724 // offsets from PC to be generated.
1725 for (auto& branch : branches_) {
1726 uint32_t target = branch.GetTarget();
1727 if (target >= first_literal_location) {
1728 branch.Resolve(target - sizeof(uint32_t));
1729 }
1730 }
1731 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
1732 // we need to adjust the location of the literal's label as well.
1733 for (Literal& literal : long_literals_) {
1734 // Bound label's position is negative, hence incrementing it instead of decrementing.
1735 literal.GetLabel()->position_ += sizeof(uint32_t);
1736 }
1737 }
1738 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001739}
1740
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001741// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1742const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1743 // Short branches.
1744 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1745 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1746 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08001747 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
1748 // Near label.
1749 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
1750 // Near literals.
1751 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
1752 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
1753 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001754 // Long branches.
1755 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1756 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08001757 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1758 // Far label.
1759 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
1760 // Far literals.
1761 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
1762 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
1763 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001764};
1765
1766// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1767void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1768 CHECK(overwriting_);
1769 overwrite_location_ = branch->GetLocation();
1770 uint32_t offset = branch->GetOffset();
1771 BranchCondition condition = branch->GetCondition();
1772 GpuRegister lhs = branch->GetLeftRegister();
1773 GpuRegister rhs = branch->GetRightRegister();
1774 switch (branch->GetType()) {
1775 // Short branches.
1776 case Branch::kUncondBranch:
1777 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1778 Bc(offset);
1779 break;
1780 case Branch::kCondBranch:
1781 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1782 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001783 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001784 break;
1785 case Branch::kCall:
1786 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001787 Balc(offset);
1788 break;
1789
1790 // Near label.
1791 case Branch::kLabel:
1792 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001793 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001794 break;
1795 // Near literals.
1796 case Branch::kLiteral:
1797 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1798 Lwpc(lhs, offset);
1799 break;
1800 case Branch::kLiteralUnsigned:
1801 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1802 Lwupc(lhs, offset);
1803 break;
1804 case Branch::kLiteralLong:
1805 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1806 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001807 break;
1808
1809 // Long branches.
1810 case Branch::kLongUncondBranch:
1811 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1812 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1813 Auipc(AT, High16Bits(offset));
1814 Jic(AT, Low16Bits(offset));
1815 break;
1816 case Branch::kLongCondBranch:
1817 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1818 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1819 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1820 Auipc(AT, High16Bits(offset));
1821 Jic(AT, Low16Bits(offset));
1822 break;
1823 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001824 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001825 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001826 Auipc(AT, High16Bits(offset));
1827 Jialc(AT, Low16Bits(offset));
1828 break;
1829
1830 // Far label.
1831 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08001832 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001833 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1834 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08001835 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08001836 break;
1837 // Far literals.
1838 case Branch::kFarLiteral:
1839 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
1840 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1841 Auipc(AT, High16Bits(offset));
1842 Lw(lhs, AT, Low16Bits(offset));
1843 break;
1844 case Branch::kFarLiteralUnsigned:
1845 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
1846 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1847 Auipc(AT, High16Bits(offset));
1848 Lwu(lhs, AT, Low16Bits(offset));
1849 break;
1850 case Branch::kFarLiteralLong:
1851 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
1852 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1853 Auipc(AT, High16Bits(offset));
1854 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001855 break;
1856 }
1857 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1858 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001859}
1860
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001861void Mips64Assembler::Bc(Mips64Label* label) {
1862 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001863}
1864
Alexey Frunze19f6c692016-11-30 19:19:55 -08001865void Mips64Assembler::Balc(Mips64Label* label) {
1866 Call(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001867}
1868
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001869void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1870 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001871}
1872
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001873void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1874 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001875}
1876
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001877void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1878 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001879}
1880
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001881void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1882 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001883}
1884
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001885void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1886 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001887}
1888
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001889void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1890 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001891}
1892
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001893void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1894 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001895}
1896
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001897void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1898 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001899}
1900
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001901void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1902 Bcond(label, kCondEQ, rs, rt);
1903}
1904
1905void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1906 Bcond(label, kCondNE, rs, rt);
1907}
1908
1909void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
1910 Bcond(label, kCondEQZ, rs);
1911}
1912
1913void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
1914 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08001915}
1916
Alexey Frunze299a9392015-12-08 16:08:02 -08001917void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
1918 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
1919}
1920
1921void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
1922 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
1923}
1924
Andreas Gampe57b34292015-01-14 15:45:59 -08001925void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
1926 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001927 if (!IsInt<16>(offset) ||
1928 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1929 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1930 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001931 Daddu(AT, AT, base);
1932 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001933 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001934 }
1935
Andreas Gampe57b34292015-01-14 15:45:59 -08001936 switch (type) {
1937 case kLoadSignedByte:
1938 Lb(reg, base, offset);
1939 break;
1940 case kLoadUnsignedByte:
1941 Lbu(reg, base, offset);
1942 break;
1943 case kLoadSignedHalfword:
1944 Lh(reg, base, offset);
1945 break;
1946 case kLoadUnsignedHalfword:
1947 Lhu(reg, base, offset);
1948 break;
1949 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001950 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001951 Lw(reg, base, offset);
1952 break;
Douglas Leungd90957f2015-04-30 19:22:49 -07001953 case kLoadUnsignedWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001954 CHECK_ALIGNED(offset, kMips64WordSize);
Douglas Leungd90957f2015-04-30 19:22:49 -07001955 Lwu(reg, base, offset);
1956 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001957 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001958 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1959 CHECK_ALIGNED(offset, kMips64WordSize);
1960 Lwu(reg, base, offset);
1961 Lwu(TMP2, base, offset + kMips64WordSize);
1962 Dinsu(reg, TMP2, 32, 32);
1963 } else {
1964 Ld(reg, base, offset);
1965 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001966 break;
Andreas Gampe57b34292015-01-14 15:45:59 -08001967 }
1968}
1969
1970void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
1971 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02001972 if (!IsInt<16>(offset) ||
1973 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
1974 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
1975 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001976 Daddu(AT, AT, base);
1977 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02001978 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001979 }
1980
Andreas Gampe57b34292015-01-14 15:45:59 -08001981 switch (type) {
1982 case kLoadWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02001983 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08001984 Lwc1(reg, base, offset);
1985 break;
1986 case kLoadDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02001987 if (!IsAligned<kMips64DoublewordSize>(offset)) {
1988 CHECK_ALIGNED(offset, kMips64WordSize);
1989 Lwc1(reg, base, offset);
1990 Lw(TMP2, base, offset + kMips64WordSize);
1991 Mthc1(TMP2, reg);
1992 } else {
1993 Ldc1(reg, base, offset);
1994 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001995 break;
1996 default:
1997 LOG(FATAL) << "UNREACHABLE";
1998 }
1999}
2000
2001void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
2002 size_t size) {
2003 Mips64ManagedRegister dst = m_dst.AsMips64();
2004 if (dst.IsNoRegister()) {
2005 CHECK_EQ(0u, size) << dst;
2006 } else if (dst.IsGpuRegister()) {
2007 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002008 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
2009 } else if (size == 8) {
2010 CHECK_EQ(8u, size) << dst;
2011 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
2012 } else {
2013 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2014 }
2015 } else if (dst.IsFpuRegister()) {
2016 if (size == 4) {
2017 CHECK_EQ(4u, size) << dst;
2018 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
2019 } else if (size == 8) {
2020 CHECK_EQ(8u, size) << dst;
2021 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
2022 } else {
2023 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2024 }
2025 }
2026}
2027
2028void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
2029 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002030 if (!IsInt<16>(offset) ||
2031 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2032 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2033 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002034 Daddu(AT, AT, base);
2035 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002036 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002037 }
2038
Andreas Gampe57b34292015-01-14 15:45:59 -08002039 switch (type) {
2040 case kStoreByte:
2041 Sb(reg, base, offset);
2042 break;
2043 case kStoreHalfword:
2044 Sh(reg, base, offset);
2045 break;
2046 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002047 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002048 Sw(reg, base, offset);
2049 break;
2050 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002051 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2052 CHECK_ALIGNED(offset, kMips64WordSize);
2053 Sw(reg, base, offset);
2054 Dsrl32(TMP2, reg, 0);
2055 Sw(TMP2, base, offset + kMips64WordSize);
2056 } else {
2057 Sd(reg, base, offset);
2058 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002059 break;
2060 default:
2061 LOG(FATAL) << "UNREACHABLE";
2062 }
2063}
2064
2065void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
2066 int32_t offset) {
Lazar Trsicd9672662015-09-03 17:33:01 +02002067 if (!IsInt<16>(offset) ||
2068 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
2069 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2070 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002071 Daddu(AT, AT, base);
2072 base = AT;
Lazar Trsicd9672662015-09-03 17:33:01 +02002073 offset &= (kMips64DoublewordSize - 1);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002074 }
2075
Andreas Gampe57b34292015-01-14 15:45:59 -08002076 switch (type) {
2077 case kStoreWord:
Lazar Trsicd9672662015-09-03 17:33:01 +02002078 CHECK_ALIGNED(offset, kMips64WordSize);
Andreas Gampe57b34292015-01-14 15:45:59 -08002079 Swc1(reg, base, offset);
2080 break;
2081 case kStoreDoubleword:
Lazar Trsicd9672662015-09-03 17:33:01 +02002082 if (!IsAligned<kMips64DoublewordSize>(offset)) {
2083 CHECK_ALIGNED(offset, kMips64WordSize);
2084 Mfhc1(TMP2, reg);
2085 Swc1(reg, base, offset);
2086 Sw(TMP2, base, offset + kMips64WordSize);
2087 } else {
2088 Sdc1(reg, base, offset);
2089 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002090 break;
2091 default:
2092 LOG(FATAL) << "UNREACHABLE";
2093 }
2094}
2095
David Srbeckydd973932015-04-07 20:29:48 +01002096static dwarf::Reg DWARFReg(GpuRegister reg) {
2097 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
2098}
2099
Andreas Gampe57b34292015-01-14 15:45:59 -08002100constexpr size_t kFramePointerSize = 8;
2101
Vladimir Marko32248382016-05-19 10:37:24 +01002102void Mips64Assembler::BuildFrame(size_t frame_size,
2103 ManagedRegister method_reg,
2104 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002105 const ManagedRegisterEntrySpills& entry_spills) {
2106 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002107 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002108
2109 // Increase frame to required size.
2110 IncreaseFrameSize(frame_size);
2111
2112 // Push callee saves and return address
2113 int stack_offset = frame_size - kFramePointerSize;
2114 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002115 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002116 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2117 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002118 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002119 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002120 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002121 }
2122
2123 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002124 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002125
2126 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002127 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002128 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002129 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002130 ManagedRegisterSpill spill = entry_spills.at(i);
2131 int32_t size = spill.getSize();
2132 if (reg.IsNoRegister()) {
2133 // only increment stack offset.
2134 offset += size;
2135 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002136 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2137 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002138 offset += size;
2139 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002140 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2141 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002142 offset += size;
2143 }
2144 }
2145}
2146
2147void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002148 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002149 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002150 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002151 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002152
2153 // Pop callee saves and return address
2154 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2155 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002156 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002157 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002158 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002159 stack_offset += kFramePointerSize;
2160 }
2161 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002162 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002163
2164 // Decrease frame to required size.
2165 DecreaseFrameSize(frame_size);
2166
2167 // Then jump to the return address.
2168 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002169 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002170
2171 // The CFI should be restored for any code that follows the exit block.
2172 cfi_.RestoreState();
2173 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002174}
2175
2176void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002177 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002178 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002179 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002180 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002181}
2182
2183void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002184 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002185 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002186 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002187 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002188}
2189
2190void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2191 Mips64ManagedRegister src = msrc.AsMips64();
2192 if (src.IsNoRegister()) {
2193 CHECK_EQ(0u, size);
2194 } else if (src.IsGpuRegister()) {
2195 CHECK(size == 4 || size == 8) << size;
2196 if (size == 8) {
2197 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2198 } else if (size == 4) {
2199 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2200 } else {
2201 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2202 }
2203 } else if (src.IsFpuRegister()) {
2204 CHECK(size == 4 || size == 8) << size;
2205 if (size == 8) {
2206 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2207 } else if (size == 4) {
2208 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2209 } else {
2210 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2211 }
2212 }
2213}
2214
2215void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2216 Mips64ManagedRegister src = msrc.AsMips64();
2217 CHECK(src.IsGpuRegister());
2218 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2219}
2220
2221void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2222 Mips64ManagedRegister src = msrc.AsMips64();
2223 CHECK(src.IsGpuRegister());
2224 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2225}
2226
2227void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2228 ManagedRegister mscratch) {
2229 Mips64ManagedRegister scratch = mscratch.AsMips64();
2230 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002231 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002232 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2233}
2234
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002235void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2236 FrameOffset fr_offs,
2237 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002238 Mips64ManagedRegister scratch = mscratch.AsMips64();
2239 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002240 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002241 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2242}
2243
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002244void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002245 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2246}
2247
2248void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2249 FrameOffset in_off, ManagedRegister mscratch) {
2250 Mips64ManagedRegister src = msrc.AsMips64();
2251 Mips64ManagedRegister scratch = mscratch.AsMips64();
2252 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2253 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2254 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2255}
2256
2257void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2258 return EmitLoad(mdest, SP, src.Int32Value(), size);
2259}
2260
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002261void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002262 return EmitLoad(mdest, S1, src.Int32Value(), size);
2263}
2264
2265void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2266 Mips64ManagedRegister dest = mdest.AsMips64();
2267 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002268 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002269}
2270
Mathieu Chartiere401d142015-04-22 13:56:20 -07002271void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002272 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002273 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002274 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2275 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002276 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01002277 if (kPoisonHeapReferences && unpoison_reference) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002278 // TODO: review
2279 // Negate the 32-bit ref
2280 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
2281 // 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 +02002282 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
Andreas Gampe57b34292015-01-14 15:45:59 -08002283 }
2284}
2285
2286void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002287 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002288 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002289 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002290 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2291 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2292}
2293
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002294void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002295 Mips64ManagedRegister dest = mdest.AsMips64();
2296 CHECK(dest.IsGpuRegister());
2297 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2298}
2299
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002300void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2301 size_t size ATTRIBUTE_UNUSED) {
2302 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002303}
2304
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002305void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2306 size_t size ATTRIBUTE_UNUSED) {
2307 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002308}
2309
2310void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2311 Mips64ManagedRegister dest = mdest.AsMips64();
2312 Mips64ManagedRegister src = msrc.AsMips64();
2313 if (!dest.Equals(src)) {
2314 if (dest.IsGpuRegister()) {
2315 CHECK(src.IsGpuRegister()) << src;
2316 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2317 } else if (dest.IsFpuRegister()) {
2318 CHECK(src.IsFpuRegister()) << src;
2319 if (size == 4) {
2320 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2321 } else if (size == 8) {
2322 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2323 } else {
2324 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2325 }
2326 }
2327 }
2328}
2329
2330void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2331 ManagedRegister mscratch) {
2332 Mips64ManagedRegister scratch = mscratch.AsMips64();
2333 CHECK(scratch.IsGpuRegister()) << scratch;
2334 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2335 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2336}
2337
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002338void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2339 ThreadOffset64 thr_offs,
2340 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002341 Mips64ManagedRegister scratch = mscratch.AsMips64();
2342 CHECK(scratch.IsGpuRegister()) << scratch;
2343 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2344 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2345}
2346
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002347void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2348 FrameOffset fr_offs,
2349 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002350 Mips64ManagedRegister scratch = mscratch.AsMips64();
2351 CHECK(scratch.IsGpuRegister()) << scratch;
2352 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2353 SP, fr_offs.Int32Value());
2354 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2355 S1, thr_offs.Int32Value());
2356}
2357
2358void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2359 ManagedRegister mscratch, size_t size) {
2360 Mips64ManagedRegister scratch = mscratch.AsMips64();
2361 CHECK(scratch.IsGpuRegister()) << scratch;
2362 CHECK(size == 4 || size == 8) << size;
2363 if (size == 4) {
2364 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002365 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002366 } else if (size == 8) {
2367 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2368 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2369 } else {
2370 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2371 }
2372}
2373
2374void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002375 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002376 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2377 CHECK(size == 4 || size == 8) << size;
2378 if (size == 4) {
2379 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2380 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002381 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002382 } else if (size == 8) {
2383 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2384 src_offset.Int32Value());
2385 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2386 } else {
2387 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2388 }
2389}
2390
2391void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002392 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002393 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2394 CHECK(size == 4 || size == 8) << size;
2395 if (size == 4) {
2396 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002397 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002398 dest_offset.Int32Value());
2399 } else if (size == 8) {
2400 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2401 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2402 dest_offset.Int32Value());
2403 } else {
2404 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2405 }
2406}
2407
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002408void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2409 FrameOffset src_base ATTRIBUTE_UNUSED,
2410 Offset src_offset ATTRIBUTE_UNUSED,
2411 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2412 size_t size ATTRIBUTE_UNUSED) {
2413 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002414}
2415
2416void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002417 ManagedRegister src, Offset src_offset,
2418 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002419 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2420 CHECK(size == 4 || size == 8) << size;
2421 if (size == 4) {
2422 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002423 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002424 } else if (size == 8) {
2425 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2426 src_offset.Int32Value());
2427 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2428 dest_offset.Int32Value());
2429 } else {
2430 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2431 }
2432}
2433
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002434void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2435 Offset dest_offset ATTRIBUTE_UNUSED,
2436 FrameOffset src ATTRIBUTE_UNUSED,
2437 Offset src_offset ATTRIBUTE_UNUSED,
2438 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2439 size_t size ATTRIBUTE_UNUSED) {
2440 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002441}
2442
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002443void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002444 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002445 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002446}
2447
2448void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002449 FrameOffset handle_scope_offset,
2450 ManagedRegister min_reg,
2451 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002452 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2453 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2454 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2455 CHECK(out_reg.IsGpuRegister()) << out_reg;
2456 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002457 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002458 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2459 // the address in the handle scope holding the reference.
2460 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2461 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002462 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002463 SP, handle_scope_offset.Int32Value());
2464 in_reg = out_reg;
2465 }
2466 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002467 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002468 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002469 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2470 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2471 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002472 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002473 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002474 }
2475}
2476
2477void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002478 FrameOffset handle_scope_offset,
2479 ManagedRegister mscratch,
2480 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002481 Mips64ManagedRegister scratch = mscratch.AsMips64();
2482 CHECK(scratch.IsGpuRegister()) << scratch;
2483 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002484 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002485 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002486 handle_scope_offset.Int32Value());
2487 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2488 // the address in the handle scope holding the reference.
2489 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002490 Beqzc(scratch.AsGpuRegister(), &null_arg);
2491 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2492 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002493 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002494 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002495 }
2496 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2497}
2498
2499// Given a handle scope entry, load the associated reference.
2500void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002501 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002502 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2503 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2504 CHECK(out_reg.IsGpuRegister()) << out_reg;
2505 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002506 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002507 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002508 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002509 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002510 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002511 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2512 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002513 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002514}
2515
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002516void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2517 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002518 // TODO: not validating references
2519}
2520
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002521void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2522 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002523 // TODO: not validating references
2524}
2525
2526void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2527 Mips64ManagedRegister base = mbase.AsMips64();
2528 Mips64ManagedRegister scratch = mscratch.AsMips64();
2529 CHECK(base.IsGpuRegister()) << base;
2530 CHECK(scratch.IsGpuRegister()) << scratch;
2531 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2532 base.AsGpuRegister(), offset.Int32Value());
2533 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002534 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002535 // TODO: place reference map on call
2536}
2537
2538void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2539 Mips64ManagedRegister scratch = mscratch.AsMips64();
2540 CHECK(scratch.IsGpuRegister()) << scratch;
2541 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002542 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002543 SP, base.Int32Value());
2544 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2545 scratch.AsGpuRegister(), offset.Int32Value());
2546 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002547 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002548 // TODO: place reference map on call
2549}
2550
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002551void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2552 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002553 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002554}
2555
2556void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2557 Move(tr.AsMips64().AsGpuRegister(), S1);
2558}
2559
2560void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002561 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002562 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2563}
2564
2565void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2566 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002567 exception_blocks_.emplace_back(scratch, stack_adjust);
2568 LoadFromOffset(kLoadDoubleword,
2569 scratch.AsGpuRegister(),
2570 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002571 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002572 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002573}
2574
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002575void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2576 Bind(exception->Entry());
2577 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2578 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002579 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002580 // Pass exception object as argument.
2581 // Don't care about preserving A0 as this call won't return.
2582 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2583 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002584 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002585 LoadFromOffset(kLoadDoubleword,
2586 T9,
2587 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002588 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002589 Jr(T9);
2590 Nop();
2591
Andreas Gampe57b34292015-01-14 15:45:59 -08002592 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002593 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002594}
2595
2596} // namespace mips64
2597} // namespace art