blob: 70313ca093c46b15a514ed4931446dff4ed90afa [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"
David Sehr1ce2b3b2018-04-05 11:02:03 -070021#include "base/memory_region.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080022#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070023#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080024#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
Andreas Gampec55bb392018-09-21 00:02:02 +000055 using DelayedAdvancePC = DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC;
Alexey Frunzea0e87b02015-09-24 22:57:20 -070056 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
Lena Djokica556e6b2017-12-13 12:09:42 +0100433void Mips64Assembler::Ins(GpuRegister rd, GpuRegister rt, int pos, int size) {
434 CHECK(IsUint<5>(pos)) << pos;
435 CHECK(IsUint<5>(size - 1)) << size;
436 CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
437 EmitR(0x1f, rt, rd, static_cast<GpuRegister>(pos + size - 1), pos, 0x04);
438}
439
440void Mips64Assembler::Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size) {
441 CHECK(IsUint<5>(pos)) << pos;
442 CHECK(2 <= size && size <= 64) << size;
443 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
444 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos, 0x5);
445}
446
Lazar Trsicd9672662015-09-03 17:33:01 +0200447void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
448 CHECK(IsUint<5>(pos - 32)) << pos;
449 CHECK(IsUint<5>(size - 1)) << size;
450 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
451 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800452}
453
Lena Djokica556e6b2017-12-13 12:09:42 +0100454void Mips64Assembler::Dins(GpuRegister rt, GpuRegister rs, int pos, int size) {
455 CHECK(IsUint<5>(pos)) << pos;
456 CHECK(IsUint<5>(size - 1)) << size;
457 CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
458 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 1), pos, 0x7);
459}
460
461void Mips64Assembler::DblIns(GpuRegister rt, GpuRegister rs, int pos, int size) {
462 if (pos >= 32) {
463 Dinsu(rt, rs, pos, size);
464 } else if ((static_cast<int64_t>(pos) + size - 1) >= 32) {
465 Dinsm(rt, rs, pos, size);
466 } else {
467 Dins(rt, rs, pos, size);
468 }
469}
470
Chris Larsene3660592016-11-09 11:13:42 -0800471void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
472 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
473 int sa = saPlusOne - 1;
474 EmitR(0x0, rs, rt, rd, sa, 0x05);
475}
476
477void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
478 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
479 int sa = saPlusOne - 1;
480 EmitR(0x0, rs, rt, rd, sa, 0x15);
481}
482
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700483void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
484 EmitRtd(0x1f, rt, rd, 2, 0x20);
485}
486
487void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200488 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700489 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
490}
491
492void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200493 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700494 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
495}
496
497void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200498 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700499 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
500}
501
502void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200503 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700504 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
505}
506
Alexey Frunze4dda3372015-06-01 18:31:49 -0700507void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
508 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
509}
510
511void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
512 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
513}
514
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700515void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
516 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
517}
518
Alexey Frunze4dda3372015-06-01 18:31:49 -0700519void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
520 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
521}
522
523void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800524 EmitR(0, rs, rt, rd, 0, 0x04);
525}
526
Chris Larsen9aebff22015-09-22 17:54:15 -0700527void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
528 EmitR(0, rs, rt, rd, 1, 0x06);
529}
530
Alexey Frunze4dda3372015-06-01 18:31:49 -0700531void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800532 EmitR(0, rs, rt, rd, 0, 0x06);
533}
534
Alexey Frunze4dda3372015-06-01 18:31:49 -0700535void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800536 EmitR(0, rs, rt, rd, 0, 0x07);
537}
538
Alexey Frunze4dda3372015-06-01 18:31:49 -0700539void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
540 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
541}
542
543void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
544 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
545}
546
Chris Larsen9aebff22015-09-22 17:54:15 -0700547void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
548 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
549}
550
Alexey Frunze4dda3372015-06-01 18:31:49 -0700551void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
552 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
553}
554
555void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
556 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
557}
558
559void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
560 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
561}
562
Chris Larsen9aebff22015-09-22 17:54:15 -0700563void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
564 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
565}
566
Alexey Frunze4dda3372015-06-01 18:31:49 -0700567void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
568 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
569}
570
571void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
572 EmitR(0, rs, rt, rd, 0, 0x14);
573}
574
575void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
576 EmitR(0, rs, rt, rd, 0, 0x16);
577}
578
Chris Larsen9aebff22015-09-22 17:54:15 -0700579void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
580 EmitR(0, rs, rt, rd, 1, 0x16);
581}
582
Alexey Frunze4dda3372015-06-01 18:31:49 -0700583void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
584 EmitR(0, rs, rt, rd, 0, 0x17);
585}
586
Andreas Gampe57b34292015-01-14 15:45:59 -0800587void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
588 EmitI(0x20, rs, rt, imm16);
589}
590
591void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
592 EmitI(0x21, rs, rt, imm16);
593}
594
595void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
596 EmitI(0x23, rs, rt, imm16);
597}
598
599void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
600 EmitI(0x37, rs, rt, imm16);
601}
602
603void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
604 EmitI(0x24, rs, rt, imm16);
605}
606
607void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
608 EmitI(0x25, rs, rt, imm16);
609}
610
Douglas Leungd90957f2015-04-30 19:22:49 -0700611void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
612 EmitI(0x27, rs, rt, imm16);
613}
614
Alexey Frunze19f6c692016-11-30 19:19:55 -0800615void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
616 CHECK(IsUint<19>(imm19)) << imm19;
617 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
618}
619
620void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
621 CHECK(IsUint<19>(imm19)) << imm19;
622 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
623}
624
625void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
626 CHECK(IsUint<18>(imm18)) << imm18;
627 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
628}
629
Andreas Gampe57b34292015-01-14 15:45:59 -0800630void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
631 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
632}
633
Alexey Frunze0960ac52016-12-20 17:24:59 -0800634void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
635 EmitI(0xf, rs, rt, imm16);
636}
637
Alexey Frunzec061de12017-02-14 13:27:23 -0800638void Mips64Assembler::Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
639 CHECK_NE(rs, ZERO);
640 EmitI(0x1d, rs, rt, imm16);
641}
642
Alexey Frunze4dda3372015-06-01 18:31:49 -0700643void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
644 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
645}
646
647void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
648 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
649}
650
651void Mips64Assembler::Sync(uint32_t stype) {
652 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
653 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
654}
655
Andreas Gampe57b34292015-01-14 15:45:59 -0800656void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
657 EmitI(0x28, rs, rt, imm16);
658}
659
660void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
661 EmitI(0x29, rs, rt, imm16);
662}
663
664void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
665 EmitI(0x2b, rs, rt, imm16);
666}
667
668void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
669 EmitI(0x3f, rs, rt, imm16);
670}
671
672void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
673 EmitR(0, rs, rt, rd, 0, 0x2a);
674}
675
676void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
677 EmitR(0, rs, rt, rd, 0, 0x2b);
678}
679
680void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
681 EmitI(0xa, rs, rt, imm16);
682}
683
684void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
685 EmitI(0xb, rs, rt, imm16);
686}
687
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700688void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
689 EmitR(0, rs, rt, rd, 0, 0x35);
690}
691
692void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
693 EmitR(0, rs, rt, rd, 0, 0x37);
694}
695
696void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
697 EmitRsd(0, rs, rd, 0x01, 0x10);
698}
699
700void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
701 EmitRsd(0, rs, rd, 0x01, 0x11);
702}
703
704void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
705 EmitRsd(0, rs, rd, 0x01, 0x12);
706}
707
708void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
709 EmitRsd(0, rs, rd, 0x01, 0x13);
710}
711
Alexey Frunze4dda3372015-06-01 18:31:49 -0700712void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
713 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800714}
715
716void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700717 Jalr(RA, rs);
718}
719
720void Mips64Assembler::Jr(GpuRegister rs) {
721 Jalr(ZERO, rs);
722}
723
724void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
725 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
726}
727
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700728void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
729 CHECK(IsUint<19>(imm19)) << imm19;
730 EmitI21(0x3B, rs, imm19);
731}
732
733void Mips64Assembler::Bc(uint32_t imm26) {
734 EmitI26(0x32, imm26);
735}
736
Alexey Frunze19f6c692016-11-30 19:19:55 -0800737void Mips64Assembler::Balc(uint32_t imm26) {
738 EmitI26(0x3A, imm26);
739}
740
Alexey Frunze4dda3372015-06-01 18:31:49 -0700741void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
742 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
743}
744
745void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
746 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
747}
748
749void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
750 CHECK_NE(rs, ZERO);
751 CHECK_NE(rt, ZERO);
752 CHECK_NE(rs, rt);
753 EmitI(0x17, rs, rt, imm16);
754}
755
756void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
757 CHECK_NE(rt, ZERO);
758 EmitI(0x17, rt, rt, imm16);
759}
760
761void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
762 CHECK_NE(rt, ZERO);
763 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
764}
765
766void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
767 CHECK_NE(rs, ZERO);
768 CHECK_NE(rt, ZERO);
769 CHECK_NE(rs, rt);
770 EmitI(0x16, rs, rt, imm16);
771}
772
773void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
774 CHECK_NE(rt, ZERO);
775 EmitI(0x16, rt, rt, imm16);
776}
777
778void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
779 CHECK_NE(rt, ZERO);
780 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
781}
782
783void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
784 CHECK_NE(rs, ZERO);
785 CHECK_NE(rt, ZERO);
786 CHECK_NE(rs, rt);
787 EmitI(0x7, rs, rt, imm16);
788}
789
790void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
791 CHECK_NE(rs, ZERO);
792 CHECK_NE(rt, ZERO);
793 CHECK_NE(rs, rt);
794 EmitI(0x6, rs, rt, imm16);
795}
796
797void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
798 CHECK_NE(rs, ZERO);
799 CHECK_NE(rt, ZERO);
800 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700801 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700802}
803
804void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
805 CHECK_NE(rs, ZERO);
806 CHECK_NE(rt, ZERO);
807 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700808 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700809}
810
811void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
812 CHECK_NE(rs, ZERO);
813 EmitI21(0x36, rs, imm21);
814}
815
816void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
817 CHECK_NE(rs, ZERO);
818 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800819}
820
Alexey Frunze299a9392015-12-08 16:08:02 -0800821void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
822 EmitFI(0x11, 0x9, ft, imm16);
823}
824
825void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
826 EmitFI(0x11, 0xD, ft, imm16);
827}
828
Alexey Frunze0cab6562017-07-25 15:19:36 -0700829void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
830 EmitI(0x4, rs, rt, imm16);
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700831}
832
Alexey Frunze0cab6562017-07-25 15:19:36 -0700833void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
834 EmitI(0x5, rs, rt, imm16);
835}
836
837void Mips64Assembler::Beqz(GpuRegister rt, uint16_t imm16) {
838 Beq(rt, ZERO, imm16);
839}
840
841void Mips64Assembler::Bnez(GpuRegister rt, uint16_t imm16) {
842 Bne(rt, ZERO, imm16);
843}
844
845void Mips64Assembler::Bltz(GpuRegister rt, uint16_t imm16) {
846 EmitI(0x1, rt, static_cast<GpuRegister>(0), imm16);
847}
848
849void Mips64Assembler::Bgez(GpuRegister rt, uint16_t imm16) {
850 EmitI(0x1, rt, static_cast<GpuRegister>(0x1), imm16);
851}
852
853void Mips64Assembler::Blez(GpuRegister rt, uint16_t imm16) {
854 EmitI(0x6, rt, static_cast<GpuRegister>(0), imm16);
855}
856
857void Mips64Assembler::Bgtz(GpuRegister rt, uint16_t imm16) {
858 EmitI(0x7, rt, static_cast<GpuRegister>(0), imm16);
859}
860
861void Mips64Assembler::EmitBcondR6(BranchCondition cond,
862 GpuRegister rs,
863 GpuRegister rt,
864 uint32_t imm16_21) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700865 switch (cond) {
866 case kCondLT:
867 Bltc(rs, rt, imm16_21);
868 break;
869 case kCondGE:
870 Bgec(rs, rt, imm16_21);
871 break;
872 case kCondLE:
873 Bgec(rt, rs, imm16_21);
874 break;
875 case kCondGT:
876 Bltc(rt, rs, imm16_21);
877 break;
878 case kCondLTZ:
879 CHECK_EQ(rt, ZERO);
880 Bltzc(rs, imm16_21);
881 break;
882 case kCondGEZ:
883 CHECK_EQ(rt, ZERO);
884 Bgezc(rs, imm16_21);
885 break;
886 case kCondLEZ:
887 CHECK_EQ(rt, ZERO);
888 Blezc(rs, imm16_21);
889 break;
890 case kCondGTZ:
891 CHECK_EQ(rt, ZERO);
892 Bgtzc(rs, imm16_21);
893 break;
894 case kCondEQ:
895 Beqc(rs, rt, imm16_21);
896 break;
897 case kCondNE:
898 Bnec(rs, rt, imm16_21);
899 break;
900 case kCondEQZ:
901 CHECK_EQ(rt, ZERO);
902 Beqzc(rs, imm16_21);
903 break;
904 case kCondNEZ:
905 CHECK_EQ(rt, ZERO);
906 Bnezc(rs, imm16_21);
907 break;
908 case kCondLTU:
909 Bltuc(rs, rt, imm16_21);
910 break;
911 case kCondGEU:
912 Bgeuc(rs, rt, imm16_21);
913 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800914 case kCondF:
915 CHECK_EQ(rt, ZERO);
916 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
917 break;
918 case kCondT:
919 CHECK_EQ(rt, ZERO);
920 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
921 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700922 case kUncond:
923 LOG(FATAL) << "Unexpected branch condition " << cond;
924 UNREACHABLE();
925 }
926}
927
Alexey Frunze0cab6562017-07-25 15:19:36 -0700928void Mips64Assembler::EmitBcondR2(BranchCondition cond,
929 GpuRegister rs,
930 GpuRegister rt,
931 uint16_t imm16) {
932 switch (cond) {
933 case kCondLTZ:
934 CHECK_EQ(rt, ZERO);
935 Bltz(rs, imm16);
936 break;
937 case kCondGEZ:
938 CHECK_EQ(rt, ZERO);
939 Bgez(rs, imm16);
940 break;
941 case kCondLEZ:
942 CHECK_EQ(rt, ZERO);
943 Blez(rs, imm16);
944 break;
945 case kCondGTZ:
946 CHECK_EQ(rt, ZERO);
947 Bgtz(rs, imm16);
948 break;
949 case kCondEQ:
950 Beq(rs, rt, imm16);
951 break;
952 case kCondNE:
953 Bne(rs, rt, imm16);
954 break;
955 case kCondEQZ:
956 CHECK_EQ(rt, ZERO);
957 Beqz(rs, imm16);
958 break;
959 case kCondNEZ:
960 CHECK_EQ(rt, ZERO);
961 Bnez(rs, imm16);
962 break;
963 case kCondF:
964 case kCondT:
965 case kCondLT:
966 case kCondGE:
967 case kCondLE:
968 case kCondGT:
969 case kCondLTU:
970 case kCondGEU:
971 case kUncond:
972 LOG(FATAL) << "Unexpected branch condition " << cond;
973 UNREACHABLE();
974 }
975}
976
Andreas Gampe57b34292015-01-14 15:45:59 -0800977void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
978 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
979}
980
981void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
982 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
983}
984
985void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
986 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
987}
988
989void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
990 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
991}
992
993void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700994 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800995}
996
997void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700998 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800999}
1000
1001void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001002 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -08001003}
1004
1005void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001006 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -08001007}
1008
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001009void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
1010 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
1011}
1012
1013void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
1014 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
1015}
1016
1017void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
1018 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
1019}
1020
1021void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
1022 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
1023}
1024
Andreas Gampe57b34292015-01-14 15:45:59 -08001025void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
1026 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
1027}
1028
1029void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001030 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
1031}
1032
1033void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
1034 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
1035}
1036
1037void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
1038 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
1039}
1040
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001041void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
1042 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
1043}
1044
1045void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
1046 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
1047}
1048
1049void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
1050 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
1051}
1052
1053void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
1054 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
1055}
1056
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001057void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
1058 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
1059}
1060
1061void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
1062 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
1063}
1064
1065void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
1066 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
1067}
1068
1069void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
1070 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
1071}
1072
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001073void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
1074 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
1075}
1076
1077void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
1078 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
1079}
1080
1081void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
1082 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
1083}
1084
1085void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
1086 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
1087}
1088
1089void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
1090 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
1091}
1092
1093void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
1094 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
1095}
1096
1097void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
1098 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
1099}
1100
1101void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
1102 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
1103}
1104
1105void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1106 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
1107}
1108
1109void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1110 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
1111}
1112
Goran Jakovljevic2dec9272017-08-02 11:41:26 +02001113void Mips64Assembler::SeleqzS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1114 EmitFR(0x11, 0x10, ft, fs, fd, 0x14);
1115}
1116
1117void Mips64Assembler::SeleqzD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1118 EmitFR(0x11, 0x11, ft, fs, fd, 0x14);
1119}
1120
1121void Mips64Assembler::SelnezS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1122 EmitFR(0x11, 0x10, ft, fs, fd, 0x17);
1123}
1124
1125void Mips64Assembler::SelnezD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1126 EmitFR(0x11, 0x11, ft, fs, fd, 0x17);
1127}
1128
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001129void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
1130 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
1131}
1132
1133void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
1134 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
1135}
1136
1137void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
1138 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
1139}
1140
1141void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
1142 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
1143}
1144
1145void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1146 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1147}
1148
1149void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1150 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1151}
1152
1153void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1154 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1155}
1156
1157void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1158 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1159}
1160
Alexey Frunze299a9392015-12-08 16:08:02 -08001161void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1162 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1163}
1164
1165void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1166 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1167}
1168
1169void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1170 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1171}
1172
1173void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1174 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1175}
1176
1177void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1178 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1179}
1180
1181void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1182 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1183}
1184
1185void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1186 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1187}
1188
1189void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1190 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1191}
1192
1193void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1194 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1195}
1196
1197void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1198 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1199}
1200
1201void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1202 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1203}
1204
1205void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1206 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1207}
1208
1209void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1210 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1211}
1212
1213void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1214 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1215}
1216
1217void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1218 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1219}
1220
1221void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1222 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1223}
1224
1225void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1226 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1227}
1228
1229void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1230 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1231}
1232
1233void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1234 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1235}
1236
1237void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1238 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1239}
1240
Alexey Frunze4dda3372015-06-01 18:31:49 -07001241void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
1242 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
1243}
1244
1245void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
1246 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
1247}
1248
1249void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
1250 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
1251}
1252
1253void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
1254 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -08001255}
1256
Chris Larsen51417632015-10-02 13:24:25 -07001257void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
1258 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
1259}
1260
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001261void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
1262 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
1263}
1264
Andreas Gampe57b34292015-01-14 15:45:59 -08001265void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
1266 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1267}
1268
Lazar Trsicd9672662015-09-03 17:33:01 +02001269void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1270 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1271}
1272
Alexey Frunze4dda3372015-06-01 18:31:49 -07001273void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1274 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1275}
1276
Lazar Trsicd9672662015-09-03 17:33:01 +02001277void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1278 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1279}
1280
Alexey Frunze4dda3372015-06-01 18:31:49 -07001281void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1282 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1283}
1284
1285void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1286 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001287}
1288
1289void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1290 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1291}
1292
1293void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1294 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1295}
1296
1297void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1298 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1299}
1300
1301void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1302 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1303}
1304
1305void Mips64Assembler::Break() {
1306 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1307 static_cast<GpuRegister>(0), 0, 0xD);
1308}
1309
1310void Mips64Assembler::Nop() {
1311 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1312 static_cast<GpuRegister>(0), 0, 0x0);
1313}
1314
Alexey Frunze4dda3372015-06-01 18:31:49 -07001315void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1316 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001317}
1318
Alexey Frunze4dda3372015-06-01 18:31:49 -07001319void Mips64Assembler::Clear(GpuRegister rd) {
1320 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001321}
1322
Alexey Frunze4dda3372015-06-01 18:31:49 -07001323void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1324 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001325}
1326
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001327void Mips64Assembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001328 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001329 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e);
1330}
1331
1332void Mips64Assembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001333 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001334 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e);
1335}
1336
1337void Mips64Assembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001338 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001339 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e);
1340}
1341
1342void Mips64Assembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001343 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001344 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e);
1345}
1346
1347void Mips64Assembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001348 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001349 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe);
1350}
1351
1352void Mips64Assembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001353 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001354 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe);
1355}
1356
1357void Mips64Assembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001358 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001359 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe);
1360}
1361
1362void Mips64Assembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001363 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001364 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe);
1365}
1366
1367void Mips64Assembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001368 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001369 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe);
1370}
1371
1372void Mips64Assembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001373 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001374 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe);
1375}
1376
1377void Mips64Assembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001378 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001379 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe);
1380}
1381
1382void Mips64Assembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001383 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001384 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe);
1385}
1386
Lena Djokic72aba712017-10-30 15:47:20 +01001387void Mips64Assembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1388 CHECK(HasMsa());
1389 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11);
1390}
1391
1392void Mips64Assembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1393 CHECK(HasMsa());
1394 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11);
1395}
1396
1397void Mips64Assembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1398 CHECK(HasMsa());
1399 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11);
1400}
1401
1402void Mips64Assembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1403 CHECK(HasMsa());
1404 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11);
1405}
1406
1407void Mips64Assembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1408 CHECK(HasMsa());
1409 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11);
1410}
1411
1412void Mips64Assembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1413 CHECK(HasMsa());
1414 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11);
1415}
1416
1417void Mips64Assembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1418 CHECK(HasMsa());
1419 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11);
1420}
1421
1422void Mips64Assembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1423 CHECK(HasMsa());
1424 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11);
1425}
1426
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001427void Mips64Assembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001428 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001429 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12);
1430}
1431
1432void Mips64Assembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001433 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001434 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12);
1435}
1436
1437void Mips64Assembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001438 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001439 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12);
1440}
1441
1442void Mips64Assembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001443 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001444 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12);
1445}
1446
1447void Mips64Assembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001448 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001449 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12);
1450}
1451
1452void Mips64Assembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001453 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001454 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12);
1455}
1456
1457void Mips64Assembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001458 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001459 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12);
1460}
1461
1462void Mips64Assembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001463 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001464 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12);
1465}
1466
1467void Mips64Assembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001468 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001469 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12);
1470}
1471
1472void Mips64Assembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001473 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001474 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12);
1475}
1476
1477void Mips64Assembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001478 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001479 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12);
1480}
1481
1482void Mips64Assembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001483 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001484 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12);
1485}
1486
1487void Mips64Assembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001488 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001489 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12);
1490}
1491
1492void Mips64Assembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001493 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001494 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12);
1495}
1496
1497void Mips64Assembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001498 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001499 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12);
1500}
1501
1502void Mips64Assembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001503 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001504 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12);
1505}
1506
1507void Mips64Assembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001508 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001509 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12);
1510}
1511
1512void Mips64Assembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001513 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001514 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12);
1515}
1516
1517void Mips64Assembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001518 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001519 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12);
1520}
1521
1522void Mips64Assembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001523 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001524 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12);
1525}
1526
Goran Jakovljevic80248d72017-04-20 11:55:47 +02001527void Mips64Assembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1528 CHECK(HasMsa());
1529 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10);
1530}
1531
1532void Mips64Assembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1533 CHECK(HasMsa());
1534 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10);
1535}
1536
1537void Mips64Assembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1538 CHECK(HasMsa());
1539 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10);
1540}
1541
1542void Mips64Assembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1543 CHECK(HasMsa());
1544 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10);
1545}
1546
1547void Mips64Assembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1548 CHECK(HasMsa());
1549 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10);
1550}
1551
1552void Mips64Assembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1553 CHECK(HasMsa());
1554 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10);
1555}
1556
1557void Mips64Assembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1558 CHECK(HasMsa());
1559 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10);
1560}
1561
1562void Mips64Assembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1563 CHECK(HasMsa());
1564 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10);
1565}
1566
1567void Mips64Assembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1568 CHECK(HasMsa());
1569 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10);
1570}
1571
1572void Mips64Assembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1573 CHECK(HasMsa());
1574 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10);
1575}
1576
1577void Mips64Assembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1578 CHECK(HasMsa());
1579 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10);
1580}
1581
1582void Mips64Assembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1583 CHECK(HasMsa());
1584 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10);
1585}
1586
1587void Mips64Assembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1588 CHECK(HasMsa());
1589 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10);
1590}
1591
1592void Mips64Assembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1593 CHECK(HasMsa());
1594 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10);
1595}
1596
1597void Mips64Assembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1598 CHECK(HasMsa());
1599 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10);
1600}
1601
1602void Mips64Assembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1603 CHECK(HasMsa());
1604 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10);
1605}
1606
1607void Mips64Assembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1608 CHECK(HasMsa());
1609 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10);
1610}
1611
1612void Mips64Assembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1613 CHECK(HasMsa());
1614 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10);
1615}
1616
1617void Mips64Assembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1618 CHECK(HasMsa());
1619 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10);
1620}
1621
1622void Mips64Assembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1623 CHECK(HasMsa());
1624 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10);
1625}
1626
Goran Jakovljevic658263e2017-06-07 09:35:53 +02001627void Mips64Assembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1628 CHECK(HasMsa());
1629 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe);
1630}
1631
1632void Mips64Assembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1633 CHECK(HasMsa());
1634 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe);
1635}
1636
1637void Mips64Assembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1638 CHECK(HasMsa());
1639 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe);
1640}
1641
1642void Mips64Assembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1643 CHECK(HasMsa());
1644 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe);
1645}
1646
1647void Mips64Assembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1648 CHECK(HasMsa());
1649 EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe);
1650}
1651
1652void Mips64Assembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1653 CHECK(HasMsa());
1654 EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe);
1655}
1656
1657void Mips64Assembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1658 CHECK(HasMsa());
1659 EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe);
1660}
1661
1662void Mips64Assembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1663 CHECK(HasMsa());
1664 EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe);
1665}
1666
1667void Mips64Assembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1668 CHECK(HasMsa());
1669 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe);
1670}
1671
1672void Mips64Assembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1673 CHECK(HasMsa());
1674 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe);
1675}
1676
1677void Mips64Assembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1678 CHECK(HasMsa());
1679 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe);
1680}
1681
1682void Mips64Assembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1683 CHECK(HasMsa());
1684 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe);
1685}
1686
1687void Mips64Assembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1688 CHECK(HasMsa());
1689 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe);
1690}
1691
1692void Mips64Assembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1693 CHECK(HasMsa());
1694 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe);
1695}
1696
1697void Mips64Assembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1698 CHECK(HasMsa());
1699 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe);
1700}
1701
1702void Mips64Assembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1703 CHECK(HasMsa());
1704 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe);
1705}
1706
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001707void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001708 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001709 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b);
1710}
1711
1712void Mips64Assembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001713 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001714 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b);
1715}
1716
1717void Mips64Assembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001718 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001719 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b);
1720}
1721
1722void Mips64Assembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001723 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001724 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b);
1725}
1726
1727void Mips64Assembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001728 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001729 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b);
1730}
1731
1732void Mips64Assembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001733 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001734 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b);
1735}
1736
1737void Mips64Assembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001738 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001739 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b);
1740}
1741
1742void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001743 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001744 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b);
1745}
1746
Goran Jakovljevic658263e2017-06-07 09:35:53 +02001747void Mips64Assembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1748 CHECK(HasMsa());
1749 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b);
1750}
1751
1752void Mips64Assembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1753 CHECK(HasMsa());
1754 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b);
1755}
1756
1757void Mips64Assembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1758 CHECK(HasMsa());
1759 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b);
1760}
1761
1762void Mips64Assembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1763 CHECK(HasMsa());
1764 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b);
1765}
1766
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001767void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001768 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001769 EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e);
1770}
1771
1772void Mips64Assembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001773 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001774 EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e);
1775}
1776
1777void Mips64Assembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001778 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001779 EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e);
1780}
1781
1782void Mips64Assembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001783 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001784 EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e);
1785}
1786
1787void Mips64Assembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001788 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001789 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd);
1790}
1791
1792void Mips64Assembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001793 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001794 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd);
1795}
1796
1797void Mips64Assembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001798 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001799 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd);
1800}
1801
1802void Mips64Assembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001803 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001804 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd);
1805}
1806
1807void Mips64Assembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001808 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001809 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd);
1810}
1811
1812void Mips64Assembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001813 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001814 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd);
1815}
1816
1817void Mips64Assembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001818 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001819 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd);
1820}
1821
1822void Mips64Assembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001823 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001824 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd);
1825}
1826
1827void Mips64Assembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001828 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001829 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd);
1830}
1831
1832void Mips64Assembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001833 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001834 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd);
1835}
1836
1837void Mips64Assembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001838 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001839 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd);
1840}
1841
1842void Mips64Assembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001843 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001844 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd);
1845}
1846
1847void Mips64Assembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001848 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001849 CHECK(IsUint<3>(shamt3)) << shamt3;
1850 EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1851}
1852
1853void Mips64Assembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001854 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001855 CHECK(IsUint<4>(shamt4)) << shamt4;
1856 EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1857}
1858
1859void Mips64Assembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001860 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001861 CHECK(IsUint<5>(shamt5)) << shamt5;
1862 EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1863}
1864
1865void Mips64Assembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001866 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001867 CHECK(IsUint<6>(shamt6)) << shamt6;
1868 EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1869}
1870
1871void Mips64Assembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001872 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001873 CHECK(IsUint<3>(shamt3)) << shamt3;
1874 EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1875}
1876
1877void Mips64Assembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001878 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001879 CHECK(IsUint<4>(shamt4)) << shamt4;
1880 EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1881}
1882
1883void Mips64Assembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001884 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001885 CHECK(IsUint<5>(shamt5)) << shamt5;
1886 EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1887}
1888
1889void Mips64Assembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001890 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001891 CHECK(IsUint<6>(shamt6)) << shamt6;
1892 EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1893}
1894
1895void Mips64Assembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001896 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001897 CHECK(IsUint<3>(shamt3)) << shamt3;
1898 EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1899}
1900
1901void Mips64Assembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001902 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001903 CHECK(IsUint<4>(shamt4)) << shamt4;
1904 EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1905}
1906
1907void Mips64Assembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001908 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001909 CHECK(IsUint<5>(shamt5)) << shamt5;
1910 EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1911}
1912
1913void Mips64Assembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001914 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001915 CHECK(IsUint<6>(shamt6)) << shamt6;
1916 EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1917}
1918
1919void Mips64Assembler::MoveV(VectorRegister wd, VectorRegister ws) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001920 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001921 EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19);
1922}
1923
1924void Mips64Assembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001925 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001926 CHECK(IsUint<4>(n4)) << n4;
1927 EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19);
1928}
1929
1930void Mips64Assembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001931 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001932 CHECK(IsUint<3>(n3)) << n3;
1933 EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19);
1934}
1935
1936void Mips64Assembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001937 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001938 CHECK(IsUint<2>(n2)) << n2;
1939 EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19);
1940}
1941
1942void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01001943 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001944 CHECK(IsUint<1>(n1)) << n1;
1945 EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19);
1946}
1947
Lena Djokic3309c012017-10-13 14:34:32 +02001948void Mips64Assembler::Copy_sB(GpuRegister rd, VectorRegister ws, int n4) {
1949 CHECK(HasMsa());
1950 CHECK(IsUint<4>(n4)) << n4;
1951 EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19);
1952}
1953
1954void Mips64Assembler::Copy_sH(GpuRegister rd, VectorRegister ws, int n3) {
1955 CHECK(HasMsa());
1956 CHECK(IsUint<3>(n3)) << n3;
1957 EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19);
1958}
1959
1960void Mips64Assembler::Copy_sW(GpuRegister rd, VectorRegister ws, int n2) {
1961 CHECK(HasMsa());
1962 CHECK(IsUint<2>(n2)) << n2;
1963 EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19);
1964}
1965
1966void Mips64Assembler::Copy_sD(GpuRegister rd, VectorRegister ws, int n1) {
1967 CHECK(HasMsa());
1968 CHECK(IsUint<1>(n1)) << n1;
1969 EmitMsaELM(0x2, n1 | kMsaDfNDoublewordMask, ws, static_cast<VectorRegister>(rd), 0x19);
1970}
1971
1972void Mips64Assembler::Copy_uB(GpuRegister rd, VectorRegister ws, int n4) {
1973 CHECK(HasMsa());
1974 CHECK(IsUint<4>(n4)) << n4;
1975 EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19);
1976}
1977
1978void Mips64Assembler::Copy_uH(GpuRegister rd, VectorRegister ws, int n3) {
1979 CHECK(HasMsa());
1980 CHECK(IsUint<3>(n3)) << n3;
1981 EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19);
1982}
1983
1984void Mips64Assembler::Copy_uW(GpuRegister rd, VectorRegister ws, int n2) {
1985 CHECK(HasMsa());
1986 CHECK(IsUint<2>(n2)) << n2;
1987 EmitMsaELM(0x3, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19);
1988}
1989
1990void Mips64Assembler::InsertB(VectorRegister wd, GpuRegister rs, int n4) {
1991 CHECK(HasMsa());
1992 CHECK(IsUint<4>(n4)) << n4;
1993 EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19);
1994}
1995
1996void Mips64Assembler::InsertH(VectorRegister wd, GpuRegister rs, int n3) {
1997 CHECK(HasMsa());
1998 CHECK(IsUint<3>(n3)) << n3;
1999 EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19);
2000}
2001
2002void Mips64Assembler::InsertW(VectorRegister wd, GpuRegister rs, int n2) {
2003 CHECK(HasMsa());
2004 CHECK(IsUint<2>(n2)) << n2;
2005 EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19);
2006}
2007
2008void Mips64Assembler::InsertD(VectorRegister wd, GpuRegister rs, int n1) {
2009 CHECK(HasMsa());
2010 CHECK(IsUint<1>(n1)) << n1;
2011 EmitMsaELM(0x4, n1 | kMsaDfNDoublewordMask, static_cast<VectorRegister>(rs), wd, 0x19);
2012}
2013
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002014void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002015 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002016 EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e);
2017}
2018
2019void Mips64Assembler::FillH(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002020 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002021 EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e);
2022}
2023
2024void Mips64Assembler::FillW(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002025 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002026 EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e);
2027}
2028
2029void Mips64Assembler::FillD(VectorRegister wd, GpuRegister rs) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002030 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002031 EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e);
2032}
2033
Goran Jakovljevic3f444032017-03-31 14:38:20 +02002034void Mips64Assembler::LdiB(VectorRegister wd, int imm8) {
2035 CHECK(HasMsa());
2036 CHECK(IsInt<8>(imm8)) << imm8;
2037 EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7);
2038}
2039
2040void Mips64Assembler::LdiH(VectorRegister wd, int imm10) {
2041 CHECK(HasMsa());
2042 CHECK(IsInt<10>(imm10)) << imm10;
2043 EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7);
2044}
2045
2046void Mips64Assembler::LdiW(VectorRegister wd, int imm10) {
2047 CHECK(HasMsa());
2048 CHECK(IsInt<10>(imm10)) << imm10;
2049 EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7);
2050}
2051
2052void Mips64Assembler::LdiD(VectorRegister wd, int imm10) {
2053 CHECK(HasMsa());
2054 CHECK(IsInt<10>(imm10)) << imm10;
2055 EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7);
2056}
2057
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002058void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002059 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002060 CHECK(IsInt<10>(offset)) << offset;
2061 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0);
2062}
2063
2064void Mips64Assembler::LdH(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002065 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002066 CHECK(IsInt<11>(offset)) << offset;
2067 CHECK_ALIGNED(offset, kMips64HalfwordSize);
2068 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1);
2069}
2070
2071void Mips64Assembler::LdW(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002072 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002073 CHECK(IsInt<12>(offset)) << offset;
2074 CHECK_ALIGNED(offset, kMips64WordSize);
2075 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2);
2076}
2077
2078void Mips64Assembler::LdD(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002079 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002080 CHECK(IsInt<13>(offset)) << offset;
2081 CHECK_ALIGNED(offset, kMips64DoublewordSize);
2082 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3);
2083}
2084
2085void Mips64Assembler::StB(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002086 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002087 CHECK(IsInt<10>(offset)) << offset;
2088 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0);
2089}
2090
2091void Mips64Assembler::StH(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002092 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002093 CHECK(IsInt<11>(offset)) << offset;
2094 CHECK_ALIGNED(offset, kMips64HalfwordSize);
2095 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1);
2096}
2097
2098void Mips64Assembler::StW(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002099 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002100 CHECK(IsInt<12>(offset)) << offset;
2101 CHECK_ALIGNED(offset, kMips64WordSize);
2102 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2);
2103}
2104
2105void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) {
Goran Jakovljevic27af9372017-03-15 15:31:34 +01002106 CHECK(HasMsa());
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00002107 CHECK(IsInt<13>(offset)) << offset;
2108 CHECK_ALIGNED(offset, kMips64DoublewordSize);
2109 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3);
2110}
2111
Lena Djokic3309c012017-10-13 14:34:32 +02002112void Mips64Assembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2113 CHECK(HasMsa());
2114 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14);
2115}
2116
2117void Mips64Assembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2118 CHECK(HasMsa());
2119 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14);
2120}
2121
2122void Mips64Assembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2123 CHECK(HasMsa());
2124 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14);
2125}
2126
2127void Mips64Assembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2128 CHECK(HasMsa());
2129 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14);
2130}
2131
Goran Jakovljevic38370112017-05-10 14:30:28 +02002132void Mips64Assembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2133 CHECK(HasMsa());
2134 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14);
2135}
2136
2137void Mips64Assembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2138 CHECK(HasMsa());
2139 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14);
2140}
2141
2142void Mips64Assembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2143 CHECK(HasMsa());
2144 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14);
2145}
2146
2147void Mips64Assembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2148 CHECK(HasMsa());
2149 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14);
2150}
2151
Lena Djokic3309c012017-10-13 14:34:32 +02002152void Mips64Assembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2153 CHECK(HasMsa());
2154 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14);
2155}
2156
2157void Mips64Assembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2158 CHECK(HasMsa());
2159 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14);
2160}
2161
2162void Mips64Assembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2163 CHECK(HasMsa());
2164 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14);
2165}
2166
2167void Mips64Assembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2168 CHECK(HasMsa());
2169 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14);
2170}
2171
2172void Mips64Assembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2173 CHECK(HasMsa());
2174 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14);
2175}
2176
2177void Mips64Assembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2178 CHECK(HasMsa());
2179 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14);
2180}
2181
2182void Mips64Assembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2183 CHECK(HasMsa());
2184 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14);
2185}
2186
2187void Mips64Assembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2188 CHECK(HasMsa());
2189 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14);
2190}
2191
Lena Djokicb3d79e42017-07-25 11:20:52 +02002192void Mips64Assembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2193 CHECK(HasMsa());
2194 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12);
2195}
2196
2197void Mips64Assembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2198 CHECK(HasMsa());
2199 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12);
2200}
2201
2202void Mips64Assembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2203 CHECK(HasMsa());
2204 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12);
2205}
2206
2207void Mips64Assembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2208 CHECK(HasMsa());
2209 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12);
2210}
2211
2212void Mips64Assembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2213 CHECK(HasMsa());
2214 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12);
2215}
2216
2217void Mips64Assembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2218 CHECK(HasMsa());
2219 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12);
2220}
2221
2222void Mips64Assembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2223 CHECK(HasMsa());
2224 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12);
2225}
2226
2227void Mips64Assembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2228 CHECK(HasMsa());
2229 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12);
2230}
2231
2232void Mips64Assembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2233 CHECK(HasMsa());
2234 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b);
2235}
2236
2237void Mips64Assembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2238 CHECK(HasMsa());
2239 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b);
2240}
2241
2242void Mips64Assembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2243 CHECK(HasMsa());
2244 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b);
2245}
2246
2247void Mips64Assembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2248 CHECK(HasMsa());
2249 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b);
2250}
2251
Lena Djokic3309c012017-10-13 14:34:32 +02002252void Mips64Assembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2253 CHECK(HasMsa());
2254 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15);
2255}
2256
2257void Mips64Assembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2258 CHECK(HasMsa());
2259 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15);
2260}
2261
2262void Mips64Assembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2263 CHECK(HasMsa());
2264 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15);
2265}
2266
2267void Mips64Assembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2268 CHECK(HasMsa());
2269 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15);
2270}
2271
2272void Mips64Assembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2273 CHECK(HasMsa());
2274 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15);
2275}
2276
2277void Mips64Assembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2278 CHECK(HasMsa());
2279 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15);
2280}
2281
Lena Djokic0d2cab52018-03-06 15:20:45 +01002282void Mips64Assembler::PcntB(VectorRegister wd, VectorRegister ws) {
2283 CHECK(HasMsa());
2284 EmitMsa2R(0xc1, 0x0, ws, wd, 0x1e);
2285}
2286
2287void Mips64Assembler::PcntH(VectorRegister wd, VectorRegister ws) {
2288 CHECK(HasMsa());
2289 EmitMsa2R(0xc1, 0x1, ws, wd, 0x1e);
2290}
2291
2292void Mips64Assembler::PcntW(VectorRegister wd, VectorRegister ws) {
2293 CHECK(HasMsa());
2294 EmitMsa2R(0xc1, 0x2, ws, wd, 0x1e);
2295}
2296
2297void Mips64Assembler::PcntD(VectorRegister wd, VectorRegister ws) {
2298 CHECK(HasMsa());
2299 EmitMsa2R(0xc1, 0x3, ws, wd, 0x1e);
2300}
2301
Goran Jakovljevic19680d32017-05-11 10:38:36 +02002302void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst,
2303 FpuRegister src,
2304 bool is_double) {
2305 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
2306 if (is_double) {
2307 SplatiD(dst, static_cast<VectorRegister>(src), 0);
2308 } else {
2309 SplatiW(dst, static_cast<VectorRegister>(src), 0);
2310 }
2311}
2312
Alexey Frunze4dda3372015-06-01 18:31:49 -07002313void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07002314 TemplateLoadConst32(this, rd, value);
2315}
2316
2317// This function is only used for testing purposes.
2318void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002319}
2320
Alexey Frunze4dda3372015-06-01 18:31:49 -07002321void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07002322 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08002323}
2324
Alexey Frunze0960ac52016-12-20 17:24:59 -08002325void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) {
2326 if (IsInt<16>(value)) {
2327 Addiu(rt, rs, value);
2328 } else {
2329 int16_t high = High16Bits(value);
2330 int16_t low = Low16Bits(value);
2331 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
2332 Aui(rt, rs, high);
2333 if (low != 0) {
2334 Addiu(rt, rt, low);
2335 }
2336 }
2337}
2338
Alexey Frunze15958152017-02-09 19:08:30 -08002339// TODO: don't use rtmp, use daui, dahi, dati.
Alexey Frunze4dda3372015-06-01 18:31:49 -07002340void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
Chris Larsen5863f852017-03-23 15:41:37 -07002341 CHECK_NE(rs, rtmp);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002342 if (IsInt<16>(value)) {
2343 Daddiu(rt, rs, value);
2344 } else {
2345 LoadConst64(rtmp, value);
2346 Daddu(rt, rs, rtmp);
2347 }
Andreas Gampe57b34292015-01-14 15:45:59 -08002348}
2349
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002350void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
2351 Mips64Assembler::Branch::Type short_type,
2352 Mips64Assembler::Branch::Type long_type) {
2353 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
2354}
Alexey Frunze4dda3372015-06-01 18:31:49 -07002355
Alexey Frunze0cab6562017-07-25 15:19:36 -07002356void Mips64Assembler::Branch::InitializeType(Type initial_type, bool is_r6) {
2357 OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
2358 if (is_r6) {
2359 // R6
2360 switch (initial_type) {
2361 case kLabel:
2362 case kLiteral:
2363 case kLiteralUnsigned:
2364 case kLiteralLong:
2365 CHECK(!IsResolved());
2366 type_ = initial_type;
2367 break;
2368 case kCall:
2369 InitShortOrLong(offset_size_needed, kCall, kLongCall);
2370 break;
2371 case kCondBranch:
2372 switch (condition_) {
2373 case kUncond:
2374 InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
2375 break;
2376 case kCondEQZ:
2377 case kCondNEZ:
2378 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
2379 type_ = (offset_size_needed <= kOffset23) ? kCondBranch : kLongCondBranch;
2380 break;
2381 default:
2382 InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
2383 break;
2384 }
2385 break;
2386 case kBareCall:
2387 type_ = kBareCall;
2388 CHECK_LE(offset_size_needed, GetOffsetSize());
2389 break;
2390 case kBareCondBranch:
2391 type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
2392 CHECK_LE(offset_size_needed, GetOffsetSize());
2393 break;
2394 default:
2395 LOG(FATAL) << "Unexpected branch type " << initial_type;
2396 UNREACHABLE();
2397 }
2398 } else {
2399 // R2
2400 CHECK_EQ(initial_type, kBareCondBranch);
2401 switch (condition_) {
2402 case kCondLTZ:
2403 case kCondGEZ:
2404 case kCondLEZ:
2405 case kCondGTZ:
2406 case kCondEQ:
2407 case kCondNE:
2408 case kCondEQZ:
2409 case kCondNEZ:
2410 break;
2411 default:
2412 LOG(FATAL) << "Unexpected R2 branch condition " << condition_;
2413 UNREACHABLE();
2414 }
2415 type_ = kR2BareCondBranch;
2416 CHECK_LE(offset_size_needed, GetOffsetSize());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002417 }
2418 old_type_ = type_;
2419}
2420
2421bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
2422 switch (condition) {
2423 case kCondLT:
2424 case kCondGT:
2425 case kCondNE:
2426 case kCondLTU:
2427 return lhs == rhs;
2428 default:
2429 return false;
2430 }
2431}
2432
2433bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
2434 GpuRegister lhs,
2435 GpuRegister rhs) {
2436 switch (condition) {
2437 case kUncond:
2438 return true;
2439 case kCondGE:
2440 case kCondLE:
2441 case kCondEQ:
2442 case kCondGEU:
2443 return lhs == rhs;
2444 default:
2445 return false;
2446 }
2447}
2448
Alexey Frunze0cab6562017-07-25 15:19:36 -07002449Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call, bool is_bare)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002450 : old_location_(location),
2451 location_(location),
2452 target_(target),
2453 lhs_reg_(ZERO),
2454 rhs_reg_(ZERO),
2455 condition_(kUncond) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002456 InitializeType(
2457 (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
Andreas Gampe3db70682018-12-26 15:12:03 -08002458 /* is_r6= */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002459}
2460
Alexey Frunze0cab6562017-07-25 15:19:36 -07002461Mips64Assembler::Branch::Branch(bool is_r6,
2462 uint32_t location,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002463 uint32_t target,
2464 Mips64Assembler::BranchCondition condition,
2465 GpuRegister lhs_reg,
Alexey Frunze0cab6562017-07-25 15:19:36 -07002466 GpuRegister rhs_reg,
2467 bool is_bare)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002468 : old_location_(location),
2469 location_(location),
2470 target_(target),
2471 lhs_reg_(lhs_reg),
2472 rhs_reg_(rhs_reg),
2473 condition_(condition) {
2474 CHECK_NE(condition, kUncond);
2475 switch (condition) {
2476 case kCondEQ:
2477 case kCondNE:
2478 case kCondLT:
2479 case kCondGE:
2480 case kCondLE:
2481 case kCondGT:
2482 case kCondLTU:
2483 case kCondGEU:
2484 CHECK_NE(lhs_reg, ZERO);
2485 CHECK_NE(rhs_reg, ZERO);
2486 break;
2487 case kCondLTZ:
2488 case kCondGEZ:
2489 case kCondLEZ:
2490 case kCondGTZ:
2491 case kCondEQZ:
2492 case kCondNEZ:
2493 CHECK_NE(lhs_reg, ZERO);
2494 CHECK_EQ(rhs_reg, ZERO);
2495 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08002496 case kCondF:
2497 case kCondT:
2498 CHECK_EQ(rhs_reg, ZERO);
2499 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002500 case kUncond:
2501 UNREACHABLE();
2502 }
2503 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
2504 if (IsUncond(condition, lhs_reg, rhs_reg)) {
2505 // Branch condition is always true, make the branch unconditional.
2506 condition_ = kUncond;
2507 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07002508 InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002509}
2510
Alexey Frunze19f6c692016-11-30 19:19:55 -08002511Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002512 : old_location_(location),
2513 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08002514 target_(kUnresolved),
2515 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002516 rhs_reg_(ZERO),
2517 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08002518 CHECK_NE(dest_reg, ZERO);
Andreas Gampe3db70682018-12-26 15:12:03 -08002519 InitializeType(label_or_literal_type, /* is_r6= */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002520}
2521
2522Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
2523 Mips64Assembler::BranchCondition cond) {
2524 switch (cond) {
2525 case kCondLT:
2526 return kCondGE;
2527 case kCondGE:
2528 return kCondLT;
2529 case kCondLE:
2530 return kCondGT;
2531 case kCondGT:
2532 return kCondLE;
2533 case kCondLTZ:
2534 return kCondGEZ;
2535 case kCondGEZ:
2536 return kCondLTZ;
2537 case kCondLEZ:
2538 return kCondGTZ;
2539 case kCondGTZ:
2540 return kCondLEZ;
2541 case kCondEQ:
2542 return kCondNE;
2543 case kCondNE:
2544 return kCondEQ;
2545 case kCondEQZ:
2546 return kCondNEZ;
2547 case kCondNEZ:
2548 return kCondEQZ;
2549 case kCondLTU:
2550 return kCondGEU;
2551 case kCondGEU:
2552 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08002553 case kCondF:
2554 return kCondT;
2555 case kCondT:
2556 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002557 case kUncond:
2558 LOG(FATAL) << "Unexpected branch condition " << cond;
2559 }
2560 UNREACHABLE();
2561}
2562
2563Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
2564 return type_;
2565}
2566
2567Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
2568 return condition_;
2569}
2570
2571GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
2572 return lhs_reg_;
2573}
2574
2575GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
2576 return rhs_reg_;
2577}
2578
2579uint32_t Mips64Assembler::Branch::GetTarget() const {
2580 return target_;
2581}
2582
2583uint32_t Mips64Assembler::Branch::GetLocation() const {
2584 return location_;
2585}
2586
2587uint32_t Mips64Assembler::Branch::GetOldLocation() const {
2588 return old_location_;
2589}
2590
2591uint32_t Mips64Assembler::Branch::GetLength() const {
2592 return branch_info_[type_].length;
2593}
2594
2595uint32_t Mips64Assembler::Branch::GetOldLength() const {
2596 return branch_info_[old_type_].length;
2597}
2598
2599uint32_t Mips64Assembler::Branch::GetSize() const {
2600 return GetLength() * sizeof(uint32_t);
2601}
2602
2603uint32_t Mips64Assembler::Branch::GetOldSize() const {
2604 return GetOldLength() * sizeof(uint32_t);
2605}
2606
2607uint32_t Mips64Assembler::Branch::GetEndLocation() const {
2608 return GetLocation() + GetSize();
2609}
2610
2611uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
2612 return GetOldLocation() + GetOldSize();
2613}
2614
Alexey Frunze0cab6562017-07-25 15:19:36 -07002615bool Mips64Assembler::Branch::IsBare() const {
2616 switch (type_) {
2617 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
2618 case kBareUncondBranch:
2619 case kBareCondBranch:
2620 case kBareCall:
2621 // R2 short branches (can't be promoted to long), delay slots filled manually.
2622 case kR2BareCondBranch:
2623 return true;
2624 default:
2625 return false;
2626 }
2627}
2628
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002629bool Mips64Assembler::Branch::IsLong() const {
2630 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002631 // R6 short branches (can be promoted to long).
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002632 case kUncondBranch:
2633 case kCondBranch:
2634 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002635 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
2636 case kBareUncondBranch:
2637 case kBareCondBranch:
2638 case kBareCall:
2639 // R2 short branches (can't be promoted to long), delay slots filled manually.
2640 case kR2BareCondBranch:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002641 // Near label.
2642 case kLabel:
2643 // Near literals.
2644 case kLiteral:
2645 case kLiteralUnsigned:
2646 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002647 return false;
2648 // Long branches.
2649 case kLongUncondBranch:
2650 case kLongCondBranch:
2651 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002652 // Far label.
2653 case kFarLabel:
2654 // Far literals.
2655 case kFarLiteral:
2656 case kFarLiteralUnsigned:
2657 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002658 return true;
2659 }
2660 UNREACHABLE();
2661}
2662
2663bool Mips64Assembler::Branch::IsResolved() const {
2664 return target_ != kUnresolved;
2665}
2666
2667Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002668 bool r6_cond_branch = (type_ == kCondBranch || type_ == kBareCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002669 OffsetBits offset_size =
Alexey Frunze0cab6562017-07-25 15:19:36 -07002670 (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002671 ? kOffset23
2672 : branch_info_[type_].offset_size;
2673 return offset_size;
2674}
2675
2676Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
2677 uint32_t target) {
2678 // For unresolved targets assume the shortest encoding
2679 // (later it will be made longer if needed).
2680 if (target == kUnresolved)
2681 return kOffset16;
2682 int64_t distance = static_cast<int64_t>(target) - location;
2683 // To simplify calculations in composite branches consisting of multiple instructions
2684 // bump up the distance by a value larger than the max byte size of a composite branch.
2685 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
2686 if (IsInt<kOffset16>(distance))
2687 return kOffset16;
2688 else if (IsInt<kOffset18>(distance))
2689 return kOffset18;
2690 else if (IsInt<kOffset21>(distance))
2691 return kOffset21;
2692 else if (IsInt<kOffset23>(distance))
2693 return kOffset23;
2694 else if (IsInt<kOffset28>(distance))
2695 return kOffset28;
2696 return kOffset32;
2697}
2698
2699void Mips64Assembler::Branch::Resolve(uint32_t target) {
2700 target_ = target;
2701}
2702
2703void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
2704 if (location_ > expand_location) {
2705 location_ += delta;
2706 }
2707 if (!IsResolved()) {
2708 return; // Don't know the target yet.
2709 }
2710 if (target_ > expand_location) {
2711 target_ += delta;
2712 }
2713}
2714
2715void Mips64Assembler::Branch::PromoteToLong() {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002716 CHECK(!IsBare()); // Bare branches do not promote.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002717 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002718 // R6 short branches (can be promoted to long).
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002719 case kUncondBranch:
2720 type_ = kLongUncondBranch;
2721 break;
2722 case kCondBranch:
2723 type_ = kLongCondBranch;
2724 break;
2725 case kCall:
2726 type_ = kLongCall;
2727 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002728 // Near label.
2729 case kLabel:
2730 type_ = kFarLabel;
2731 break;
2732 // Near literals.
2733 case kLiteral:
2734 type_ = kFarLiteral;
2735 break;
2736 case kLiteralUnsigned:
2737 type_ = kFarLiteralUnsigned;
2738 break;
2739 case kLiteralLong:
2740 type_ = kFarLiteralLong;
2741 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002742 default:
2743 // Note: 'type_' is already long.
2744 break;
2745 }
2746 CHECK(IsLong());
2747}
2748
2749uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
2750 // If the branch is still unresolved or already long, nothing to do.
2751 if (IsLong() || !IsResolved()) {
2752 return 0;
2753 }
2754 // Promote the short branch to long if the offset size is too small
2755 // to hold the distance between location_ and target_.
2756 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
2757 PromoteToLong();
2758 uint32_t old_size = GetOldSize();
2759 uint32_t new_size = GetSize();
2760 CHECK_GT(new_size, old_size);
2761 return new_size - old_size;
2762 }
2763 // The following logic is for debugging/testing purposes.
2764 // Promote some short branches to long when it's not really required.
Alexey Frunze0cab6562017-07-25 15:19:36 -07002765 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002766 int64_t distance = static_cast<int64_t>(target_) - location_;
2767 distance = (distance >= 0) ? distance : -distance;
2768 if (distance >= max_short_distance) {
2769 PromoteToLong();
2770 uint32_t old_size = GetOldSize();
2771 uint32_t new_size = GetSize();
2772 CHECK_GT(new_size, old_size);
2773 return new_size - old_size;
2774 }
2775 }
2776 return 0;
2777}
2778
2779uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
2780 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
2781}
2782
2783uint32_t Mips64Assembler::Branch::GetOffset() const {
2784 CHECK(IsResolved());
2785 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
2786 // Calculate the byte distance between instructions and also account for
2787 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08002788 uint32_t offset_location = GetOffsetLocation();
2789 if (type_ == kLiteralLong) {
2790 // Special case for the ldpc instruction, whose address (PC) is rounded down to
2791 // a multiple of 8 before adding the offset.
2792 // Note, branch promotion has already taken care of aligning `target_` to an
2793 // address that's a multiple of 8.
2794 offset_location = RoundDown(offset_location, sizeof(uint64_t));
2795 }
2796 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002797 // Prepare the offset for encoding into the instruction(s).
2798 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
2799 return offset;
2800}
2801
2802Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
2803 CHECK_LT(branch_id, branches_.size());
2804 return &branches_[branch_id];
2805}
2806
2807const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
2808 CHECK_LT(branch_id, branches_.size());
2809 return &branches_[branch_id];
2810}
2811
2812void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002813 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002814 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002815
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002816 // Walk the list of branches referring to and preceding this label.
2817 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07002818 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002819 uint32_t branch_id = label->Position();
2820 Branch* branch = GetBranch(branch_id);
2821 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002822
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002823 uint32_t branch_location = branch->GetLocation();
2824 // Extract the location of the previous branch in the list (walking the list backwards;
2825 // the previous branch ID was stored in the space reserved for this branch).
2826 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002827
2828 // On to the previous branch in the list...
2829 label->position_ = prev;
2830 }
2831
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002832 // Now make the label object contain its own location (relative to the end of the preceding
2833 // branch, if any; it will be used by the branches referring to and following this label).
2834 label->prev_branch_id_plus_one_ = branches_.size();
2835 if (label->prev_branch_id_plus_one_) {
2836 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2837 const Branch* branch = GetBranch(branch_id);
2838 bound_pc -= branch->GetEndLocation();
2839 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002840 label->BindTo(bound_pc);
2841}
2842
Alexey Frunze19f6c692016-11-30 19:19:55 -08002843uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002844 CHECK(label->IsBound());
2845 uint32_t target = label->Position();
2846 if (label->prev_branch_id_plus_one_) {
2847 // Get label location based on the branch preceding it.
2848 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2849 const Branch* branch = GetBranch(branch_id);
2850 target += branch->GetEndLocation();
2851 }
2852 return target;
2853}
2854
2855uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
2856 // We can reconstruct the adjustment by going through all the branches from the beginning
2857 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
2858 // with increasing old_position, we can use the data from last AdjustedPosition() to
2859 // continue where we left off and the whole loop should be O(m+n) where m is the number
2860 // of positions to adjust and n is the number of branches.
2861 if (old_position < last_old_position_) {
2862 last_position_adjustment_ = 0;
2863 last_old_position_ = 0;
2864 last_branch_id_ = 0;
2865 }
2866 while (last_branch_id_ != branches_.size()) {
2867 const Branch* branch = GetBranch(last_branch_id_);
2868 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
2869 break;
2870 }
2871 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
2872 ++last_branch_id_;
2873 }
2874 last_old_position_ = old_position;
2875 return old_position + last_position_adjustment_;
2876}
2877
2878void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
2879 uint32_t length = branches_.back().GetLength();
2880 if (!label->IsBound()) {
2881 // Branch forward (to a following label), distance is unknown.
2882 // The first branch forward will contain 0, serving as the terminator of
2883 // the list of forward-reaching branches.
2884 Emit(label->position_);
2885 length--;
2886 // Now make the label object point to this branch
2887 // (this forms a linked list of branches preceding this label).
2888 uint32_t branch_id = branches_.size() - 1;
2889 label->LinkTo(branch_id);
2890 }
2891 // Reserve space for the branch.
Andreas Gampec74d9cb2018-09-20 13:44:44 -07002892 for (; length != 0u; --length) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002893 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002894 }
2895}
2896
Alexey Frunze0cab6562017-07-25 15:19:36 -07002897void Mips64Assembler::Buncond(Mips64Label* label, bool is_bare) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002898 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Andreas Gampe3db70682018-12-26 15:12:03 -08002899 branches_.emplace_back(buffer_.Size(), target, /* is_call= */ false, is_bare);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002900 FinalizeLabeledBranch(label);
2901}
2902
2903void Mips64Assembler::Bcond(Mips64Label* label,
Alexey Frunze0cab6562017-07-25 15:19:36 -07002904 bool is_r6,
2905 bool is_bare,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002906 BranchCondition condition,
2907 GpuRegister lhs,
2908 GpuRegister rhs) {
2909 // If lhs = rhs, this can be a NOP.
2910 if (Branch::IsNop(condition, lhs, rhs)) {
2911 return;
2912 }
2913 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07002914 branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002915 FinalizeLabeledBranch(label);
2916}
2917
Alexey Frunze0cab6562017-07-25 15:19:36 -07002918void Mips64Assembler::Call(Mips64Label* label, bool is_bare) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002919 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Andreas Gampe3db70682018-12-26 15:12:03 -08002920 branches_.emplace_back(buffer_.Size(), target, /* is_call= */ true, is_bare);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002921 FinalizeLabeledBranch(label);
2922}
2923
Alexey Frunze19f6c692016-11-30 19:19:55 -08002924void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
2925 // Label address loads are treated as pseudo branches since they require very similar handling.
2926 DCHECK(!label->IsBound());
2927 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
2928 FinalizeLabeledBranch(label);
2929}
2930
2931Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
2932 // We don't support byte and half-word literals.
2933 if (size == 4u) {
2934 literals_.emplace_back(size, data);
2935 return &literals_.back();
2936 } else {
2937 DCHECK_EQ(size, 8u);
2938 long_literals_.emplace_back(size, data);
2939 return &long_literals_.back();
2940 }
2941}
2942
2943void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
2944 LoadOperandType load_type,
2945 Literal* literal) {
2946 // Literal loads are treated as pseudo branches since they require very similar handling.
2947 Branch::Type literal_type;
2948 switch (load_type) {
2949 case kLoadWord:
2950 DCHECK_EQ(literal->GetSize(), 4u);
2951 literal_type = Branch::kLiteral;
2952 break;
2953 case kLoadUnsignedWord:
2954 DCHECK_EQ(literal->GetSize(), 4u);
2955 literal_type = Branch::kLiteralUnsigned;
2956 break;
2957 case kLoadDoubleword:
2958 DCHECK_EQ(literal->GetSize(), 8u);
2959 literal_type = Branch::kLiteralLong;
2960 break;
2961 default:
2962 LOG(FATAL) << "Unexpected literal load type " << load_type;
2963 UNREACHABLE();
2964 }
2965 Mips64Label* label = literal->GetLabel();
2966 DCHECK(!label->IsBound());
2967 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
2968 FinalizeLabeledBranch(label);
2969}
2970
Alexey Frunze0960ac52016-12-20 17:24:59 -08002971JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) {
2972 jump_tables_.emplace_back(std::move(labels));
2973 JumpTable* table = &jump_tables_.back();
2974 DCHECK(!table->GetLabel()->IsBound());
2975 return table;
2976}
2977
2978void Mips64Assembler::ReserveJumpTableSpace() {
2979 if (!jump_tables_.empty()) {
2980 for (JumpTable& table : jump_tables_) {
2981 Mips64Label* label = table.GetLabel();
2982 Bind(label);
2983
2984 // Bulk ensure capacity, as this may be large.
2985 size_t orig_size = buffer_.Size();
2986 size_t required_capacity = orig_size + table.GetSize();
2987 if (required_capacity > buffer_.Capacity()) {
2988 buffer_.ExtendCapacity(required_capacity);
2989 }
2990#ifndef NDEBUG
2991 buffer_.has_ensured_capacity_ = true;
2992#endif
2993
2994 // Fill the space with dummy data as the data is not final
2995 // until the branches have been promoted. And we shouldn't
2996 // be moving uninitialized data during branch promotion.
2997 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
2998 buffer_.Emit<uint32_t>(0x1abe1234u);
2999 }
3000
3001#ifndef NDEBUG
3002 buffer_.has_ensured_capacity_ = false;
3003#endif
3004 }
3005 }
3006}
3007
3008void Mips64Assembler::EmitJumpTables() {
3009 if (!jump_tables_.empty()) {
3010 CHECK(!overwriting_);
3011 // Switch from appending instructions at the end of the buffer to overwriting
3012 // existing instructions (here, jump tables) in the buffer.
3013 overwriting_ = true;
3014
3015 for (JumpTable& table : jump_tables_) {
3016 Mips64Label* table_label = table.GetLabel();
3017 uint32_t start = GetLabelLocation(table_label);
3018 overwrite_location_ = start;
3019
3020 for (Mips64Label* target : table.GetData()) {
3021 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
3022 // The table will contain target addresses relative to the table start.
3023 uint32_t offset = GetLabelLocation(target) - start;
3024 Emit(offset);
3025 }
3026 }
3027
3028 overwriting_ = false;
3029 }
3030}
3031
Alexey Frunze19f6c692016-11-30 19:19:55 -08003032void Mips64Assembler::EmitLiterals() {
3033 if (!literals_.empty()) {
3034 for (Literal& literal : literals_) {
3035 Mips64Label* label = literal.GetLabel();
3036 Bind(label);
3037 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
3038 DCHECK_EQ(literal.GetSize(), 4u);
3039 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
3040 buffer_.Emit<uint8_t>(literal.GetData()[i]);
3041 }
3042 }
3043 }
3044 if (!long_literals_.empty()) {
3045 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
3046 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
3047 Emit(0); // NOP.
3048 for (Literal& literal : long_literals_) {
3049 Mips64Label* label = literal.GetLabel();
3050 Bind(label);
3051 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
3052 DCHECK_EQ(literal.GetSize(), 8u);
3053 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
3054 buffer_.Emit<uint8_t>(literal.GetData()[i]);
3055 }
3056 }
3057 }
3058}
3059
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003060void Mips64Assembler::PromoteBranches() {
3061 // Promote short branches to long as necessary.
3062 bool changed;
3063 do {
3064 changed = false;
3065 for (auto& branch : branches_) {
3066 CHECK(branch.IsResolved());
3067 uint32_t delta = branch.PromoteIfNeeded();
3068 // If this branch has been promoted and needs to expand in size,
3069 // relocate all branches by the expansion size.
3070 if (delta) {
3071 changed = true;
3072 uint32_t expand_location = branch.GetLocation();
3073 for (auto& branch2 : branches_) {
3074 branch2.Relocate(expand_location, delta);
3075 }
3076 }
3077 }
3078 } while (changed);
3079
3080 // Account for branch expansion by resizing the code buffer
3081 // and moving the code in it to its final location.
3082 size_t branch_count = branches_.size();
3083 if (branch_count > 0) {
3084 // Resize.
3085 Branch& last_branch = branches_[branch_count - 1];
3086 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
3087 uint32_t old_size = buffer_.Size();
3088 buffer_.Resize(old_size + size_delta);
3089 // Move the code residing between branch placeholders.
3090 uint32_t end = old_size;
3091 for (size_t i = branch_count; i > 0; ) {
3092 Branch& branch = branches_[--i];
3093 uint32_t size = end - branch.GetOldEndLocation();
3094 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
3095 end = branch.GetOldLocation();
3096 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07003097 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08003098
3099 // Align 64-bit literals by moving them down by 4 bytes if needed.
3100 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
3101 if (!long_literals_.empty()) {
3102 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
3103 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
3104 size_t buf_size = buffer_.Size();
3105 // 64-bit literals must be at the very end of the buffer.
3106 CHECK_EQ(first_literal_location + lit_size, buf_size);
3107 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
3108 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
3109 // The 4 reserved bytes proved useless, reduce the buffer size.
3110 buffer_.Resize(buf_size - sizeof(uint32_t));
3111 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
3112 // offsets from PC to be generated.
3113 for (auto& branch : branches_) {
3114 uint32_t target = branch.GetTarget();
3115 if (target >= first_literal_location) {
3116 branch.Resolve(target - sizeof(uint32_t));
3117 }
3118 }
3119 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
3120 // we need to adjust the location of the literal's label as well.
3121 for (Literal& literal : long_literals_) {
3122 // Bound label's position is negative, hence incrementing it instead of decrementing.
3123 literal.GetLabel()->position_ += sizeof(uint32_t);
3124 }
3125 }
3126 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07003127}
3128
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003129// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
3130const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003131 // R6 short branches (can be promoted to long).
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003132 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
3133 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
3134 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08003135 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
Alexey Frunze0cab6562017-07-25 15:19:36 -07003136 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3137 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareUncondBranch
3138 { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kBareCondBranch
3139 // Exception: kOffset23 for beqzc/bnezc
3140 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareCall
3141 // R2 short branches (can't be promoted to long), delay slots filled manually.
3142 { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kR2BareCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08003143 // Near label.
3144 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
3145 // Near literals.
3146 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
3147 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
3148 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003149 // Long branches.
3150 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
3151 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08003152 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
3153 // Far label.
3154 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
3155 // Far literals.
3156 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
3157 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
3158 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003159};
3160
3161// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
3162void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
3163 CHECK(overwriting_);
3164 overwrite_location_ = branch->GetLocation();
3165 uint32_t offset = branch->GetOffset();
3166 BranchCondition condition = branch->GetCondition();
3167 GpuRegister lhs = branch->GetLeftRegister();
3168 GpuRegister rhs = branch->GetRightRegister();
3169 switch (branch->GetType()) {
3170 // Short branches.
3171 case Branch::kUncondBranch:
3172 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3173 Bc(offset);
3174 break;
3175 case Branch::kCondBranch:
3176 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze0cab6562017-07-25 15:19:36 -07003177 EmitBcondR6(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08003178 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003179 break;
3180 case Branch::kCall:
3181 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08003182 Balc(offset);
3183 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003184 case Branch::kBareUncondBranch:
3185 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3186 Bc(offset);
3187 break;
3188 case Branch::kBareCondBranch:
3189 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3190 EmitBcondR6(condition, lhs, rhs, offset);
3191 break;
3192 case Branch::kBareCall:
3193 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3194 Balc(offset);
3195 break;
3196 case Branch::kR2BareCondBranch:
3197 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3198 EmitBcondR2(condition, lhs, rhs, offset);
3199 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08003200
3201 // Near label.
3202 case Branch::kLabel:
3203 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003204 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08003205 break;
3206 // Near literals.
3207 case Branch::kLiteral:
3208 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3209 Lwpc(lhs, offset);
3210 break;
3211 case Branch::kLiteralUnsigned:
3212 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3213 Lwupc(lhs, offset);
3214 break;
3215 case Branch::kLiteralLong:
3216 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3217 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003218 break;
3219
3220 // Long branches.
3221 case Branch::kLongUncondBranch:
3222 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
3223 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3224 Auipc(AT, High16Bits(offset));
3225 Jic(AT, Low16Bits(offset));
3226 break;
3227 case Branch::kLongCondBranch:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003228 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003229 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
3230 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3231 Auipc(AT, High16Bits(offset));
3232 Jic(AT, Low16Bits(offset));
3233 break;
3234 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08003235 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003236 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08003237 Auipc(AT, High16Bits(offset));
3238 Jialc(AT, Low16Bits(offset));
3239 break;
3240
3241 // Far label.
3242 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08003243 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08003244 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3245 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08003246 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08003247 break;
3248 // Far literals.
3249 case Branch::kFarLiteral:
3250 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
3251 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3252 Auipc(AT, High16Bits(offset));
3253 Lw(lhs, AT, Low16Bits(offset));
3254 break;
3255 case Branch::kFarLiteralUnsigned:
3256 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
3257 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3258 Auipc(AT, High16Bits(offset));
3259 Lwu(lhs, AT, Low16Bits(offset));
3260 break;
3261 case Branch::kFarLiteralLong:
3262 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
3263 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3264 Auipc(AT, High16Bits(offset));
3265 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003266 break;
3267 }
3268 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
3269 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07003270}
3271
Alexey Frunze0cab6562017-07-25 15:19:36 -07003272void Mips64Assembler::Bc(Mips64Label* label, bool is_bare) {
3273 Buncond(label, is_bare);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003274}
3275
Alexey Frunze0cab6562017-07-25 15:19:36 -07003276void Mips64Assembler::Balc(Mips64Label* label, bool is_bare) {
3277 Call(label, is_bare);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003278}
3279
Alexey Frunze0cab6562017-07-25 15:19:36 -07003280void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003281 Bcond(label, /* is_r6= */ true, is_bare, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003282}
3283
Alexey Frunze0cab6562017-07-25 15:19:36 -07003284void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003285 Bcond(label, /* is_r6= */ true, is_bare, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003286}
3287
Alexey Frunze0cab6562017-07-25 15:19:36 -07003288void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003289 Bcond(label, /* is_r6= */ true, is_bare, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003290}
3291
Alexey Frunze0cab6562017-07-25 15:19:36 -07003292void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003293 Bcond(label, /* is_r6= */ true, is_bare, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003294}
3295
Alexey Frunze0cab6562017-07-25 15:19:36 -07003296void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003297 Bcond(label, /* is_r6= */ true, is_bare, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003298}
3299
Alexey Frunze0cab6562017-07-25 15:19:36 -07003300void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003301 Bcond(label, /* is_r6= */ true, is_bare, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003302}
3303
Alexey Frunze0cab6562017-07-25 15:19:36 -07003304void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003305 Bcond(label, /* is_r6= */ true, is_bare, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003306}
3307
Alexey Frunze0cab6562017-07-25 15:19:36 -07003308void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003309 Bcond(label, /* is_r6= */ true, is_bare, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003310}
3311
Alexey Frunze0cab6562017-07-25 15:19:36 -07003312void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003313 Bcond(label, /* is_r6= */ true, is_bare, kCondEQ, rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003314}
3315
Alexey Frunze0cab6562017-07-25 15:19:36 -07003316void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003317 Bcond(label, /* is_r6= */ true, is_bare, kCondNE, rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003318}
3319
Alexey Frunze0cab6562017-07-25 15:19:36 -07003320void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003321 Bcond(label, /* is_r6= */ true, is_bare, kCondEQZ, rs);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003322}
3323
Alexey Frunze0cab6562017-07-25 15:19:36 -07003324void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003325 Bcond(label, /* is_r6= */ true, is_bare, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08003326}
3327
Alexey Frunze0cab6562017-07-25 15:19:36 -07003328void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003329 Bcond(label, /* is_r6= */ true, is_bare, kCondF, static_cast<GpuRegister>(ft), ZERO);
Alexey Frunze299a9392015-12-08 16:08:02 -08003330}
3331
Alexey Frunze0cab6562017-07-25 15:19:36 -07003332void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label, bool is_bare) {
Andreas Gampe3db70682018-12-26 15:12:03 -08003333 Bcond(label, /* is_r6= */ true, is_bare, kCondT, static_cast<GpuRegister>(ft), ZERO);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003334}
3335
3336void Mips64Assembler::Bltz(GpuRegister rt, Mips64Label* label, bool is_bare) {
3337 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003338 Bcond(label, /* is_r6= */ false, is_bare, kCondLTZ, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003339}
3340
3341void Mips64Assembler::Bgtz(GpuRegister rt, Mips64Label* label, bool is_bare) {
3342 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003343 Bcond(label, /* is_r6= */ false, is_bare, kCondGTZ, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003344}
3345
3346void Mips64Assembler::Bgez(GpuRegister rt, Mips64Label* label, bool is_bare) {
3347 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003348 Bcond(label, /* is_r6= */ false, is_bare, kCondGEZ, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003349}
3350
3351void Mips64Assembler::Blez(GpuRegister rt, Mips64Label* label, bool is_bare) {
3352 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003353 Bcond(label, /* is_r6= */ false, is_bare, kCondLEZ, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003354}
3355
3356void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
3357 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003358 Bcond(label, /* is_r6= */ false, is_bare, kCondEQ, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003359}
3360
3361void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
3362 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003363 Bcond(label, /* is_r6= */ false, is_bare, kCondNE, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003364}
3365
3366void Mips64Assembler::Beqz(GpuRegister rs, Mips64Label* label, bool is_bare) {
3367 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003368 Bcond(label, /* is_r6= */ false, is_bare, kCondEQZ, rs);
Alexey Frunze0cab6562017-07-25 15:19:36 -07003369}
3370
3371void Mips64Assembler::Bnez(GpuRegister rs, Mips64Label* label, bool is_bare) {
3372 CHECK(is_bare);
Andreas Gampe3db70682018-12-26 15:12:03 -08003373 Bcond(label, /* is_r6= */ false, is_bare, kCondNEZ, rs);
Alexey Frunze299a9392015-12-08 16:08:02 -08003374}
3375
Chris Larsenc3fec0c2016-12-15 11:44:14 -08003376void Mips64Assembler::AdjustBaseAndOffset(GpuRegister& base,
3377 int32_t& offset,
3378 bool is_doubleword) {
3379 // This method is used to adjust the base register and offset pair
3380 // for a load/store when the offset doesn't fit into int16_t.
3381 // It is assumed that `base + offset` is sufficiently aligned for memory
3382 // operands that are machine word in size or smaller. For doubleword-sized
3383 // operands it's assumed that `base` is a multiple of 8, while `offset`
3384 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
3385 // and spilled variables on the stack accessed relative to the stack
3386 // pointer register).
3387 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
3388 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
3389
3390 bool doubleword_aligned = IsAligned<kMips64DoublewordSize>(offset);
3391 bool two_accesses = is_doubleword && !doubleword_aligned;
3392
3393 // IsInt<16> must be passed a signed value, hence the static cast below.
3394 if (IsInt<16>(offset) &&
3395 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
3396 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
3397 return;
3398 }
3399
3400 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
3401 uint32_t misalignment = offset & (kMips64DoublewordSize - 1);
3402
3403 // First, see if `offset` can be represented as a sum of two 16-bit signed
3404 // offsets. This can save an instruction.
3405 // To simplify matters, only do this for a symmetric range of offsets from
3406 // about -64KB to about +64KB, allowing further addition of 4 when accessing
3407 // 64-bit variables with two 32-bit accesses.
3408 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
3409 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
3410
3411 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
3412 Daddiu(AT, base, kMinOffsetForSimpleAdjustment);
3413 offset -= kMinOffsetForSimpleAdjustment;
3414 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
3415 Daddiu(AT, base, -kMinOffsetForSimpleAdjustment);
3416 offset += kMinOffsetForSimpleAdjustment;
3417 } else {
3418 // In more complex cases take advantage of the daui instruction, e.g.:
3419 // daui AT, base, offset_high
3420 // [dahi AT, 1] // When `offset` is close to +2GB.
3421 // lw reg_lo, offset_low(AT)
3422 // [lw reg_hi, (offset_low+4)(AT)] // If misaligned 64-bit load.
3423 // or when offset_low+4 overflows int16_t:
3424 // daui AT, base, offset_high
3425 // daddiu AT, AT, 8
3426 // lw reg_lo, (offset_low-8)(AT)
3427 // lw reg_hi, (offset_low-4)(AT)
3428 int16_t offset_low = Low16Bits(offset);
3429 int32_t offset_low32 = offset_low;
3430 int16_t offset_high = High16Bits(offset);
3431 bool increment_hi16 = offset_low < 0;
3432 bool overflow_hi16 = false;
3433
3434 if (increment_hi16) {
3435 offset_high++;
3436 overflow_hi16 = (offset_high == -32768);
3437 }
3438 Daui(AT, base, offset_high);
3439
3440 if (overflow_hi16) {
3441 Dahi(AT, 1);
3442 }
3443
3444 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low32 + kMips64WordSize))) {
3445 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
3446 Daddiu(AT, AT, kMips64DoublewordSize);
3447 offset_low32 -= kMips64DoublewordSize;
3448 }
3449
3450 offset = offset_low32;
3451 }
3452 base = AT;
3453
3454 CHECK(IsInt<16>(offset));
3455 if (two_accesses) {
3456 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)));
3457 }
3458 CHECK_EQ(misalignment, offset & (kMips64DoublewordSize - 1));
3459}
3460
Goran Jakovljevicd8b6a532017-04-20 11:42:30 +02003461void Mips64Assembler::AdjustBaseOffsetAndElementSizeShift(GpuRegister& base,
3462 int32_t& offset,
3463 int& element_size_shift) {
3464 // This method is used to adjust the base register, offset and element_size_shift
3465 // for a vector load/store when the offset doesn't fit into allowed number of bits.
3466 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
3467 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
3468 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
3469 // If element_size_shift is non-negative at entry, it won't be changed, but offset
3470 // will be checked for appropriate alignment. If negative at entry, it will be
3471 // adjusted based on offset for maximum fit.
3472 // It's assumed that `base` is a multiple of 8.
3473
3474 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
3475
3476 if (element_size_shift >= 0) {
3477 CHECK_LE(element_size_shift, TIMES_8);
3478 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
3479 } else if (IsAligned<kMips64DoublewordSize>(offset)) {
3480 element_size_shift = TIMES_8;
3481 } else if (IsAligned<kMips64WordSize>(offset)) {
3482 element_size_shift = TIMES_4;
3483 } else if (IsAligned<kMips64HalfwordSize>(offset)) {
3484 element_size_shift = TIMES_2;
3485 } else {
3486 element_size_shift = TIMES_1;
3487 }
3488
3489 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
3490 // will take.
3491 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
3492 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
3493 if (low == offset) {
3494 return; // `offset` fits into ld.df/st.df.
3495 }
3496
3497 // First, see if `offset` can be represented as a sum of two signed offsets.
3498 // This can save an instruction.
3499
3500 // Max int16_t that's a multiple of element size.
3501 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
3502 // Max ld.df/st.df offset that's a multiple of element size.
3503 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
3504 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
3505
3506 if (IsInt<16>(offset)) {
3507 Daddiu(AT, base, offset);
3508 offset = 0;
3509 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
3510 Daddiu(AT, base, kMaxDeltaForSimpleAdjustment);
3511 offset -= kMaxDeltaForSimpleAdjustment;
3512 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
3513 Daddiu(AT, base, -kMaxDeltaForSimpleAdjustment);
3514 offset += kMaxDeltaForSimpleAdjustment;
3515 } else {
3516 // Let's treat `offset` as 64-bit to simplify handling of sign
3517 // extensions in the instructions that supply its smaller signed parts.
3518 //
3519 // 16-bit or smaller parts of `offset`:
3520 // |63 top 48|47 hi 32|31 upper 16|15 mid 13-10|12-9 low 0|
3521 //
3522 // Instructions that supply each part as a signed integer addend:
3523 // |dati |dahi |daui |daddiu |ld.df/st.df |
3524 //
3525 // `top` is always 0, so dati isn't used.
3526 // `hi` is 1 when `offset` is close to +2GB and 0 otherwise.
3527 uint64_t tmp = static_cast<uint64_t>(offset) - low; // Exclude `low` from the rest of `offset`
3528 // (accounts for sign of `low`).
3529 tmp += (tmp & (UINT64_C(1) << 15)) << 1; // Account for sign extension in daddiu.
3530 tmp += (tmp & (UINT64_C(1) << 31)) << 1; // Account for sign extension in daui.
3531 int16_t mid = Low16Bits(tmp);
3532 int16_t upper = High16Bits(tmp);
3533 int16_t hi = Low16Bits(High32Bits(tmp));
3534 Daui(AT, base, upper);
3535 if (hi != 0) {
3536 CHECK_EQ(hi, 1);
3537 Dahi(AT, hi);
3538 }
3539 if (mid != 0) {
3540 Daddiu(AT, AT, mid);
3541 }
3542 offset = low;
3543 }
3544 base = AT;
3545 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
3546 CHECK(IsInt<10>(offset >> element_size_shift));
3547}
3548
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003549void Mips64Assembler::LoadFromOffset(LoadOperandType type,
3550 GpuRegister reg,
3551 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003552 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003553 LoadFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003554}
3555
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003556void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type,
3557 FpuRegister reg,
3558 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003559 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003560 LoadFpuFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003561}
3562
3563void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
3564 size_t size) {
3565 Mips64ManagedRegister dst = m_dst.AsMips64();
3566 if (dst.IsNoRegister()) {
3567 CHECK_EQ(0u, size) << dst;
3568 } else if (dst.IsGpuRegister()) {
3569 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003570 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
3571 } else if (size == 8) {
3572 CHECK_EQ(8u, size) << dst;
3573 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
3574 } else {
3575 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
3576 }
3577 } else if (dst.IsFpuRegister()) {
3578 if (size == 4) {
3579 CHECK_EQ(4u, size) << dst;
3580 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
3581 } else if (size == 8) {
3582 CHECK_EQ(8u, size) << dst;
3583 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
3584 } else {
3585 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
3586 }
3587 }
3588}
3589
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003590void Mips64Assembler::StoreToOffset(StoreOperandType type,
3591 GpuRegister reg,
3592 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003593 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003594 StoreToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003595}
3596
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003597void Mips64Assembler::StoreFpuToOffset(StoreOperandType type,
3598 FpuRegister reg,
3599 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08003600 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01003601 StoreFpuToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003602}
3603
David Srbeckydd973932015-04-07 20:29:48 +01003604static dwarf::Reg DWARFReg(GpuRegister reg) {
3605 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
3606}
3607
Andreas Gampe57b34292015-01-14 15:45:59 -08003608constexpr size_t kFramePointerSize = 8;
3609
Vladimir Marko32248382016-05-19 10:37:24 +01003610void Mips64Assembler::BuildFrame(size_t frame_size,
3611 ManagedRegister method_reg,
3612 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08003613 const ManagedRegisterEntrySpills& entry_spills) {
3614 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003615 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08003616
3617 // Increase frame to required size.
3618 IncreaseFrameSize(frame_size);
3619
3620 // Push callee saves and return address
3621 int stack_offset = frame_size - kFramePointerSize;
3622 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003623 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003624 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
3625 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01003626 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08003627 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003628 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003629 }
3630
3631 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07003632 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08003633
3634 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07003635 int32_t offset = frame_size + kFramePointerSize;
Vladimir Marko35d5b8a2018-07-03 09:18:32 +01003636 for (const ManagedRegisterSpill& spill : entry_spills) {
3637 Mips64ManagedRegister reg = spill.AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08003638 int32_t size = spill.getSize();
3639 if (reg.IsNoRegister()) {
3640 // only increment stack offset.
3641 offset += size;
3642 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003643 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
3644 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003645 offset += size;
3646 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003647 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
3648 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08003649 offset += size;
3650 }
3651 }
3652}
3653
3654void Mips64Assembler::RemoveFrame(size_t frame_size,
Roland Levillain0d127e12017-07-05 17:01:11 +01003655 ArrayRef<const ManagedRegister> callee_save_regs,
3656 bool may_suspend ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003657 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003658 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01003659 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08003660
3661 // Pop callee saves and return address
3662 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
3663 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01003664 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08003665 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003666 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08003667 stack_offset += kFramePointerSize;
3668 }
3669 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01003670 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08003671
3672 // Decrease frame to required size.
3673 DecreaseFrameSize(frame_size);
3674
3675 // Then jump to the return address.
3676 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003677 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01003678
3679 // The CFI should be restored for any code that follows the exit block.
3680 cfi_.RestoreState();
3681 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08003682}
3683
3684void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003685 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003686 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003687 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01003688 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08003689}
3690
3691void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003692 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003693 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07003694 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01003695 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08003696}
3697
3698void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
3699 Mips64ManagedRegister src = msrc.AsMips64();
3700 if (src.IsNoRegister()) {
3701 CHECK_EQ(0u, size);
3702 } else if (src.IsGpuRegister()) {
3703 CHECK(size == 4 || size == 8) << size;
3704 if (size == 8) {
3705 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3706 } else if (size == 4) {
3707 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
3708 } else {
3709 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
3710 }
3711 } else if (src.IsFpuRegister()) {
3712 CHECK(size == 4 || size == 8) << size;
3713 if (size == 8) {
3714 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
3715 } else if (size == 4) {
3716 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
3717 } else {
3718 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
3719 }
3720 }
3721}
3722
3723void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
3724 Mips64ManagedRegister src = msrc.AsMips64();
3725 CHECK(src.IsGpuRegister());
3726 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
3727}
3728
3729void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
3730 Mips64ManagedRegister src = msrc.AsMips64();
3731 CHECK(src.IsGpuRegister());
3732 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3733}
3734
3735void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
3736 ManagedRegister mscratch) {
3737 Mips64ManagedRegister scratch = mscratch.AsMips64();
3738 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07003739 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08003740 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
3741}
3742
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003743void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
3744 FrameOffset fr_offs,
3745 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003746 Mips64ManagedRegister scratch = mscratch.AsMips64();
3747 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07003748 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003749 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
3750}
3751
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003752void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003753 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
3754}
3755
3756void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
3757 FrameOffset in_off, ManagedRegister mscratch) {
3758 Mips64ManagedRegister src = msrc.AsMips64();
3759 Mips64ManagedRegister scratch = mscratch.AsMips64();
3760 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
3761 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
3762 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
3763}
3764
3765void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
3766 return EmitLoad(mdest, SP, src.Int32Value(), size);
3767}
3768
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003769void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003770 return EmitLoad(mdest, S1, src.Int32Value(), size);
3771}
3772
3773void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
3774 Mips64ManagedRegister dest = mdest.AsMips64();
3775 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07003776 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003777}
3778
Mathieu Chartiere401d142015-04-22 13:56:20 -07003779void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01003780 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003781 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07003782 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
3783 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003784 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08003785 if (unpoison_reference) {
3786 MaybeUnpoisonHeapReference(dest.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003787 }
3788}
3789
3790void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003791 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003792 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07003793 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003794 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
3795 base.AsMips64().AsGpuRegister(), offs.Int32Value());
3796}
3797
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003798void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003799 Mips64ManagedRegister dest = mdest.AsMips64();
3800 CHECK(dest.IsGpuRegister());
3801 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
3802}
3803
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003804void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
3805 size_t size ATTRIBUTE_UNUSED) {
3806 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08003807}
3808
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003809void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
3810 size_t size ATTRIBUTE_UNUSED) {
3811 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08003812}
3813
3814void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
3815 Mips64ManagedRegister dest = mdest.AsMips64();
3816 Mips64ManagedRegister src = msrc.AsMips64();
3817 if (!dest.Equals(src)) {
3818 if (dest.IsGpuRegister()) {
3819 CHECK(src.IsGpuRegister()) << src;
3820 Move(dest.AsGpuRegister(), src.AsGpuRegister());
3821 } else if (dest.IsFpuRegister()) {
3822 CHECK(src.IsFpuRegister()) << src;
3823 if (size == 4) {
3824 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
3825 } else if (size == 8) {
3826 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
3827 } else {
3828 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3829 }
3830 }
3831 }
3832}
3833
3834void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
3835 ManagedRegister mscratch) {
3836 Mips64ManagedRegister scratch = mscratch.AsMips64();
3837 CHECK(scratch.IsGpuRegister()) << scratch;
3838 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
3839 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
3840}
3841
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003842void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
3843 ThreadOffset64 thr_offs,
3844 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003845 Mips64ManagedRegister scratch = mscratch.AsMips64();
3846 CHECK(scratch.IsGpuRegister()) << scratch;
3847 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
3848 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
3849}
3850
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003851void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
3852 FrameOffset fr_offs,
3853 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003854 Mips64ManagedRegister scratch = mscratch.AsMips64();
3855 CHECK(scratch.IsGpuRegister()) << scratch;
3856 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
3857 SP, fr_offs.Int32Value());
3858 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
3859 S1, thr_offs.Int32Value());
3860}
3861
3862void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
3863 ManagedRegister mscratch, size_t size) {
3864 Mips64ManagedRegister scratch = mscratch.AsMips64();
3865 CHECK(scratch.IsGpuRegister()) << scratch;
3866 CHECK(size == 4 || size == 8) << size;
3867 if (size == 4) {
3868 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003869 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003870 } else if (size == 8) {
3871 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
3872 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
3873 } else {
3874 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3875 }
3876}
3877
3878void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003879 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003880 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3881 CHECK(size == 4 || size == 8) << size;
3882 if (size == 4) {
3883 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
3884 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003885 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003886 } else if (size == 8) {
3887 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
3888 src_offset.Int32Value());
3889 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
3890 } else {
3891 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3892 }
3893}
3894
3895void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003896 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003897 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3898 CHECK(size == 4 || size == 8) << size;
3899 if (size == 4) {
3900 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003901 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003902 dest_offset.Int32Value());
3903 } else if (size == 8) {
3904 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
3905 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
3906 dest_offset.Int32Value());
3907 } else {
3908 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3909 }
3910}
3911
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003912void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3913 FrameOffset src_base ATTRIBUTE_UNUSED,
3914 Offset src_offset ATTRIBUTE_UNUSED,
3915 ManagedRegister mscratch ATTRIBUTE_UNUSED,
3916 size_t size ATTRIBUTE_UNUSED) {
3917 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003918}
3919
3920void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003921 ManagedRegister src, Offset src_offset,
3922 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003923 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
3924 CHECK(size == 4 || size == 8) << size;
3925 if (size == 4) {
3926 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02003927 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003928 } else if (size == 8) {
3929 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
3930 src_offset.Int32Value());
3931 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
3932 dest_offset.Int32Value());
3933 } else {
3934 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
3935 }
3936}
3937
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003938void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3939 Offset dest_offset ATTRIBUTE_UNUSED,
3940 FrameOffset src ATTRIBUTE_UNUSED,
3941 Offset src_offset ATTRIBUTE_UNUSED,
3942 ManagedRegister mscratch ATTRIBUTE_UNUSED,
3943 size_t size ATTRIBUTE_UNUSED) {
3944 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003945}
3946
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003947void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003948 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003949 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003950}
3951
3952void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003953 FrameOffset handle_scope_offset,
3954 ManagedRegister min_reg,
3955 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003956 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
3957 Mips64ManagedRegister in_reg = min_reg.AsMips64();
3958 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
3959 CHECK(out_reg.IsGpuRegister()) << out_reg;
3960 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003961 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08003962 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
3963 // the address in the handle scope holding the reference.
3964 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
3965 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07003966 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08003967 SP, handle_scope_offset.Int32Value());
3968 in_reg = out_reg;
3969 }
3970 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003971 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08003972 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07003973 Beqzc(in_reg.AsGpuRegister(), &null_arg);
3974 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
3975 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003976 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003977 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003978 }
3979}
3980
3981void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07003982 FrameOffset handle_scope_offset,
3983 ManagedRegister mscratch,
3984 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003985 Mips64ManagedRegister scratch = mscratch.AsMips64();
3986 CHECK(scratch.IsGpuRegister()) << scratch;
3987 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003988 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07003989 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08003990 handle_scope_offset.Int32Value());
3991 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
3992 // the address in the handle scope holding the reference.
3993 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07003994 Beqzc(scratch.AsGpuRegister(), &null_arg);
3995 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
3996 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08003997 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07003998 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08003999 }
4000 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
4001}
4002
4003// Given a handle scope entry, load the associated reference.
4004void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07004005 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08004006 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
4007 Mips64ManagedRegister in_reg = min_reg.AsMips64();
4008 CHECK(out_reg.IsGpuRegister()) << out_reg;
4009 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004010 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08004011 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07004012 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08004013 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07004014 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08004015 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
4016 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07004017 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08004018}
4019
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004020void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
4021 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08004022 // TODO: not validating references
4023}
4024
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004025void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
4026 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08004027 // TODO: not validating references
4028}
4029
4030void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
4031 Mips64ManagedRegister base = mbase.AsMips64();
4032 Mips64ManagedRegister scratch = mscratch.AsMips64();
4033 CHECK(base.IsGpuRegister()) << base;
4034 CHECK(scratch.IsGpuRegister()) << scratch;
4035 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
4036 base.AsGpuRegister(), offset.Int32Value());
4037 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004038 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08004039 // TODO: place reference map on call
4040}
4041
4042void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
4043 Mips64ManagedRegister scratch = mscratch.AsMips64();
4044 CHECK(scratch.IsGpuRegister()) << scratch;
4045 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07004046 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08004047 SP, base.Int32Value());
4048 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
4049 scratch.AsGpuRegister(), offset.Int32Value());
4050 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004051 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08004052 // TODO: place reference map on call
4053}
4054
Andreas Gampe3b165bc2016-08-01 22:07:04 -07004055void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
4056 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004057 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08004058}
4059
4060void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
4061 Move(tr.AsMips64().AsGpuRegister(), S1);
4062}
4063
4064void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004065 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08004066 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
4067}
4068
4069void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
4070 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004071 exception_blocks_.emplace_back(scratch, stack_adjust);
4072 LoadFromOffset(kLoadDoubleword,
4073 scratch.AsGpuRegister(),
4074 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07004075 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004076 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08004077}
4078
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004079void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
4080 Bind(exception->Entry());
4081 if (exception->stack_adjust_ != 0) { // Fix up the frame.
4082 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08004083 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004084 // Pass exception object as argument.
4085 // Don't care about preserving A0 as this call won't return.
4086 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
4087 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08004088 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004089 LoadFromOffset(kLoadDoubleword,
4090 T9,
4091 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07004092 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004093 Jr(T9);
4094 Nop();
4095
Andreas Gampe57b34292015-01-14 15:45:59 -08004096 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07004097 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08004098}
4099
4100} // namespace mips64
4101} // namespace art