blob: 70414e7987bd0b67a64c22031b2ed16c5ba77d80 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
Alexey Frunze0960ac52016-12-20 17:24:59 -080038 ReserveJumpTableSpace();
Alexey Frunze19f6c692016-11-30 19:19:55 -080039 EmitLiterals();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070040 PromoteBranches();
41}
42
43void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
44 EmitBranches();
Alexey Frunze0960ac52016-12-20 17:24:59 -080045 EmitJumpTables();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070046 Assembler::FinalizeInstructions(region);
47 PatchCFI();
48}
49
50void Mips64Assembler::PatchCFI() {
51 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
52 return;
53 }
54
55 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
56 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
57 const std::vector<uint8_t>& old_stream = data.first;
58 const std::vector<DelayedAdvancePC>& advances = data.second;
59
60 // Refill our data buffer with patched opcodes.
61 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
62 size_t stream_pos = 0;
63 for (const DelayedAdvancePC& advance : advances) {
64 DCHECK_GE(advance.stream_pos, stream_pos);
65 // Copy old data up to the point where advance was issued.
66 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
67 stream_pos = advance.stream_pos;
68 // Insert the advance command with its final offset.
69 size_t final_pc = GetAdjustedPosition(advance.pc);
70 cfi().AdvancePC(final_pc);
71 }
72 // Copy the final segment if any.
73 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
74}
75
76void Mips64Assembler::EmitBranches() {
77 CHECK(!overwriting_);
78 // Switch from appending instructions at the end of the buffer to overwriting
79 // existing instructions (branch placeholders) in the buffer.
80 overwriting_ = true;
81 for (auto& branch : branches_) {
82 EmitBranch(&branch);
83 }
84 overwriting_ = false;
85}
86
Alexey Frunze4dda3372015-06-01 18:31:49 -070087void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070088 if (overwriting_) {
89 // Branches to labels are emitted into their placeholders here.
90 buffer_.Store<uint32_t>(overwrite_location_, value);
91 overwrite_location_ += sizeof(uint32_t);
92 } else {
93 // Other instructions are simply appended at the end here.
94 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
95 buffer_.Emit<uint32_t>(value);
96 }
Andreas Gampe57b34292015-01-14 15:45:59 -080097}
98
99void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
100 int shamt, int funct) {
101 CHECK_NE(rs, kNoGpuRegister);
102 CHECK_NE(rt, kNoGpuRegister);
103 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700104 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
105 static_cast<uint32_t>(rs) << kRsShift |
106 static_cast<uint32_t>(rt) << kRtShift |
107 static_cast<uint32_t>(rd) << kRdShift |
108 shamt << kShamtShift |
109 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800110 Emit(encoding);
111}
112
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700113void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
114 int shamt, int funct) {
115 CHECK_NE(rs, kNoGpuRegister);
116 CHECK_NE(rd, kNoGpuRegister);
117 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
118 static_cast<uint32_t>(rs) << kRsShift |
119 static_cast<uint32_t>(ZERO) << kRtShift |
120 static_cast<uint32_t>(rd) << kRdShift |
121 shamt << kShamtShift |
122 funct;
123 Emit(encoding);
124}
125
126void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
127 int shamt, int funct) {
128 CHECK_NE(rt, kNoGpuRegister);
129 CHECK_NE(rd, kNoGpuRegister);
130 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
131 static_cast<uint32_t>(ZERO) << kRsShift |
132 static_cast<uint32_t>(rt) << kRtShift |
133 static_cast<uint32_t>(rd) << kRdShift |
134 shamt << kShamtShift |
135 funct;
136 Emit(encoding);
137}
138
Andreas Gampe57b34292015-01-14 15:45:59 -0800139void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
140 CHECK_NE(rs, kNoGpuRegister);
141 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700142 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
143 static_cast<uint32_t>(rs) << kRsShift |
144 static_cast<uint32_t>(rt) << kRtShift |
145 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800146 Emit(encoding);
147}
148
Alexey Frunze4dda3372015-06-01 18:31:49 -0700149void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
150 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700151 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700152 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
153 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700154 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700155 Emit(encoding);
156}
157
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700158void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
159 CHECK(IsUint<26>(imm26)) << imm26;
160 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800161 Emit(encoding);
162}
163
164void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700165 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800166 CHECK_NE(ft, kNoFpuRegister);
167 CHECK_NE(fs, kNoFpuRegister);
168 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700169 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
170 fmt << kFmtShift |
171 static_cast<uint32_t>(ft) << kFtShift |
172 static_cast<uint32_t>(fs) << kFsShift |
173 static_cast<uint32_t>(fd) << kFdShift |
174 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800175 Emit(encoding);
176}
177
Alexey Frunze4dda3372015-06-01 18:31:49 -0700178void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
179 CHECK_NE(ft, kNoFpuRegister);
180 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
181 fmt << kFmtShift |
182 static_cast<uint32_t>(ft) << kFtShift |
183 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800184 Emit(encoding);
185}
186
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000187void Mips64Assembler::EmitMsa3R(int operation,
188 int df,
189 VectorRegister wt,
190 VectorRegister ws,
191 VectorRegister wd,
192 int minor_opcode) {
193 CHECK_NE(wt, kNoVectorRegister);
194 CHECK_NE(ws, kNoVectorRegister);
195 CHECK_NE(wd, kNoVectorRegister);
196 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
197 operation << kMsaOperationShift |
198 df << kDfShift |
199 static_cast<uint32_t>(wt) << kWtShift |
200 static_cast<uint32_t>(ws) << kWsShift |
201 static_cast<uint32_t>(wd) << kWdShift |
202 minor_opcode;
203 Emit(encoding);
204}
205
206void Mips64Assembler::EmitMsaBIT(int operation,
207 int df_m,
208 VectorRegister ws,
209 VectorRegister wd,
210 int minor_opcode) {
211 CHECK_NE(ws, kNoVectorRegister);
212 CHECK_NE(wd, kNoVectorRegister);
213 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
214 operation << kMsaOperationShift |
215 df_m << kDfMShift |
216 static_cast<uint32_t>(ws) << kWsShift |
217 static_cast<uint32_t>(wd) << kWdShift |
218 minor_opcode;
219 Emit(encoding);
220}
221
222void Mips64Assembler::EmitMsaELM(int operation,
223 int df_n,
224 VectorRegister ws,
225 VectorRegister wd,
226 int minor_opcode) {
227 CHECK_NE(ws, kNoVectorRegister);
228 CHECK_NE(wd, kNoVectorRegister);
229 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
230 operation << kMsaELMOperationShift |
231 df_n << kDfNShift |
232 static_cast<uint32_t>(ws) << kWsShift |
233 static_cast<uint32_t>(wd) << kWdShift |
234 minor_opcode;
235 Emit(encoding);
236}
237
238void Mips64Assembler::EmitMsaMI10(int s10,
239 GpuRegister rs,
240 VectorRegister wd,
241 int minor_opcode,
242 int df) {
243 CHECK_NE(rs, kNoGpuRegister);
244 CHECK_NE(wd, kNoVectorRegister);
245 CHECK(IsUint<10>(s10)) << s10;
246 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
247 s10 << kS10Shift |
248 static_cast<uint32_t>(rs) << kWsShift |
249 static_cast<uint32_t>(wd) << kWdShift |
250 minor_opcode << kS10MinorShift |
251 df;
252 Emit(encoding);
253}
254
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200255void Mips64Assembler::EmitMsaI10(int operation,
256 int df,
257 int i10,
258 VectorRegister wd,
259 int minor_opcode) {
260 CHECK_NE(wd, kNoVectorRegister);
261 CHECK(IsUint<10>(i10)) << i10;
262 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
263 operation << kMsaOperationShift |
264 df << kDfShift |
265 i10 << kI10Shift |
266 static_cast<uint32_t>(wd) << kWdShift |
267 minor_opcode;
268 Emit(encoding);
269}
270
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000271void Mips64Assembler::EmitMsa2R(int operation,
272 int df,
273 VectorRegister ws,
274 VectorRegister wd,
275 int minor_opcode) {
276 CHECK_NE(ws, kNoVectorRegister);
277 CHECK_NE(wd, kNoVectorRegister);
278 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
279 operation << kMsa2ROperationShift |
280 df << kDf2RShift |
281 static_cast<uint32_t>(ws) << kWsShift |
282 static_cast<uint32_t>(wd) << kWdShift |
283 minor_opcode;
284 Emit(encoding);
285}
286
287void Mips64Assembler::EmitMsa2RF(int operation,
288 int df,
289 VectorRegister ws,
290 VectorRegister wd,
291 int minor_opcode) {
292 CHECK_NE(ws, kNoVectorRegister);
293 CHECK_NE(wd, kNoVectorRegister);
294 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
295 operation << kMsa2RFOperationShift |
296 df << kDf2RShift |
297 static_cast<uint32_t>(ws) << kWsShift |
298 static_cast<uint32_t>(wd) << kWdShift |
299 minor_opcode;
300 Emit(encoding);
301}
302
Andreas Gampe57b34292015-01-14 15:45:59 -0800303void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
304 EmitR(0, rs, rt, rd, 0, 0x21);
305}
306
307void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
308 EmitI(0x9, rs, rt, imm16);
309}
310
Alexey Frunze4dda3372015-06-01 18:31:49 -0700311void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
312 EmitR(0, rs, rt, rd, 0, 0x2d);
313}
314
Andreas Gampe57b34292015-01-14 15:45:59 -0800315void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
316 EmitI(0x19, rs, rt, imm16);
317}
318
Andreas Gampe57b34292015-01-14 15:45:59 -0800319void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
320 EmitR(0, rs, rt, rd, 0, 0x23);
321}
322
Alexey Frunze4dda3372015-06-01 18:31:49 -0700323void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
324 EmitR(0, rs, rt, rd, 0, 0x2f);
325}
326
Alexey Frunze4dda3372015-06-01 18:31:49 -0700327void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
328 EmitR(0, rs, rt, rd, 2, 0x18);
329}
330
Alexey Frunzec857c742015-09-23 15:12:39 -0700331void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
332 EmitR(0, rs, rt, rd, 3, 0x18);
333}
334
Alexey Frunze4dda3372015-06-01 18:31:49 -0700335void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
336 EmitR(0, rs, rt, rd, 2, 0x1a);
337}
338
339void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
340 EmitR(0, rs, rt, rd, 3, 0x1a);
341}
342
343void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
344 EmitR(0, rs, rt, rd, 2, 0x1b);
345}
346
347void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
348 EmitR(0, rs, rt, rd, 3, 0x1b);
349}
350
351void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
352 EmitR(0, rs, rt, rd, 2, 0x1c);
353}
354
Alexey Frunzec857c742015-09-23 15:12:39 -0700355void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
356 EmitR(0, rs, rt, rd, 3, 0x1c);
357}
358
Alexey Frunze4dda3372015-06-01 18:31:49 -0700359void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
360 EmitR(0, rs, rt, rd, 2, 0x1e);
361}
362
363void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
364 EmitR(0, rs, rt, rd, 3, 0x1e);
365}
366
367void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
368 EmitR(0, rs, rt, rd, 2, 0x1f);
369}
370
371void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
372 EmitR(0, rs, rt, rd, 3, 0x1f);
373}
374
Andreas Gampe57b34292015-01-14 15:45:59 -0800375void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
376 EmitR(0, rs, rt, rd, 0, 0x24);
377}
378
379void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
380 EmitI(0xc, rs, rt, imm16);
381}
382
383void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
384 EmitR(0, rs, rt, rd, 0, 0x25);
385}
386
387void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
388 EmitI(0xd, rs, rt, imm16);
389}
390
391void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
392 EmitR(0, rs, rt, rd, 0, 0x26);
393}
394
395void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
396 EmitI(0xe, rs, rt, imm16);
397}
398
399void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
400 EmitR(0, rs, rt, rd, 0, 0x27);
401}
402
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700403void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
404 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
405}
406
407void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
408 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
409}
410
Alexey Frunze4dda3372015-06-01 18:31:49 -0700411void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
412 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800413}
414
Alexey Frunze4dda3372015-06-01 18:31:49 -0700415void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
416 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800417}
418
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700419void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
420 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
421}
422
423void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
424 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
425}
426
Lazar Trsicd9672662015-09-03 17:33:01 +0200427void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
428 CHECK(IsUint<5>(pos)) << pos;
429 CHECK(IsUint<5>(size - 1)) << size;
430 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
431}
432
433void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
434 CHECK(IsUint<5>(pos - 32)) << pos;
435 CHECK(IsUint<5>(size - 1)) << size;
436 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
437 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800438}
439
Chris Larsene3660592016-11-09 11:13:42 -0800440void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
441 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
442 int sa = saPlusOne - 1;
443 EmitR(0x0, rs, rt, rd, sa, 0x05);
444}
445
446void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
447 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
448 int sa = saPlusOne - 1;
449 EmitR(0x0, rs, rt, rd, sa, 0x15);
450}
451
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700452void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
453 EmitRtd(0x1f, rt, rd, 2, 0x20);
454}
455
456void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200457 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700458 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
459}
460
461void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200462 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700463 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
464}
465
466void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200467 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700468 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
469}
470
471void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200472 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700473 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
474}
475
Alexey Frunze4dda3372015-06-01 18:31:49 -0700476void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
477 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
478}
479
480void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
481 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
482}
483
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700484void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
485 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
486}
487
Alexey Frunze4dda3372015-06-01 18:31:49 -0700488void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
489 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
490}
491
492void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800493 EmitR(0, rs, rt, rd, 0, 0x04);
494}
495
Chris Larsen9aebff22015-09-22 17:54:15 -0700496void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
497 EmitR(0, rs, rt, rd, 1, 0x06);
498}
499
Alexey Frunze4dda3372015-06-01 18:31:49 -0700500void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800501 EmitR(0, rs, rt, rd, 0, 0x06);
502}
503
Alexey Frunze4dda3372015-06-01 18:31:49 -0700504void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800505 EmitR(0, rs, rt, rd, 0, 0x07);
506}
507
Alexey Frunze4dda3372015-06-01 18:31:49 -0700508void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
509 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
510}
511
512void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
513 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
514}
515
Chris Larsen9aebff22015-09-22 17:54:15 -0700516void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
517 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
518}
519
Alexey Frunze4dda3372015-06-01 18:31:49 -0700520void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
521 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
522}
523
524void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
525 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
526}
527
528void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
529 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
530}
531
Chris Larsen9aebff22015-09-22 17:54:15 -0700532void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
533 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
534}
535
Alexey Frunze4dda3372015-06-01 18:31:49 -0700536void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
537 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
538}
539
540void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
541 EmitR(0, rs, rt, rd, 0, 0x14);
542}
543
544void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
545 EmitR(0, rs, rt, rd, 0, 0x16);
546}
547
Chris Larsen9aebff22015-09-22 17:54:15 -0700548void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
549 EmitR(0, rs, rt, rd, 1, 0x16);
550}
551
Alexey Frunze4dda3372015-06-01 18:31:49 -0700552void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
553 EmitR(0, rs, rt, rd, 0, 0x17);
554}
555
Andreas Gampe57b34292015-01-14 15:45:59 -0800556void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
557 EmitI(0x20, rs, rt, imm16);
558}
559
560void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
561 EmitI(0x21, rs, rt, imm16);
562}
563
564void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
565 EmitI(0x23, rs, rt, imm16);
566}
567
568void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
569 EmitI(0x37, rs, rt, imm16);
570}
571
572void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
573 EmitI(0x24, rs, rt, imm16);
574}
575
576void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
577 EmitI(0x25, rs, rt, imm16);
578}
579
Douglas Leungd90957f2015-04-30 19:22:49 -0700580void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
581 EmitI(0x27, rs, rt, imm16);
582}
583
Alexey Frunze19f6c692016-11-30 19:19:55 -0800584void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
585 CHECK(IsUint<19>(imm19)) << imm19;
586 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
587}
588
589void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
590 CHECK(IsUint<19>(imm19)) << imm19;
591 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
592}
593
594void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
595 CHECK(IsUint<18>(imm18)) << imm18;
596 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
597}
598
Andreas Gampe57b34292015-01-14 15:45:59 -0800599void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
600 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
601}
602
Alexey Frunze0960ac52016-12-20 17:24:59 -0800603void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
604 EmitI(0xf, rs, rt, imm16);
605}
606
Alexey Frunzec061de12017-02-14 13:27:23 -0800607void Mips64Assembler::Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
608 CHECK_NE(rs, ZERO);
609 EmitI(0x1d, rs, rt, imm16);
610}
611
Alexey Frunze4dda3372015-06-01 18:31:49 -0700612void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
613 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
614}
615
616void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
617 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
618}
619
620void Mips64Assembler::Sync(uint32_t stype) {
621 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
622 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
623}
624
Andreas Gampe57b34292015-01-14 15:45:59 -0800625void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
626 EmitI(0x28, rs, rt, imm16);
627}
628
629void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
630 EmitI(0x29, rs, rt, imm16);
631}
632
633void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
634 EmitI(0x2b, rs, rt, imm16);
635}
636
637void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
638 EmitI(0x3f, rs, rt, imm16);
639}
640
641void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
642 EmitR(0, rs, rt, rd, 0, 0x2a);
643}
644
645void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
646 EmitR(0, rs, rt, rd, 0, 0x2b);
647}
648
649void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
650 EmitI(0xa, rs, rt, imm16);
651}
652
653void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
654 EmitI(0xb, rs, rt, imm16);
655}
656
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700657void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
658 EmitR(0, rs, rt, rd, 0, 0x35);
659}
660
661void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
662 EmitR(0, rs, rt, rd, 0, 0x37);
663}
664
665void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
666 EmitRsd(0, rs, rd, 0x01, 0x10);
667}
668
669void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
670 EmitRsd(0, rs, rd, 0x01, 0x11);
671}
672
673void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
674 EmitRsd(0, rs, rd, 0x01, 0x12);
675}
676
677void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
678 EmitRsd(0, rs, rd, 0x01, 0x13);
679}
680
Alexey Frunze4dda3372015-06-01 18:31:49 -0700681void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
682 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800683}
684
685void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700686 Jalr(RA, rs);
687}
688
689void Mips64Assembler::Jr(GpuRegister rs) {
690 Jalr(ZERO, rs);
691}
692
693void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
694 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
695}
696
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700697void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
698 CHECK(IsUint<19>(imm19)) << imm19;
699 EmitI21(0x3B, rs, imm19);
700}
701
702void Mips64Assembler::Bc(uint32_t imm26) {
703 EmitI26(0x32, imm26);
704}
705
Alexey Frunze19f6c692016-11-30 19:19:55 -0800706void Mips64Assembler::Balc(uint32_t imm26) {
707 EmitI26(0x3A, imm26);
708}
709
Alexey Frunze4dda3372015-06-01 18:31:49 -0700710void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
711 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
712}
713
714void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
715 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
716}
717
718void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
719 CHECK_NE(rs, ZERO);
720 CHECK_NE(rt, ZERO);
721 CHECK_NE(rs, rt);
722 EmitI(0x17, rs, rt, imm16);
723}
724
725void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
726 CHECK_NE(rt, ZERO);
727 EmitI(0x17, rt, rt, imm16);
728}
729
730void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
731 CHECK_NE(rt, ZERO);
732 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
733}
734
735void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
736 CHECK_NE(rs, ZERO);
737 CHECK_NE(rt, ZERO);
738 CHECK_NE(rs, rt);
739 EmitI(0x16, rs, rt, imm16);
740}
741
742void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
743 CHECK_NE(rt, ZERO);
744 EmitI(0x16, rt, rt, imm16);
745}
746
747void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
748 CHECK_NE(rt, ZERO);
749 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
750}
751
752void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
753 CHECK_NE(rs, ZERO);
754 CHECK_NE(rt, ZERO);
755 CHECK_NE(rs, rt);
756 EmitI(0x7, rs, rt, imm16);
757}
758
759void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
760 CHECK_NE(rs, ZERO);
761 CHECK_NE(rt, ZERO);
762 CHECK_NE(rs, rt);
763 EmitI(0x6, rs, rt, imm16);
764}
765
766void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
767 CHECK_NE(rs, ZERO);
768 CHECK_NE(rt, ZERO);
769 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700770 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700771}
772
773void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
774 CHECK_NE(rs, ZERO);
775 CHECK_NE(rt, ZERO);
776 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700777 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700778}
779
780void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
781 CHECK_NE(rs, ZERO);
782 EmitI21(0x36, rs, imm21);
783}
784
785void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
786 CHECK_NE(rs, ZERO);
787 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800788}
789
Alexey Frunze299a9392015-12-08 16:08:02 -0800790void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
791 EmitFI(0x11, 0x9, ft, imm16);
792}
793
794void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
795 EmitFI(0x11, 0xD, ft, imm16);
796}
797
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700798void Mips64Assembler::Beqz(GpuRegister rt, uint16_t imm16) {
799 EmitI(0x4, ZERO, rt, imm16);
800}
801
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700802void Mips64Assembler::EmitBcondc(BranchCondition cond,
803 GpuRegister rs,
804 GpuRegister rt,
805 uint32_t imm16_21) {
806 switch (cond) {
807 case kCondLT:
808 Bltc(rs, rt, imm16_21);
809 break;
810 case kCondGE:
811 Bgec(rs, rt, imm16_21);
812 break;
813 case kCondLE:
814 Bgec(rt, rs, imm16_21);
815 break;
816 case kCondGT:
817 Bltc(rt, rs, imm16_21);
818 break;
819 case kCondLTZ:
820 CHECK_EQ(rt, ZERO);
821 Bltzc(rs, imm16_21);
822 break;
823 case kCondGEZ:
824 CHECK_EQ(rt, ZERO);
825 Bgezc(rs, imm16_21);
826 break;
827 case kCondLEZ:
828 CHECK_EQ(rt, ZERO);
829 Blezc(rs, imm16_21);
830 break;
831 case kCondGTZ:
832 CHECK_EQ(rt, ZERO);
833 Bgtzc(rs, imm16_21);
834 break;
835 case kCondEQ:
836 Beqc(rs, rt, imm16_21);
837 break;
838 case kCondNE:
839 Bnec(rs, rt, imm16_21);
840 break;
841 case kCondEQZ:
842 CHECK_EQ(rt, ZERO);
843 Beqzc(rs, imm16_21);
844 break;
845 case kCondNEZ:
846 CHECK_EQ(rt, ZERO);
847 Bnezc(rs, imm16_21);
848 break;
849 case kCondLTU:
850 Bltuc(rs, rt, imm16_21);
851 break;
852 case kCondGEU:
853 Bgeuc(rs, rt, imm16_21);
854 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800855 case kCondF:
856 CHECK_EQ(rt, ZERO);
857 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
858 break;
859 case kCondT:
860 CHECK_EQ(rt, ZERO);
861 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
862 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700863 case kUncond:
864 LOG(FATAL) << "Unexpected branch condition " << cond;
865 UNREACHABLE();
866 }
867}
868
Andreas Gampe57b34292015-01-14 15:45:59 -0800869void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
870 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
871}
872
873void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
874 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
875}
876
877void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
878 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
879}
880
881void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
882 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
883}
884
885void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700886 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800887}
888
889void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700890 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800891}
892
893void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700894 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800895}
896
897void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700898 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800899}
900
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700901void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
902 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
903}
904
905void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
906 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
907}
908
909void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
910 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
911}
912
913void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
914 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
915}
916
Andreas Gampe57b34292015-01-14 15:45:59 -0800917void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
918 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
919}
920
921void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700922 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
923}
924
925void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
926 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
927}
928
929void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
930 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
931}
932
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700933void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
934 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
935}
936
937void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
938 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
939}
940
941void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
942 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
943}
944
945void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
946 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
947}
948
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800949void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
950 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
951}
952
953void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
954 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
955}
956
957void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
958 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
959}
960
961void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
962 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
963}
964
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700965void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
966 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
967}
968
969void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
970 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
971}
972
973void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
974 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
975}
976
977void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
978 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
979}
980
981void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
982 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
983}
984
985void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
986 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
987}
988
989void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
990 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
991}
992
993void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
994 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
995}
996
997void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
998 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
999}
1000
1001void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1002 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1003}
1004
Goran Jakovljevic2dec9272017-08-02 11:41:26 +02001005void Mips64Assembler::SeleqzS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1006 EmitFR(0x11, 0x10, ft, fs, fd, 0x14);
1007}
1008
1009void Mips64Assembler::SeleqzD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1010 EmitFR(0x11, 0x11, ft, fs, fd, 0x14);
1011}
1012
1013void Mips64Assembler::SelnezS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1014 EmitFR(0x11, 0x10, ft, fs, fd, 0x17);
1015}
1016
1017void Mips64Assembler::SelnezD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1018 EmitFR(0x11, 0x11, ft, fs, fd, 0x17);
1019}
1020
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001021void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
1022 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
1023}
1024
1025void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
1026 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
1027}
1028
1029void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
1030 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
1031}
1032
1033void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
1034 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
1035}
1036
1037void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1038 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1039}
1040
1041void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1042 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1043}
1044
1045void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1046 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1047}
1048
1049void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1050 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1051}
1052
Alexey Frunze299a9392015-12-08 16:08:02 -08001053void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1054 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1055}
1056
1057void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1058 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1059}
1060
1061void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1062 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1063}
1064
1065void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1066 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1067}
1068
1069void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1070 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1071}
1072
1073void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1074 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1075}
1076
1077void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1078 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1079}
1080
1081void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1082 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1083}
1084
1085void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1086 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1087}
1088
1089void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1090 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1091}
1092
1093void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1094 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1095}
1096
1097void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1098 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1099}
1100
1101void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1102 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1103}
1104
1105void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1106 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1107}
1108
1109void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1110 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1111}
1112
1113void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1114 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1115}
1116
1117void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1118 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1119}
1120
1121void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1122 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1123}
1124
1125void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1126 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1127}
1128
1129void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1130 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1131}
1132
Alexey Frunze4dda3372015-06-01 18:31:49 -07001133void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
1134 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
1135}
1136
1137void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
1138 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
1139}
1140
1141void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
1142 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
1143}
1144
1145void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
1146 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -08001147}
1148
Chris Larsen51417632015-10-02 13:24:25 -07001149void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
1150 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
1151}
1152
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001153void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
1154 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
1155}
1156
Andreas Gampe57b34292015-01-14 15:45:59 -08001157void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
1158 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1159}
1160
Lazar Trsicd9672662015-09-03 17:33:01 +02001161void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1162 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1163}
1164
Alexey Frunze4dda3372015-06-01 18:31:49 -07001165void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1166 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1167}
1168
Lazar Trsicd9672662015-09-03 17:33:01 +02001169void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1170 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1171}
1172
Alexey Frunze4dda3372015-06-01 18:31:49 -07001173void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1174 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1175}
1176
1177void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1178 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001179}
1180
1181void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1182 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1183}
1184
1185void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1186 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1187}
1188
1189void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1190 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1191}
1192
1193void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1194 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1195}
1196
1197void Mips64Assembler::Break() {
1198 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1199 static_cast<GpuRegister>(0), 0, 0xD);
1200}
1201
1202void Mips64Assembler::Nop() {
1203 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1204 static_cast<GpuRegister>(0), 0, 0x0);
1205}
1206
Alexey Frunze4dda3372015-06-01 18:31:49 -07001207void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1208 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001209}
1210
Alexey Frunze4dda3372015-06-01 18:31:49 -07001211void Mips64Assembler::Clear(GpuRegister rd) {
1212 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001213}
1214
Alexey Frunze4dda3372015-06-01 18:31:49 -07001215void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1216 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001217}
1218
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001219void Mips64Assembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001220 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001221 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e);
1222}
1223
1224void Mips64Assembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001225 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001226 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e);
1227}
1228
1229void Mips64Assembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001230 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001231 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e);
1232}
1233
1234void Mips64Assembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001235 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001236 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e);
1237}
1238
1239void Mips64Assembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001240 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001241 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe);
1242}
1243
1244void Mips64Assembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001245 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001246 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe);
1247}
1248
1249void Mips64Assembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001250 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001251 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe);
1252}
1253
1254void Mips64Assembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001255 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001256 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe);
1257}
1258
1259void Mips64Assembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001260 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001261 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe);
1262}
1263
1264void Mips64Assembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001265 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001266 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe);
1267}
1268
1269void Mips64Assembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001270 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001271 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe);
1272}
1273
1274void Mips64Assembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001275 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001276 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe);
1277}
1278
1279void Mips64Assembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001280 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001281 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12);
1282}
1283
1284void Mips64Assembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001285 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001286 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12);
1287}
1288
1289void Mips64Assembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001290 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001291 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12);
1292}
1293
1294void Mips64Assembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001295 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001296 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12);
1297}
1298
1299void Mips64Assembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001300 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001301 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12);
1302}
1303
1304void Mips64Assembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001305 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001306 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12);
1307}
1308
1309void Mips64Assembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001310 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001311 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12);
1312}
1313
1314void Mips64Assembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001315 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001316 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12);
1317}
1318
1319void Mips64Assembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001320 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001321 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12);
1322}
1323
1324void Mips64Assembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001325 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001326 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12);
1327}
1328
1329void Mips64Assembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001330 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001331 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12);
1332}
1333
1334void Mips64Assembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001335 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001336 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12);
1337}
1338
1339void Mips64Assembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001340 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001341 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12);
1342}
1343
1344void Mips64Assembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001345 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001346 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12);
1347}
1348
1349void Mips64Assembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001350 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001351 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12);
1352}
1353
1354void Mips64Assembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001355 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001356 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12);
1357}
1358
1359void Mips64Assembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001360 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001361 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12);
1362}
1363
1364void Mips64Assembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001365 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001366 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12);
1367}
1368
1369void Mips64Assembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001370 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001371 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12);
1372}
1373
1374void Mips64Assembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001375 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001376 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12);
1377}
1378
Goran Jakovljevic80248d72017-04-20 11:55:47 +02001379void Mips64Assembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1380 CHECK(HasMsa());
1381 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10);
1382}
1383
1384void Mips64Assembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1385 CHECK(HasMsa());
1386 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10);
1387}
1388
1389void Mips64Assembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1390 CHECK(HasMsa());
1391 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10);
1392}
1393
1394void Mips64Assembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1395 CHECK(HasMsa());
1396 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10);
1397}
1398
1399void Mips64Assembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1400 CHECK(HasMsa());
1401 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10);
1402}
1403
1404void Mips64Assembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1405 CHECK(HasMsa());
1406 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10);
1407}
1408
1409void Mips64Assembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1410 CHECK(HasMsa());
1411 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10);
1412}
1413
1414void Mips64Assembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1415 CHECK(HasMsa());
1416 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10);
1417}
1418
1419void Mips64Assembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1420 CHECK(HasMsa());
1421 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10);
1422}
1423
1424void Mips64Assembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1425 CHECK(HasMsa());
1426 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10);
1427}
1428
1429void Mips64Assembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1430 CHECK(HasMsa());
1431 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10);
1432}
1433
1434void Mips64Assembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1435 CHECK(HasMsa());
1436 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10);
1437}
1438
1439void Mips64Assembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1440 CHECK(HasMsa());
1441 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10);
1442}
1443
1444void Mips64Assembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1445 CHECK(HasMsa());
1446 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10);
1447}
1448
1449void Mips64Assembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1450 CHECK(HasMsa());
1451 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10);
1452}
1453
1454void Mips64Assembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1455 CHECK(HasMsa());
1456 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10);
1457}
1458
1459void Mips64Assembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1460 CHECK(HasMsa());
1461 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10);
1462}
1463
1464void Mips64Assembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1465 CHECK(HasMsa());
1466 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10);
1467}
1468
1469void Mips64Assembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1470 CHECK(HasMsa());
1471 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10);
1472}
1473
1474void Mips64Assembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1475 CHECK(HasMsa());
1476 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10);
1477}
1478
Goran Jakovljevic658263e2017-06-07 09:35:53 +02001479void Mips64Assembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1480 CHECK(HasMsa());
1481 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe);
1482}
1483
1484void Mips64Assembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1485 CHECK(HasMsa());
1486 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe);
1487}
1488
1489void Mips64Assembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1490 CHECK(HasMsa());
1491 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe);
1492}
1493
1494void Mips64Assembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1495 CHECK(HasMsa());
1496 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe);
1497}
1498
1499void Mips64Assembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1500 CHECK(HasMsa());
1501 EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe);
1502}
1503
1504void Mips64Assembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1505 CHECK(HasMsa());
1506 EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe);
1507}
1508
1509void Mips64Assembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1510 CHECK(HasMsa());
1511 EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe);
1512}
1513
1514void Mips64Assembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1515 CHECK(HasMsa());
1516 EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe);
1517}
1518
1519void Mips64Assembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1520 CHECK(HasMsa());
1521 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe);
1522}
1523
1524void Mips64Assembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1525 CHECK(HasMsa());
1526 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe);
1527}
1528
1529void Mips64Assembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1530 CHECK(HasMsa());
1531 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe);
1532}
1533
1534void Mips64Assembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1535 CHECK(HasMsa());
1536 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe);
1537}
1538
1539void Mips64Assembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1540 CHECK(HasMsa());
1541 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe);
1542}
1543
1544void Mips64Assembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1545 CHECK(HasMsa());
1546 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe);
1547}
1548
1549void Mips64Assembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1550 CHECK(HasMsa());
1551 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe);
1552}
1553
1554void Mips64Assembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1555 CHECK(HasMsa());
1556 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe);
1557}
1558
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001559void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001560 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001561 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b);
1562}
1563
1564void Mips64Assembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001565 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001566 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b);
1567}
1568
1569void Mips64Assembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001570 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001571 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b);
1572}
1573
1574void Mips64Assembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001575 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001576 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b);
1577}
1578
1579void Mips64Assembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001580 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001581 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b);
1582}
1583
1584void Mips64Assembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001585 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001586 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b);
1587}
1588
1589void Mips64Assembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001590 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001591 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b);
1592}
1593
1594void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001595 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001596 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b);
1597}
1598
Goran Jakovljevic658263e2017-06-07 09:35:53 +02001599void Mips64Assembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1600 CHECK(HasMsa());
1601 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b);
1602}
1603
1604void Mips64Assembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1605 CHECK(HasMsa());
1606 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b);
1607}
1608
1609void Mips64Assembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1610 CHECK(HasMsa());
1611 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b);
1612}
1613
1614void Mips64Assembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1615 CHECK(HasMsa());
1616 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b);
1617}
1618
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001619void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001620 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001621 EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e);
1622}
1623
1624void Mips64Assembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001625 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001626 EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e);
1627}
1628
1629void Mips64Assembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001630 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001631 EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e);
1632}
1633
1634void Mips64Assembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001635 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001636 EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e);
1637}
1638
1639void Mips64Assembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001640 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001641 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd);
1642}
1643
1644void Mips64Assembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001645 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001646 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd);
1647}
1648
1649void Mips64Assembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001650 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001651 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd);
1652}
1653
1654void Mips64Assembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001655 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001656 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd);
1657}
1658
1659void Mips64Assembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001660 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001661 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd);
1662}
1663
1664void Mips64Assembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001665 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001666 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd);
1667}
1668
1669void Mips64Assembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001670 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001671 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd);
1672}
1673
1674void Mips64Assembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001675 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001676 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd);
1677}
1678
1679void Mips64Assembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001680 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001681 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd);
1682}
1683
1684void Mips64Assembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001685 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001686 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd);
1687}
1688
1689void Mips64Assembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001690 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001691 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd);
1692}
1693
1694void Mips64Assembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001695 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001696 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd);
1697}
1698
1699void Mips64Assembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001700 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001701 CHECK(IsUint<3>(shamt3)) << shamt3;
1702 EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1703}
1704
1705void Mips64Assembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001706 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001707 CHECK(IsUint<4>(shamt4)) << shamt4;
1708 EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1709}
1710
1711void Mips64Assembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001712 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001713 CHECK(IsUint<5>(shamt5)) << shamt5;
1714 EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1715}
1716
1717void Mips64Assembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001718 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001719 CHECK(IsUint<6>(shamt6)) << shamt6;
1720 EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1721}
1722
1723void Mips64Assembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001724 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001725 CHECK(IsUint<3>(shamt3)) << shamt3;
1726 EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1727}
1728
1729void Mips64Assembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001730 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001731 CHECK(IsUint<4>(shamt4)) << shamt4;
1732 EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1733}
1734
1735void Mips64Assembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001736 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001737 CHECK(IsUint<5>(shamt5)) << shamt5;
1738 EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1739}
1740
1741void Mips64Assembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001742 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001743 CHECK(IsUint<6>(shamt6)) << shamt6;
1744 EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1745}
1746
1747void Mips64Assembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001748 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001749 CHECK(IsUint<3>(shamt3)) << shamt3;
1750 EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1751}
1752
1753void Mips64Assembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001754 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001755 CHECK(IsUint<4>(shamt4)) << shamt4;
1756 EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1757}
1758
1759void Mips64Assembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001760 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001761 CHECK(IsUint<5>(shamt5)) << shamt5;
1762 EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1763}
1764
1765void Mips64Assembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001766 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001767 CHECK(IsUint<6>(shamt6)) << shamt6;
1768 EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1769}
1770
1771void Mips64Assembler::MoveV(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001772 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001773 EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19);
1774}
1775
1776void Mips64Assembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001777 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001778 CHECK(IsUint<4>(n4)) << n4;
1779 EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19);
1780}
1781
1782void Mips64Assembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001783 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001784 CHECK(IsUint<3>(n3)) << n3;
1785 EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19);
1786}
1787
1788void Mips64Assembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001789 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001790 CHECK(IsUint<2>(n2)) << n2;
1791 EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19);
1792}
1793
1794void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001795 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001796 CHECK(IsUint<1>(n1)) << n1;
1797 EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19);
1798}
1799
1800void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001801 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001802 EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e);
1803}
1804
1805void Mips64Assembler::FillH(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001806 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001807 EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e);
1808}
1809
1810void Mips64Assembler::FillW(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001811 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001812 EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e);
1813}
1814
1815void Mips64Assembler::FillD(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001816 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001817 EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e);
1818}
1819
Goran Jakovljevic3f444032017-03-31 14:38:20 +02001820void Mips64Assembler::LdiB(VectorRegister wd, int imm8) {
1821 CHECK(HasMsa());
1822 CHECK(IsInt<8>(imm8)) << imm8;
1823 EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7);
1824}
1825
1826void Mips64Assembler::LdiH(VectorRegister wd, int imm10) {
1827 CHECK(HasMsa());
1828 CHECK(IsInt<10>(imm10)) << imm10;
1829 EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7);
1830}
1831
1832void Mips64Assembler::LdiW(VectorRegister wd, int imm10) {
1833 CHECK(HasMsa());
1834 CHECK(IsInt<10>(imm10)) << imm10;
1835 EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7);
1836}
1837
1838void Mips64Assembler::LdiD(VectorRegister wd, int imm10) {
1839 CHECK(HasMsa());
1840 CHECK(IsInt<10>(imm10)) << imm10;
1841 EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7);
1842}
1843
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001844void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001845 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001846 CHECK(IsInt<10>(offset)) << offset;
1847 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0);
1848}
1849
1850void Mips64Assembler::LdH(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001851 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001852 CHECK(IsInt<11>(offset)) << offset;
1853 CHECK_ALIGNED(offset, kMips64HalfwordSize);
1854 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1);
1855}
1856
1857void Mips64Assembler::LdW(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001858 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001859 CHECK(IsInt<12>(offset)) << offset;
1860 CHECK_ALIGNED(offset, kMips64WordSize);
1861 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2);
1862}
1863
1864void Mips64Assembler::LdD(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001865 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001866 CHECK(IsInt<13>(offset)) << offset;
1867 CHECK_ALIGNED(offset, kMips64DoublewordSize);
1868 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3);
1869}
1870
1871void Mips64Assembler::StB(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001872 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001873 CHECK(IsInt<10>(offset)) << offset;
1874 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0);
1875}
1876
1877void Mips64Assembler::StH(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001878 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001879 CHECK(IsInt<11>(offset)) << offset;
1880 CHECK_ALIGNED(offset, kMips64HalfwordSize);
1881 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1);
1882}
1883
1884void Mips64Assembler::StW(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001885 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001886 CHECK(IsInt<12>(offset)) << offset;
1887 CHECK_ALIGNED(offset, kMips64WordSize);
1888 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2);
1889}
1890
1891void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001892 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001893 CHECK(IsInt<13>(offset)) << offset;
1894 CHECK_ALIGNED(offset, kMips64DoublewordSize);
1895 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3);
1896}
1897
Goran Jakovljevic38370112017-05-10 14:30:28 +02001898void Mips64Assembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1899 CHECK(HasMsa());
1900 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14);
1901}
1902
1903void Mips64Assembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1904 CHECK(HasMsa());
1905 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14);
1906}
1907
1908void Mips64Assembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1909 CHECK(HasMsa());
1910 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14);
1911}
1912
1913void Mips64Assembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1914 CHECK(HasMsa());
1915 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14);
1916}
1917
Lena Djokicb3d79e42017-07-25 11:20:52 +02001918void Mips64Assembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1919 CHECK(HasMsa());
1920 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12);
1921}
1922
1923void Mips64Assembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1924 CHECK(HasMsa());
1925 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12);
1926}
1927
1928void Mips64Assembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1929 CHECK(HasMsa());
1930 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12);
1931}
1932
1933void Mips64Assembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1934 CHECK(HasMsa());
1935 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12);
1936}
1937
1938void Mips64Assembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1939 CHECK(HasMsa());
1940 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12);
1941}
1942
1943void Mips64Assembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1944 CHECK(HasMsa());
1945 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12);
1946}
1947
1948void Mips64Assembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1949 CHECK(HasMsa());
1950 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12);
1951}
1952
1953void Mips64Assembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1954 CHECK(HasMsa());
1955 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12);
1956}
1957
1958void Mips64Assembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1959 CHECK(HasMsa());
1960 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b);
1961}
1962
1963void Mips64Assembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1964 CHECK(HasMsa());
1965 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b);
1966}
1967
1968void Mips64Assembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1969 CHECK(HasMsa());
1970 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b);
1971}
1972
1973void Mips64Assembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1974 CHECK(HasMsa());
1975 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b);
1976}
1977
Goran Jakovljevic19680d32017-05-11 10:38:36 +02001978void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst,
1979 FpuRegister src,
1980 bool is_double) {
1981 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
1982 if (is_double) {
1983 SplatiD(dst, static_cast<VectorRegister>(src), 0);
1984 } else {
1985 SplatiW(dst, static_cast<VectorRegister>(src), 0);
1986 }
1987}
1988
Alexey Frunze4dda3372015-06-01 18:31:49 -07001989void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001990 TemplateLoadConst32(this, rd, value);
1991}
1992
1993// This function is only used for testing purposes.
1994void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001995}
1996
Alexey Frunze4dda3372015-06-01 18:31:49 -07001997void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001998 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001999}
2000
Alexey Frunze0960ac52016-12-20 17:24:59 -08002001void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) {
2002 if (IsInt<16>(value)) {
2003 Addiu(rt, rs, value);
2004 } else {
2005 int16_t high = High16Bits(value);
2006 int16_t low = Low16Bits(value);
2007 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
2008 Aui(rt, rs, high);
2009 if (low != 0) {
2010 Addiu(rt, rt, low);
2011 }
2012 }
2013}
2014
Alexey Frunze15958152017-02-09 19:08:30 -08002015// TODO: don't use rtmp, use daui, dahi, dati.
Alexey Frunze4dda3372015-06-01 18:31:49 -07002016void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
Chris Larsen5863f852017-03-23 15:41:37 -07002017 CHECK_NE(rs, rtmp);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002018 if (IsInt<16>(value)) {
2019 Daddiu(rt, rs, value);
2020 } else {
2021 LoadConst64(rtmp, value);
2022 Daddu(rt, rs, rtmp);
2023 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002024}
2025
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002026void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
2027 Mips64Assembler::Branch::Type short_type,
2028 Mips64Assembler::Branch::Type long_type) {
2029 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
2030}
Alexey Frunze4dda3372015-06-01 18:31:49 -07002031
Alexey Frunze19f6c692016-11-30 19:19:55 -08002032void Mips64Assembler::Branch::InitializeType(Type initial_type) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002033 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
Alexey Frunze19f6c692016-11-30 19:19:55 -08002034 switch (initial_type) {
2035 case kLabel:
2036 case kLiteral:
2037 case kLiteralUnsigned:
2038 case kLiteralLong:
2039 CHECK(!IsResolved());
2040 type_ = initial_type;
2041 break;
2042 case kCall:
2043 InitShortOrLong(offset_size, kCall, kLongCall);
2044 break;
2045 case kCondBranch:
2046 switch (condition_) {
2047 case kUncond:
2048 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
2049 break;
2050 case kCondEQZ:
2051 case kCondNEZ:
2052 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
2053 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
2054 break;
2055 default:
2056 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
2057 break;
2058 }
2059 break;
2060 default:
2061 LOG(FATAL) << "Unexpected branch type " << initial_type;
2062 UNREACHABLE();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002063 }
2064 old_type_ = type_;
2065}
2066
2067bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
2068 switch (condition) {
2069 case kCondLT:
2070 case kCondGT:
2071 case kCondNE:
2072 case kCondLTU:
2073 return lhs == rhs;
2074 default:
2075 return false;
2076 }
2077}
2078
2079bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
2080 GpuRegister lhs,
2081 GpuRegister rhs) {
2082 switch (condition) {
2083 case kUncond:
2084 return true;
2085 case kCondGE:
2086 case kCondLE:
2087 case kCondEQ:
2088 case kCondGEU:
2089 return lhs == rhs;
2090 default:
2091 return false;
2092 }
2093}
2094
Alexey Frunze19f6c692016-11-30 19:19:55 -08002095Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002096 : old_location_(location),
2097 location_(location),
2098 target_(target),
2099 lhs_reg_(ZERO),
2100 rhs_reg_(ZERO),
2101 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08002102 InitializeType(is_call ? kCall : kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002103}
2104
2105Mips64Assembler::Branch::Branch(uint32_t location,
2106 uint32_t target,
2107 Mips64Assembler::BranchCondition condition,
2108 GpuRegister lhs_reg,
2109 GpuRegister rhs_reg)
2110 : old_location_(location),
2111 location_(location),
2112 target_(target),
2113 lhs_reg_(lhs_reg),
2114 rhs_reg_(rhs_reg),
2115 condition_(condition) {
2116 CHECK_NE(condition, kUncond);
2117 switch (condition) {
2118 case kCondEQ:
2119 case kCondNE:
2120 case kCondLT:
2121 case kCondGE:
2122 case kCondLE:
2123 case kCondGT:
2124 case kCondLTU:
2125 case kCondGEU:
2126 CHECK_NE(lhs_reg, ZERO);
2127 CHECK_NE(rhs_reg, ZERO);
2128 break;
2129 case kCondLTZ:
2130 case kCondGEZ:
2131 case kCondLEZ:
2132 case kCondGTZ:
2133 case kCondEQZ:
2134 case kCondNEZ:
2135 CHECK_NE(lhs_reg, ZERO);
2136 CHECK_EQ(rhs_reg, ZERO);
2137 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08002138 case kCondF:
2139 case kCondT:
2140 CHECK_EQ(rhs_reg, ZERO);
2141 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002142 case kUncond:
2143 UNREACHABLE();
2144 }
2145 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
2146 if (IsUncond(condition, lhs_reg, rhs_reg)) {
2147 // Branch condition is always true, make the branch unconditional.
2148 condition_ = kUncond;
2149 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08002150 InitializeType(kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002151}
2152
Alexey Frunze19f6c692016-11-30 19:19:55 -08002153Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002154 : old_location_(location),
2155 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08002156 target_(kUnresolved),
2157 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002158 rhs_reg_(ZERO),
2159 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08002160 CHECK_NE(dest_reg, ZERO);
2161 InitializeType(label_or_literal_type);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002162}
2163
2164Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
2165 Mips64Assembler::BranchCondition cond) {
2166 switch (cond) {
2167 case kCondLT:
2168 return kCondGE;
2169 case kCondGE:
2170 return kCondLT;
2171 case kCondLE:
2172 return kCondGT;
2173 case kCondGT:
2174 return kCondLE;
2175 case kCondLTZ:
2176 return kCondGEZ;
2177 case kCondGEZ:
2178 return kCondLTZ;
2179 case kCondLEZ:
2180 return kCondGTZ;
2181 case kCondGTZ:
2182 return kCondLEZ;
2183 case kCondEQ:
2184 return kCondNE;
2185 case kCondNE:
2186 return kCondEQ;
2187 case kCondEQZ:
2188 return kCondNEZ;
2189 case kCondNEZ:
2190 return kCondEQZ;
2191 case kCondLTU:
2192 return kCondGEU;
2193 case kCondGEU:
2194 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08002195 case kCondF:
2196 return kCondT;
2197 case kCondT:
2198 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002199 case kUncond:
2200 LOG(FATAL) << "Unexpected branch condition " << cond;
2201 }
2202 UNREACHABLE();
2203}
2204
2205Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
2206 return type_;
2207}
2208
2209Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
2210 return condition_;
2211}
2212
2213GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
2214 return lhs_reg_;
2215}
2216
2217GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
2218 return rhs_reg_;
2219}
2220
2221uint32_t Mips64Assembler::Branch::GetTarget() const {
2222 return target_;
2223}
2224
2225uint32_t Mips64Assembler::Branch::GetLocation() const {
2226 return location_;
2227}
2228
2229uint32_t Mips64Assembler::Branch::GetOldLocation() const {
2230 return old_location_;
2231}
2232
2233uint32_t Mips64Assembler::Branch::GetLength() const {
2234 return branch_info_[type_].length;
2235}
2236
2237uint32_t Mips64Assembler::Branch::GetOldLength() const {
2238 return branch_info_[old_type_].length;
2239}
2240
2241uint32_t Mips64Assembler::Branch::GetSize() const {
2242 return GetLength() * sizeof(uint32_t);
2243}
2244
2245uint32_t Mips64Assembler::Branch::GetOldSize() const {
2246 return GetOldLength() * sizeof(uint32_t);
2247}
2248
2249uint32_t Mips64Assembler::Branch::GetEndLocation() const {
2250 return GetLocation() + GetSize();
2251}
2252
2253uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
2254 return GetOldLocation() + GetOldSize();
2255}
2256
2257bool Mips64Assembler::Branch::IsLong() const {
2258 switch (type_) {
2259 // Short branches.
2260 case kUncondBranch:
2261 case kCondBranch:
2262 case kCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002263 // Near label.
2264 case kLabel:
2265 // Near literals.
2266 case kLiteral:
2267 case kLiteralUnsigned:
2268 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002269 return false;
2270 // Long branches.
2271 case kLongUncondBranch:
2272 case kLongCondBranch:
2273 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002274 // Far label.
2275 case kFarLabel:
2276 // Far literals.
2277 case kFarLiteral:
2278 case kFarLiteralUnsigned:
2279 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002280 return true;
2281 }
2282 UNREACHABLE();
2283}
2284
2285bool Mips64Assembler::Branch::IsResolved() const {
2286 return target_ != kUnresolved;
2287}
2288
2289Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
2290 OffsetBits offset_size =
2291 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
2292 ? kOffset23
2293 : branch_info_[type_].offset_size;
2294 return offset_size;
2295}
2296
2297Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
2298 uint32_t target) {
2299 // For unresolved targets assume the shortest encoding
2300 // (later it will be made longer if needed).
2301 if (target == kUnresolved)
2302 return kOffset16;
2303 int64_t distance = static_cast<int64_t>(target) - location;
2304 // To simplify calculations in composite branches consisting of multiple instructions
2305 // bump up the distance by a value larger than the max byte size of a composite branch.
2306 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
2307 if (IsInt<kOffset16>(distance))
2308 return kOffset16;
2309 else if (IsInt<kOffset18>(distance))
2310 return kOffset18;
2311 else if (IsInt<kOffset21>(distance))
2312 return kOffset21;
2313 else if (IsInt<kOffset23>(distance))
2314 return kOffset23;
2315 else if (IsInt<kOffset28>(distance))
2316 return kOffset28;
2317 return kOffset32;
2318}
2319
2320void Mips64Assembler::Branch::Resolve(uint32_t target) {
2321 target_ = target;
2322}
2323
2324void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
2325 if (location_ > expand_location) {
2326 location_ += delta;
2327 }
2328 if (!IsResolved()) {
2329 return; // Don't know the target yet.
2330 }
2331 if (target_ > expand_location) {
2332 target_ += delta;
2333 }
2334}
2335
2336void Mips64Assembler::Branch::PromoteToLong() {
2337 switch (type_) {
2338 // Short branches.
2339 case kUncondBranch:
2340 type_ = kLongUncondBranch;
2341 break;
2342 case kCondBranch:
2343 type_ = kLongCondBranch;
2344 break;
2345 case kCall:
2346 type_ = kLongCall;
2347 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002348 // Near label.
2349 case kLabel:
2350 type_ = kFarLabel;
2351 break;
2352 // Near literals.
2353 case kLiteral:
2354 type_ = kFarLiteral;
2355 break;
2356 case kLiteralUnsigned:
2357 type_ = kFarLiteralUnsigned;
2358 break;
2359 case kLiteralLong:
2360 type_ = kFarLiteralLong;
2361 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002362 default:
2363 // Note: 'type_' is already long.
2364 break;
2365 }
2366 CHECK(IsLong());
2367}
2368
2369uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
2370 // If the branch is still unresolved or already long, nothing to do.
2371 if (IsLong() || !IsResolved()) {
2372 return 0;
2373 }
2374 // Promote the short branch to long if the offset size is too small
2375 // to hold the distance between location_ and target_.
2376 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
2377 PromoteToLong();
2378 uint32_t old_size = GetOldSize();
2379 uint32_t new_size = GetSize();
2380 CHECK_GT(new_size, old_size);
2381 return new_size - old_size;
2382 }
2383 // The following logic is for debugging/testing purposes.
2384 // Promote some short branches to long when it's not really required.
2385 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
2386 int64_t distance = static_cast<int64_t>(target_) - location_;
2387 distance = (distance >= 0) ? distance : -distance;
2388 if (distance >= max_short_distance) {
2389 PromoteToLong();
2390 uint32_t old_size = GetOldSize();
2391 uint32_t new_size = GetSize();
2392 CHECK_GT(new_size, old_size);
2393 return new_size - old_size;
2394 }
2395 }
2396 return 0;
2397}
2398
2399uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
2400 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
2401}
2402
2403uint32_t Mips64Assembler::Branch::GetOffset() const {
2404 CHECK(IsResolved());
2405 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
2406 // Calculate the byte distance between instructions and also account for
2407 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08002408 uint32_t offset_location = GetOffsetLocation();
2409 if (type_ == kLiteralLong) {
2410 // Special case for the ldpc instruction, whose address (PC) is rounded down to
2411 // a multiple of 8 before adding the offset.
2412 // Note, branch promotion has already taken care of aligning `target_` to an
2413 // address that's a multiple of 8.
2414 offset_location = RoundDown(offset_location, sizeof(uint64_t));
2415 }
2416 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002417 // Prepare the offset for encoding into the instruction(s).
2418 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
2419 return offset;
2420}
2421
2422Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
2423 CHECK_LT(branch_id, branches_.size());
2424 return &branches_[branch_id];
2425}
2426
2427const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
2428 CHECK_LT(branch_id, branches_.size());
2429 return &branches_[branch_id];
2430}
2431
2432void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002433 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002434 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002435
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002436 // Walk the list of branches referring to and preceding this label.
2437 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07002438 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002439 uint32_t branch_id = label->Position();
2440 Branch* branch = GetBranch(branch_id);
2441 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002442
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002443 uint32_t branch_location = branch->GetLocation();
2444 // Extract the location of the previous branch in the list (walking the list backwards;
2445 // the previous branch ID was stored in the space reserved for this branch).
2446 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002447
2448 // On to the previous branch in the list...
2449 label->position_ = prev;
2450 }
2451
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002452 // Now make the label object contain its own location (relative to the end of the preceding
2453 // branch, if any; it will be used by the branches referring to and following this label).
2454 label->prev_branch_id_plus_one_ = branches_.size();
2455 if (label->prev_branch_id_plus_one_) {
2456 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2457 const Branch* branch = GetBranch(branch_id);
2458 bound_pc -= branch->GetEndLocation();
2459 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002460 label->BindTo(bound_pc);
2461}
2462
Alexey Frunze19f6c692016-11-30 19:19:55 -08002463uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002464 CHECK(label->IsBound());
2465 uint32_t target = label->Position();
2466 if (label->prev_branch_id_plus_one_) {
2467 // Get label location based on the branch preceding it.
2468 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2469 const Branch* branch = GetBranch(branch_id);
2470 target += branch->GetEndLocation();
2471 }
2472 return target;
2473}
2474
2475uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
2476 // We can reconstruct the adjustment by going through all the branches from the beginning
2477 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
2478 // with increasing old_position, we can use the data from last AdjustedPosition() to
2479 // continue where we left off and the whole loop should be O(m+n) where m is the number
2480 // of positions to adjust and n is the number of branches.
2481 if (old_position < last_old_position_) {
2482 last_position_adjustment_ = 0;
2483 last_old_position_ = 0;
2484 last_branch_id_ = 0;
2485 }
2486 while (last_branch_id_ != branches_.size()) {
2487 const Branch* branch = GetBranch(last_branch_id_);
2488 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
2489 break;
2490 }
2491 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
2492 ++last_branch_id_;
2493 }
2494 last_old_position_ = old_position;
2495 return old_position + last_position_adjustment_;
2496}
2497
2498void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
2499 uint32_t length = branches_.back().GetLength();
2500 if (!label->IsBound()) {
2501 // Branch forward (to a following label), distance is unknown.
2502 // The first branch forward will contain 0, serving as the terminator of
2503 // the list of forward-reaching branches.
2504 Emit(label->position_);
2505 length--;
2506 // Now make the label object point to this branch
2507 // (this forms a linked list of branches preceding this label).
2508 uint32_t branch_id = branches_.size() - 1;
2509 label->LinkTo(branch_id);
2510 }
2511 // Reserve space for the branch.
2512 while (length--) {
2513 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002514 }
2515}
2516
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002517void Mips64Assembler::Buncond(Mips64Label* label) {
2518 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002519 branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002520 FinalizeLabeledBranch(label);
2521}
2522
2523void Mips64Assembler::Bcond(Mips64Label* label,
2524 BranchCondition condition,
2525 GpuRegister lhs,
2526 GpuRegister rhs) {
2527 // If lhs = rhs, this can be a NOP.
2528 if (Branch::IsNop(condition, lhs, rhs)) {
2529 return;
2530 }
2531 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
2532 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
2533 FinalizeLabeledBranch(label);
2534}
2535
Alexey Frunze19f6c692016-11-30 19:19:55 -08002536void Mips64Assembler::Call(Mips64Label* label) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002537 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002538 branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002539 FinalizeLabeledBranch(label);
2540}
2541
Alexey Frunze19f6c692016-11-30 19:19:55 -08002542void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
2543 // Label address loads are treated as pseudo branches since they require very similar handling.
2544 DCHECK(!label->IsBound());
2545 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
2546 FinalizeLabeledBranch(label);
2547}
2548
2549Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
2550 // We don't support byte and half-word literals.
2551 if (size == 4u) {
2552 literals_.emplace_back(size, data);
2553 return &literals_.back();
2554 } else {
2555 DCHECK_EQ(size, 8u);
2556 long_literals_.emplace_back(size, data);
2557 return &long_literals_.back();
2558 }
2559}
2560
2561void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
2562 LoadOperandType load_type,
2563 Literal* literal) {
2564 // Literal loads are treated as pseudo branches since they require very similar handling.
2565 Branch::Type literal_type;
2566 switch (load_type) {
2567 case kLoadWord:
2568 DCHECK_EQ(literal->GetSize(), 4u);
2569 literal_type = Branch::kLiteral;
2570 break;
2571 case kLoadUnsignedWord:
2572 DCHECK_EQ(literal->GetSize(), 4u);
2573 literal_type = Branch::kLiteralUnsigned;
2574 break;
2575 case kLoadDoubleword:
2576 DCHECK_EQ(literal->GetSize(), 8u);
2577 literal_type = Branch::kLiteralLong;
2578 break;
2579 default:
2580 LOG(FATAL) << "Unexpected literal load type " << load_type;
2581 UNREACHABLE();
2582 }
2583 Mips64Label* label = literal->GetLabel();
2584 DCHECK(!label->IsBound());
2585 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
2586 FinalizeLabeledBranch(label);
2587}
2588
Alexey Frunze0960ac52016-12-20 17:24:59 -08002589JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) {
2590 jump_tables_.emplace_back(std::move(labels));
2591 JumpTable* table = &jump_tables_.back();
2592 DCHECK(!table->GetLabel()->IsBound());
2593 return table;
2594}
2595
2596void Mips64Assembler::ReserveJumpTableSpace() {
2597 if (!jump_tables_.empty()) {
2598 for (JumpTable& table : jump_tables_) {
2599 Mips64Label* label = table.GetLabel();
2600 Bind(label);
2601
2602 // Bulk ensure capacity, as this may be large.
2603 size_t orig_size = buffer_.Size();
2604 size_t required_capacity = orig_size + table.GetSize();
2605 if (required_capacity > buffer_.Capacity()) {
2606 buffer_.ExtendCapacity(required_capacity);
2607 }
2608#ifndef NDEBUG
2609 buffer_.has_ensured_capacity_ = true;
2610#endif
2611
2612 // Fill the space with dummy data as the data is not final
2613 // until the branches have been promoted. And we shouldn't
2614 // be moving uninitialized data during branch promotion.
2615 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
2616 buffer_.Emit<uint32_t>(0x1abe1234u);
2617 }
2618
2619#ifndef NDEBUG
2620 buffer_.has_ensured_capacity_ = false;
2621#endif
2622 }
2623 }
2624}
2625
2626void Mips64Assembler::EmitJumpTables() {
2627 if (!jump_tables_.empty()) {
2628 CHECK(!overwriting_);
2629 // Switch from appending instructions at the end of the buffer to overwriting
2630 // existing instructions (here, jump tables) in the buffer.
2631 overwriting_ = true;
2632
2633 for (JumpTable& table : jump_tables_) {
2634 Mips64Label* table_label = table.GetLabel();
2635 uint32_t start = GetLabelLocation(table_label);
2636 overwrite_location_ = start;
2637
2638 for (Mips64Label* target : table.GetData()) {
2639 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
2640 // The table will contain target addresses relative to the table start.
2641 uint32_t offset = GetLabelLocation(target) - start;
2642 Emit(offset);
2643 }
2644 }
2645
2646 overwriting_ = false;
2647 }
2648}
2649
Alexey Frunze19f6c692016-11-30 19:19:55 -08002650void Mips64Assembler::EmitLiterals() {
2651 if (!literals_.empty()) {
2652 for (Literal& literal : literals_) {
2653 Mips64Label* label = literal.GetLabel();
2654 Bind(label);
2655 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2656 DCHECK_EQ(literal.GetSize(), 4u);
2657 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
2658 buffer_.Emit<uint8_t>(literal.GetData()[i]);
2659 }
2660 }
2661 }
2662 if (!long_literals_.empty()) {
2663 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
2664 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
2665 Emit(0); // NOP.
2666 for (Literal& literal : long_literals_) {
2667 Mips64Label* label = literal.GetLabel();
2668 Bind(label);
2669 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2670 DCHECK_EQ(literal.GetSize(), 8u);
2671 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
2672 buffer_.Emit<uint8_t>(literal.GetData()[i]);
2673 }
2674 }
2675 }
2676}
2677
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002678void Mips64Assembler::PromoteBranches() {
2679 // Promote short branches to long as necessary.
2680 bool changed;
2681 do {
2682 changed = false;
2683 for (auto& branch : branches_) {
2684 CHECK(branch.IsResolved());
2685 uint32_t delta = branch.PromoteIfNeeded();
2686 // If this branch has been promoted and needs to expand in size,
2687 // relocate all branches by the expansion size.
2688 if (delta) {
2689 changed = true;
2690 uint32_t expand_location = branch.GetLocation();
2691 for (auto& branch2 : branches_) {
2692 branch2.Relocate(expand_location, delta);
2693 }
2694 }
2695 }
2696 } while (changed);
2697
2698 // Account for branch expansion by resizing the code buffer
2699 // and moving the code in it to its final location.
2700 size_t branch_count = branches_.size();
2701 if (branch_count > 0) {
2702 // Resize.
2703 Branch& last_branch = branches_[branch_count - 1];
2704 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
2705 uint32_t old_size = buffer_.Size();
2706 buffer_.Resize(old_size + size_delta);
2707 // Move the code residing between branch placeholders.
2708 uint32_t end = old_size;
2709 for (size_t i = branch_count; i > 0; ) {
2710 Branch& branch = branches_[--i];
2711 uint32_t size = end - branch.GetOldEndLocation();
2712 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
2713 end = branch.GetOldLocation();
2714 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002715 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08002716
2717 // Align 64-bit literals by moving them down by 4 bytes if needed.
2718 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
2719 if (!long_literals_.empty()) {
2720 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
2721 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
2722 size_t buf_size = buffer_.Size();
2723 // 64-bit literals must be at the very end of the buffer.
2724 CHECK_EQ(first_literal_location + lit_size, buf_size);
2725 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
2726 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
2727 // The 4 reserved bytes proved useless, reduce the buffer size.
2728 buffer_.Resize(buf_size - sizeof(uint32_t));
2729 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
2730 // offsets from PC to be generated.
2731 for (auto& branch : branches_) {
2732 uint32_t target = branch.GetTarget();
2733 if (target >= first_literal_location) {
2734 branch.Resolve(target - sizeof(uint32_t));
2735 }
2736 }
2737 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
2738 // we need to adjust the location of the literal's label as well.
2739 for (Literal& literal : long_literals_) {
2740 // Bound label's position is negative, hence incrementing it instead of decrementing.
2741 literal.GetLabel()->position_ += sizeof(uint32_t);
2742 }
2743 }
2744 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002745}
2746
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002747// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2748const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
2749 // Short branches.
2750 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
2751 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
2752 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08002753 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
2754 // Near label.
2755 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
2756 // Near literals.
2757 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
2758 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
2759 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002760 // Long branches.
2761 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
2762 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08002763 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
2764 // Far label.
2765 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
2766 // Far literals.
2767 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
2768 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
2769 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002770};
2771
2772// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2773void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
2774 CHECK(overwriting_);
2775 overwrite_location_ = branch->GetLocation();
2776 uint32_t offset = branch->GetOffset();
2777 BranchCondition condition = branch->GetCondition();
2778 GpuRegister lhs = branch->GetLeftRegister();
2779 GpuRegister rhs = branch->GetRightRegister();
2780 switch (branch->GetType()) {
2781 // Short branches.
2782 case Branch::kUncondBranch:
2783 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2784 Bc(offset);
2785 break;
2786 case Branch::kCondBranch:
2787 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2788 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08002789 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002790 break;
2791 case Branch::kCall:
2792 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08002793 Balc(offset);
2794 break;
2795
2796 // Near label.
2797 case Branch::kLabel:
2798 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002799 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08002800 break;
2801 // Near literals.
2802 case Branch::kLiteral:
2803 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2804 Lwpc(lhs, offset);
2805 break;
2806 case Branch::kLiteralUnsigned:
2807 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2808 Lwupc(lhs, offset);
2809 break;
2810 case Branch::kLiteralLong:
2811 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2812 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002813 break;
2814
2815 // Long branches.
2816 case Branch::kLongUncondBranch:
2817 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2818 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2819 Auipc(AT, High16Bits(offset));
2820 Jic(AT, Low16Bits(offset));
2821 break;
2822 case Branch::kLongCondBranch:
2823 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
2824 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2825 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2826 Auipc(AT, High16Bits(offset));
2827 Jic(AT, Low16Bits(offset));
2828 break;
2829 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002830 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002831 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08002832 Auipc(AT, High16Bits(offset));
2833 Jialc(AT, Low16Bits(offset));
2834 break;
2835
2836 // Far label.
2837 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08002838 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08002839 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2840 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08002841 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08002842 break;
2843 // Far literals.
2844 case Branch::kFarLiteral:
2845 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
2846 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2847 Auipc(AT, High16Bits(offset));
2848 Lw(lhs, AT, Low16Bits(offset));
2849 break;
2850 case Branch::kFarLiteralUnsigned:
2851 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
2852 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2853 Auipc(AT, High16Bits(offset));
2854 Lwu(lhs, AT, Low16Bits(offset));
2855 break;
2856 case Branch::kFarLiteralLong:
2857 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
2858 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2859 Auipc(AT, High16Bits(offset));
2860 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002861 break;
2862 }
2863 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2864 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002865}
2866
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002867void Mips64Assembler::Bc(Mips64Label* label) {
2868 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002869}
2870
Alexey Frunze19f6c692016-11-30 19:19:55 -08002871void Mips64Assembler::Balc(Mips64Label* label) {
2872 Call(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002873}
2874
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002875void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2876 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002877}
2878
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002879void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
2880 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002881}
2882
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002883void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
2884 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002885}
2886
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002887void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2888 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002889}
2890
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002891void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
2892 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002893}
2894
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002895void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
2896 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002897}
2898
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002899void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2900 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002901}
2902
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002903void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2904 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002905}
2906
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002907void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2908 Bcond(label, kCondEQ, rs, rt);
2909}
2910
2911void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2912 Bcond(label, kCondNE, rs, rt);
2913}
2914
2915void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
2916 Bcond(label, kCondEQZ, rs);
2917}
2918
2919void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
2920 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08002921}
2922
Alexey Frunze299a9392015-12-08 16:08:02 -08002923void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
2924 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
2925}
2926
2927void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
2928 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
2929}
2930
Chris Larsenc3fec0c2016-12-15 11:44:14 -08002931void Mips64Assembler::AdjustBaseAndOffset(GpuRegister& base,
2932 int32_t& offset,
2933 bool is_doubleword) {
2934 // This method is used to adjust the base register and offset pair
2935 // for a load/store when the offset doesn't fit into int16_t.
2936 // It is assumed that `base + offset` is sufficiently aligned for memory
2937 // operands that are machine word in size or smaller. For doubleword-sized
2938 // operands it's assumed that `base` is a multiple of 8, while `offset`
2939 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
2940 // and spilled variables on the stack accessed relative to the stack
2941 // pointer register).
2942 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
2943 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
2944
2945 bool doubleword_aligned = IsAligned<kMips64DoublewordSize>(offset);
2946 bool two_accesses = is_doubleword && !doubleword_aligned;
2947
2948 // IsInt<16> must be passed a signed value, hence the static cast below.
2949 if (IsInt<16>(offset) &&
2950 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
2951 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
2952 return;
2953 }
2954
2955 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
2956 uint32_t misalignment = offset & (kMips64DoublewordSize - 1);
2957
2958 // First, see if `offset` can be represented as a sum of two 16-bit signed
2959 // offsets. This can save an instruction.
2960 // To simplify matters, only do this for a symmetric range of offsets from
2961 // about -64KB to about +64KB, allowing further addition of 4 when accessing
2962 // 64-bit variables with two 32-bit accesses.
2963 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
2964 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
2965
2966 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
2967 Daddiu(AT, base, kMinOffsetForSimpleAdjustment);
2968 offset -= kMinOffsetForSimpleAdjustment;
2969 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
2970 Daddiu(AT, base, -kMinOffsetForSimpleAdjustment);
2971 offset += kMinOffsetForSimpleAdjustment;
2972 } else {
2973 // In more complex cases take advantage of the daui instruction, e.g.:
2974 // daui AT, base, offset_high
2975 // [dahi AT, 1] // When `offset` is close to +2GB.
2976 // lw reg_lo, offset_low(AT)
2977 // [lw reg_hi, (offset_low+4)(AT)] // If misaligned 64-bit load.
2978 // or when offset_low+4 overflows int16_t:
2979 // daui AT, base, offset_high
2980 // daddiu AT, AT, 8
2981 // lw reg_lo, (offset_low-8)(AT)
2982 // lw reg_hi, (offset_low-4)(AT)
2983 int16_t offset_low = Low16Bits(offset);
2984 int32_t offset_low32 = offset_low;
2985 int16_t offset_high = High16Bits(offset);
2986 bool increment_hi16 = offset_low < 0;
2987 bool overflow_hi16 = false;
2988
2989 if (increment_hi16) {
2990 offset_high++;
2991 overflow_hi16 = (offset_high == -32768);
2992 }
2993 Daui(AT, base, offset_high);
2994
2995 if (overflow_hi16) {
2996 Dahi(AT, 1);
2997 }
2998
2999 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low32 + kMips64WordSize))) {
3000 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
3001 Daddiu(AT, AT, kMips64DoublewordSize);
3002 offset_low32 -= kMips64DoublewordSize;
3003 }
3004
3005 offset = offset_low32;
3006 }
3007 base = AT;
3008
3009 CHECK(IsInt<16>(offset));
3010 if (two_accesses) {
3011 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)));
3012 }
3013 CHECK_EQ(misalignment, offset & (kMips64DoublewordSize - 1));
3014}
3015
Goran Jakovljevicd8b6a532017-04-20 11:42:30 +02003016void Mips64Assembler::AdjustBaseOffsetAndElementSizeShift(GpuRegister& base,
3017 int32_t& offset,
3018 int& element_size_shift) {
3019 // This method is used to adjust the base register, offset and element_size_shift
3020 // for a vector load/store when the offset doesn't fit into allowed number of bits.
3021 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
3022 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
3023 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
3024 // If element_size_shift is non-negative at entry, it won't be changed, but offset
3025 // will be checked for appropriate alignment. If negative at entry, it will be
3026 // adjusted based on offset for maximum fit.
3027 // It's assumed that `base` is a multiple of 8.
3028
3029 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
3030
3031 if (element_size_shift >= 0) {
3032 CHECK_LE(element_size_shift, TIMES_8);
3033 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
3034 } else if (IsAligned<kMips64DoublewordSize>(offset)) {
3035 element_size_shift = TIMES_8;
3036 } else if (IsAligned<kMips64WordSize>(offset)) {
3037 element_size_shift = TIMES_4;
3038 } else if (IsAligned<kMips64HalfwordSize>(offset)) {
3039 element_size_shift = TIMES_2;
3040 } else {
3041 element_size_shift = TIMES_1;
3042 }
3043
3044 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
3045 // will take.
3046 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
3047 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
3048 if (low == offset) {
3049 return; // `offset` fits into ld.df/st.df.
3050 }
3051
3052 // First, see if `offset` can be represented as a sum of two signed offsets.
3053 // This can save an instruction.
3054
3055 // Max int16_t that's a multiple of element size.
3056 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
3057 // Max ld.df/st.df offset that's a multiple of element size.
3058 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
3059 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
3060
3061 if (IsInt<16>(offset)) {
3062 Daddiu(AT, base, offset);
3063 offset = 0;
3064 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
3065 Daddiu(AT, base, kMaxDeltaForSimpleAdjustment);
3066 offset -= kMaxDeltaForSimpleAdjustment;
3067 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
3068 Daddiu(AT, base, -kMaxDeltaForSimpleAdjustment);
3069 offset += kMaxDeltaForSimpleAdjustment;
3070 } else {
3071 // Let's treat `offset` as 64-bit to simplify handling of sign
3072 // extensions in the instructions that supply its smaller signed parts.
3073 //
3074 // 16-bit or smaller parts of `offset`:
3075 // |63 top 48|47 hi 32|31 upper 16|15 mid 13-10|12-9 low 0|
3076 //
3077 // Instructions that supply each part as a signed integer addend:
3078 // |dati |dahi |daui |daddiu |ld.df/st.df |
3079 //
3080 // `top` is always 0, so dati isn't used.
3081 // `hi` is 1 when `offset` is close to +2GB and 0 otherwise.
3082 uint64_t tmp = static_cast<uint64_t>(offset) - low; // Exclude `low` from the rest of `offset`
3083 // (accounts for sign of `low`).
3084 tmp += (tmp & (UINT64_C(1) << 15)) << 1; // Account for sign extension in daddiu.
3085 tmp += (tmp & (UINT64_C(1) << 31)) << 1; // Account for sign extension in daui.
3086 int16_t mid = Low16Bits(tmp);
3087 int16_t upper = High16Bits(tmp);
3088 int16_t hi = Low16Bits(High32Bits(tmp));
3089 Daui(AT, base, upper);
3090 if (hi != 0) {
3091 CHECK_EQ(hi, 1);
3092 Dahi(AT, hi);
3093 }
3094 if (mid != 0) {
3095 Daddiu(AT, AT, mid);
3096 }
3097 offset = low;
3098 }
3099 base = AT;
3100 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
3101 CHECK(IsInt<10>(offset >> element_size_shift));
3102}
3103
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003104void Mips64Assembler::LoadFromOffset(LoadOperandType type,
3105 GpuRegister reg,
3106 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003107 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003108 LoadFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003109}
3110
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003111void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type,
3112 FpuRegister reg,
3113 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003114 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003115 LoadFpuFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003116}
3117
3118void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
3119 size_t size) {
3120 Mips64ManagedRegister dst = m_dst.AsMips64();
3121 if (dst.IsNoRegister()) {
3122 CHECK_EQ(0u, size) << dst;
3123 } else if (dst.IsGpuRegister()) {
3124 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003125 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
3126 } else if (size == 8) {
3127 CHECK_EQ(8u, size) << dst;
3128 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
3129 } else {
3130 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
3131 }
3132 } else if (dst.IsFpuRegister()) {
3133 if (size == 4) {
3134 CHECK_EQ(4u, size) << dst;
3135 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
3136 } else if (size == 8) {
3137 CHECK_EQ(8u, size) << dst;
3138 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
3139 } else {
3140 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
3141 }
3142 }
3143}
3144
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003145void Mips64Assembler::StoreToOffset(StoreOperandType type,
3146 GpuRegister reg,
3147 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003148 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003149 StoreToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003150}
3151
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003152void Mips64Assembler::StoreFpuToOffset(StoreOperandType type,
3153 FpuRegister reg,
3154 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003155 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003156 StoreFpuToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003157}
3158
David Srbeckydd973932015-04-07 20:29:48 +01003159static dwarf::Reg DWARFReg(GpuRegister reg) {
3160 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
3161}
3162
Andreas Gampe57b34292015-01-14 15:45:59 -08003163constexpr size_t kFramePointerSize = 8;
3164
Vladimir Marko32248382016-05-19 10:37:24 +01003165void Mips64Assembler::BuildFrame(size_t frame_size,
3166 ManagedRegister method_reg,
3167 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08003168 const ManagedRegisterEntrySpills& entry_spills) {
3169 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003170 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08003171
3172 // Increase frame to required size.
3173 IncreaseFrameSize(frame_size);
3174
3175 // Push callee saves and return address
3176 int stack_offset = frame_size - kFramePointerSize;
3177 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003178 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003179 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
3180 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01003181 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08003182 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003183 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003184 }
3185
3186 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07003187 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08003188
3189 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07003190 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08003191 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01003192 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08003193 ManagedRegisterSpill spill = entry_spills.at(i);
3194 int32_t size = spill.getSize();
3195 if (reg.IsNoRegister()) {
3196 // only increment stack offset.
3197 offset += size;
3198 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003199 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
3200 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003201 offset += size;
3202 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003203 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
3204 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003205 offset += size;
3206 }
3207 }
3208}
3209
3210void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01003211 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003212 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003213 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01003214 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08003215
3216 // Pop callee saves and return address
3217 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
3218 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01003219 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08003220 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003221 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08003222 stack_offset += kFramePointerSize;
3223 }
3224 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003225 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08003226
3227 // Decrease frame to required size.
3228 DecreaseFrameSize(frame_size);
3229
3230 // Then jump to the return address.
3231 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003232 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01003233
3234 // The CFI should be restored for any code that follows the exit block.
3235 cfi_.RestoreState();
3236 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08003237}
3238
3239void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003240 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003241 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003242 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01003243 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08003244}
3245
3246void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003247 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003248 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003249 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01003250 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08003251}
3252
3253void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
3254 Mips64ManagedRegister src = msrc.AsMips64();
3255 if (src.IsNoRegister()) {
3256 CHECK_EQ(0u, size);
3257 } else if (src.IsGpuRegister()) {
3258 CHECK(size == 4 || size == 8) << size;
3259 if (size == 8) {
3260 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3261 } else if (size == 4) {
3262 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
3263 } else {
3264 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
3265 }
3266 } else if (src.IsFpuRegister()) {
3267 CHECK(size == 4 || size == 8) << size;
3268 if (size == 8) {
3269 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
3270 } else if (size == 4) {
3271 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
3272 } else {
3273 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
3274 }
3275 }
3276}
3277
3278void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
3279 Mips64ManagedRegister src = msrc.AsMips64();
3280 CHECK(src.IsGpuRegister());
3281 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
3282}
3283
3284void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
3285 Mips64ManagedRegister src = msrc.AsMips64();
3286 CHECK(src.IsGpuRegister());
3287 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3288}
3289
3290void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
3291 ManagedRegister mscratch) {
3292 Mips64ManagedRegister scratch = mscratch.AsMips64();
3293 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07003294 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08003295 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
3296}
3297
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003298void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
3299 FrameOffset fr_offs,
3300 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003301 Mips64ManagedRegister scratch = mscratch.AsMips64();
3302 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07003303 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003304 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
3305}
3306
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003307void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003308 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
3309}
3310
3311void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
3312 FrameOffset in_off, ManagedRegister mscratch) {
3313 Mips64ManagedRegister src = msrc.AsMips64();
3314 Mips64ManagedRegister scratch = mscratch.AsMips64();
3315 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3316 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
3317 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
3318}
3319
3320void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
3321 return EmitLoad(mdest, SP, src.Int32Value(), size);
3322}
3323
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003324void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003325 return EmitLoad(mdest, S1, src.Int32Value(), size);
3326}
3327
3328void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
3329 Mips64ManagedRegister dest = mdest.AsMips64();
3330 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07003331 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003332}
3333
Mathieu Chartiere401d142015-04-22 13:56:20 -07003334void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01003335 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003336 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07003337 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
3338 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003339 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08003340 if (unpoison_reference) {
3341 MaybeUnpoisonHeapReference(dest.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003342 }
3343}
3344
3345void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003346 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003347 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07003348 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003349 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
3350 base.AsMips64().AsGpuRegister(), offs.Int32Value());
3351}
3352
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003353void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003354 Mips64ManagedRegister dest = mdest.AsMips64();
3355 CHECK(dest.IsGpuRegister());
3356 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
3357}
3358
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003359void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
3360 size_t size ATTRIBUTE_UNUSED) {
3361 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08003362}
3363
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003364void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
3365 size_t size ATTRIBUTE_UNUSED) {
3366 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08003367}
3368
3369void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
3370 Mips64ManagedRegister dest = mdest.AsMips64();
3371 Mips64ManagedRegister src = msrc.AsMips64();
3372 if (!dest.Equals(src)) {
3373 if (dest.IsGpuRegister()) {
3374 CHECK(src.IsGpuRegister()) << src;
3375 Move(dest.AsGpuRegister(), src.AsGpuRegister());
3376 } else if (dest.IsFpuRegister()) {
3377 CHECK(src.IsFpuRegister()) << src;
3378 if (size == 4) {
3379 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
3380 } else if (size == 8) {
3381 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
3382 } else {
3383 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3384 }
3385 }
3386 }
3387}
3388
3389void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
3390 ManagedRegister mscratch) {
3391 Mips64ManagedRegister scratch = mscratch.AsMips64();
3392 CHECK(scratch.IsGpuRegister()) << scratch;
3393 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
3394 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
3395}
3396
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003397void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
3398 ThreadOffset64 thr_offs,
3399 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003400 Mips64ManagedRegister scratch = mscratch.AsMips64();
3401 CHECK(scratch.IsGpuRegister()) << scratch;
3402 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
3403 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
3404}
3405
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003406void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
3407 FrameOffset fr_offs,
3408 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003409 Mips64ManagedRegister scratch = mscratch.AsMips64();
3410 CHECK(scratch.IsGpuRegister()) << scratch;
3411 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
3412 SP, fr_offs.Int32Value());
3413 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
3414 S1, thr_offs.Int32Value());
3415}
3416
3417void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
3418 ManagedRegister mscratch, size_t size) {
3419 Mips64ManagedRegister scratch = mscratch.AsMips64();
3420 CHECK(scratch.IsGpuRegister()) << scratch;
3421 CHECK(size == 4 || size == 8) << size;
3422 if (size == 4) {
3423 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003424 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003425 } else if (size == 8) {
3426 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
3427 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
3428 } else {
3429 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3430 }
3431}
3432
3433void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003434 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003435 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3436 CHECK(size == 4 || size == 8) << size;
3437 if (size == 4) {
3438 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
3439 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003440 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003441 } else if (size == 8) {
3442 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
3443 src_offset.Int32Value());
3444 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
3445 } else {
3446 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3447 }
3448}
3449
3450void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003451 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003452 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3453 CHECK(size == 4 || size == 8) << size;
3454 if (size == 4) {
3455 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003456 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003457 dest_offset.Int32Value());
3458 } else if (size == 8) {
3459 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
3460 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
3461 dest_offset.Int32Value());
3462 } else {
3463 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3464 }
3465}
3466
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003467void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3468 FrameOffset src_base ATTRIBUTE_UNUSED,
3469 Offset src_offset ATTRIBUTE_UNUSED,
3470 ManagedRegister mscratch ATTRIBUTE_UNUSED,
3471 size_t size ATTRIBUTE_UNUSED) {
3472 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003473}
3474
3475void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003476 ManagedRegister src, Offset src_offset,
3477 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003478 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3479 CHECK(size == 4 || size == 8) << size;
3480 if (size == 4) {
3481 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003482 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003483 } else if (size == 8) {
3484 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
3485 src_offset.Int32Value());
3486 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
3487 dest_offset.Int32Value());
3488 } else {
3489 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3490 }
3491}
3492
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003493void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3494 Offset dest_offset ATTRIBUTE_UNUSED,
3495 FrameOffset src ATTRIBUTE_UNUSED,
3496 Offset src_offset ATTRIBUTE_UNUSED,
3497 ManagedRegister mscratch ATTRIBUTE_UNUSED,
3498 size_t size ATTRIBUTE_UNUSED) {
3499 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003500}
3501
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003502void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003503 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003504 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003505}
3506
3507void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003508 FrameOffset handle_scope_offset,
3509 ManagedRegister min_reg,
3510 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003511 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
3512 Mips64ManagedRegister in_reg = min_reg.AsMips64();
3513 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
3514 CHECK(out_reg.IsGpuRegister()) << out_reg;
3515 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003516 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08003517 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
3518 // the address in the handle scope holding the reference.
3519 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
3520 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07003521 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003522 SP, handle_scope_offset.Int32Value());
3523 in_reg = out_reg;
3524 }
3525 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003526 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08003527 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07003528 Beqzc(in_reg.AsGpuRegister(), &null_arg);
3529 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
3530 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003531 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003532 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003533 }
3534}
3535
3536void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003537 FrameOffset handle_scope_offset,
3538 ManagedRegister mscratch,
3539 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003540 Mips64ManagedRegister scratch = mscratch.AsMips64();
3541 CHECK(scratch.IsGpuRegister()) << scratch;
3542 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003543 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07003544 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08003545 handle_scope_offset.Int32Value());
3546 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
3547 // the address in the handle scope holding the reference.
3548 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07003549 Beqzc(scratch.AsGpuRegister(), &null_arg);
3550 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
3551 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003552 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003553 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003554 }
3555 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
3556}
3557
3558// Given a handle scope entry, load the associated reference.
3559void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003560 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003561 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
3562 Mips64ManagedRegister in_reg = min_reg.AsMips64();
3563 CHECK(out_reg.IsGpuRegister()) << out_reg;
3564 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003565 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08003566 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003567 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08003568 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07003569 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003570 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
3571 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003572 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003573}
3574
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003575void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
3576 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003577 // TODO: not validating references
3578}
3579
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003580void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
3581 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003582 // TODO: not validating references
3583}
3584
3585void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
3586 Mips64ManagedRegister base = mbase.AsMips64();
3587 Mips64ManagedRegister scratch = mscratch.AsMips64();
3588 CHECK(base.IsGpuRegister()) << base;
3589 CHECK(scratch.IsGpuRegister()) << scratch;
3590 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
3591 base.AsGpuRegister(), offset.Int32Value());
3592 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003593 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08003594 // TODO: place reference map on call
3595}
3596
3597void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
3598 Mips64ManagedRegister scratch = mscratch.AsMips64();
3599 CHECK(scratch.IsGpuRegister()) << scratch;
3600 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07003601 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003602 SP, base.Int32Value());
3603 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
3604 scratch.AsGpuRegister(), offset.Int32Value());
3605 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003606 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08003607 // TODO: place reference map on call
3608}
3609
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003610void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
3611 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003612 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003613}
3614
3615void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
3616 Move(tr.AsMips64().AsGpuRegister(), S1);
3617}
3618
3619void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003620 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003621 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
3622}
3623
3624void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
3625 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003626 exception_blocks_.emplace_back(scratch, stack_adjust);
3627 LoadFromOffset(kLoadDoubleword,
3628 scratch.AsGpuRegister(),
3629 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07003630 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003631 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08003632}
3633
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003634void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
3635 Bind(exception->Entry());
3636 if (exception->stack_adjust_ != 0) { // Fix up the frame.
3637 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08003638 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003639 // Pass exception object as argument.
3640 // Don't care about preserving A0 as this call won't return.
3641 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
3642 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003643 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003644 LoadFromOffset(kLoadDoubleword,
3645 T9,
3646 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07003647 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003648 Jr(T9);
3649 Nop();
3650
Andreas Gampe57b34292015-01-14 15:45:59 -08003651 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003652 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08003653}
3654
3655} // namespace mips64
3656} // namespace art