blob: c14315a91e1199708ec0fa83549cf231ad74443b [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_mips64.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080020#include "base/casts.h"
21#include "entrypoints/quick/quick_entrypoints.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070022#include "entrypoints/quick/quick_entrypoints_enum.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "memory_region.h"
24#include "thread.h"
25
26namespace art {
27namespace mips64 {
28
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize,
30 "Unexpected Mips64 pointer size.");
31static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size.");
32
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034void Mips64Assembler::FinalizeCode() {
35 for (auto& exception_block : exception_blocks_) {
36 EmitExceptionPoll(&exception_block);
37 }
Alexey Frunze0960ac52016-12-20 17:24:59 -080038 ReserveJumpTableSpace();
Alexey Frunze19f6c692016-11-30 19:19:55 -080039 EmitLiterals();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070040 PromoteBranches();
41}
42
43void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) {
44 EmitBranches();
Alexey Frunze0960ac52016-12-20 17:24:59 -080045 EmitJumpTables();
Alexey Frunzea0e87b02015-09-24 22:57:20 -070046 Assembler::FinalizeInstructions(region);
47 PatchCFI();
48}
49
50void Mips64Assembler::PatchCFI() {
51 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
52 return;
53 }
54
55 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
56 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
57 const std::vector<uint8_t>& old_stream = data.first;
58 const std::vector<DelayedAdvancePC>& advances = data.second;
59
60 // Refill our data buffer with patched opcodes.
61 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16);
62 size_t stream_pos = 0;
63 for (const DelayedAdvancePC& advance : advances) {
64 DCHECK_GE(advance.stream_pos, stream_pos);
65 // Copy old data up to the point where advance was issued.
66 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos);
67 stream_pos = advance.stream_pos;
68 // Insert the advance command with its final offset.
69 size_t final_pc = GetAdjustedPosition(advance.pc);
70 cfi().AdvancePC(final_pc);
71 }
72 // Copy the final segment if any.
73 cfi().AppendRawData(old_stream, stream_pos, old_stream.size());
74}
75
76void Mips64Assembler::EmitBranches() {
77 CHECK(!overwriting_);
78 // Switch from appending instructions at the end of the buffer to overwriting
79 // existing instructions (branch placeholders) in the buffer.
80 overwriting_ = true;
81 for (auto& branch : branches_) {
82 EmitBranch(&branch);
83 }
84 overwriting_ = false;
85}
86
Alexey Frunze4dda3372015-06-01 18:31:49 -070087void Mips64Assembler::Emit(uint32_t value) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -070088 if (overwriting_) {
89 // Branches to labels are emitted into their placeholders here.
90 buffer_.Store<uint32_t>(overwrite_location_, value);
91 overwrite_location_ += sizeof(uint32_t);
92 } else {
93 // Other instructions are simply appended at the end here.
94 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
95 buffer_.Emit<uint32_t>(value);
96 }
Andreas Gampe57b34292015-01-14 15:45:59 -080097}
98
99void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
100 int shamt, int funct) {
101 CHECK_NE(rs, kNoGpuRegister);
102 CHECK_NE(rt, kNoGpuRegister);
103 CHECK_NE(rd, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700104 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
105 static_cast<uint32_t>(rs) << kRsShift |
106 static_cast<uint32_t>(rt) << kRtShift |
107 static_cast<uint32_t>(rd) << kRdShift |
108 shamt << kShamtShift |
109 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800110 Emit(encoding);
111}
112
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700113void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
114 int shamt, int funct) {
115 CHECK_NE(rs, kNoGpuRegister);
116 CHECK_NE(rd, kNoGpuRegister);
117 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
118 static_cast<uint32_t>(rs) << kRsShift |
119 static_cast<uint32_t>(ZERO) << kRtShift |
120 static_cast<uint32_t>(rd) << kRdShift |
121 shamt << kShamtShift |
122 funct;
123 Emit(encoding);
124}
125
126void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
127 int shamt, int funct) {
128 CHECK_NE(rt, kNoGpuRegister);
129 CHECK_NE(rd, kNoGpuRegister);
130 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
131 static_cast<uint32_t>(ZERO) << kRsShift |
132 static_cast<uint32_t>(rt) << kRtShift |
133 static_cast<uint32_t>(rd) << kRdShift |
134 shamt << kShamtShift |
135 funct;
136 Emit(encoding);
137}
138
Andreas Gampe57b34292015-01-14 15:45:59 -0800139void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
140 CHECK_NE(rs, kNoGpuRegister);
141 CHECK_NE(rt, kNoGpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700142 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
143 static_cast<uint32_t>(rs) << kRsShift |
144 static_cast<uint32_t>(rt) << kRtShift |
145 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800146 Emit(encoding);
147}
148
Alexey Frunze4dda3372015-06-01 18:31:49 -0700149void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) {
150 CHECK_NE(rs, kNoGpuRegister);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700151 CHECK(IsUint<21>(imm21)) << imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700152 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
153 static_cast<uint32_t>(rs) << kRsShift |
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700154 imm21;
Alexey Frunze4dda3372015-06-01 18:31:49 -0700155 Emit(encoding);
156}
157
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700158void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) {
159 CHECK(IsUint<26>(imm26)) << imm26;
160 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
Andreas Gampe57b34292015-01-14 15:45:59 -0800161 Emit(encoding);
162}
163
164void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
Alexey Frunze4dda3372015-06-01 18:31:49 -0700165 int funct) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800166 CHECK_NE(ft, kNoFpuRegister);
167 CHECK_NE(fs, kNoFpuRegister);
168 CHECK_NE(fd, kNoFpuRegister);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700169 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
170 fmt << kFmtShift |
171 static_cast<uint32_t>(ft) << kFtShift |
172 static_cast<uint32_t>(fs) << kFsShift |
173 static_cast<uint32_t>(fd) << kFdShift |
174 funct;
Andreas Gampe57b34292015-01-14 15:45:59 -0800175 Emit(encoding);
176}
177
Alexey Frunze4dda3372015-06-01 18:31:49 -0700178void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) {
179 CHECK_NE(ft, kNoFpuRegister);
180 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
181 fmt << kFmtShift |
182 static_cast<uint32_t>(ft) << kFtShift |
183 imm;
Andreas Gampe57b34292015-01-14 15:45:59 -0800184 Emit(encoding);
185}
186
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000187void Mips64Assembler::EmitMsa3R(int operation,
188 int df,
189 VectorRegister wt,
190 VectorRegister ws,
191 VectorRegister wd,
192 int minor_opcode) {
193 CHECK_NE(wt, kNoVectorRegister);
194 CHECK_NE(ws, kNoVectorRegister);
195 CHECK_NE(wd, kNoVectorRegister);
196 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
197 operation << kMsaOperationShift |
198 df << kDfShift |
199 static_cast<uint32_t>(wt) << kWtShift |
200 static_cast<uint32_t>(ws) << kWsShift |
201 static_cast<uint32_t>(wd) << kWdShift |
202 minor_opcode;
203 Emit(encoding);
204}
205
206void Mips64Assembler::EmitMsaBIT(int operation,
207 int df_m,
208 VectorRegister ws,
209 VectorRegister wd,
210 int minor_opcode) {
211 CHECK_NE(ws, kNoVectorRegister);
212 CHECK_NE(wd, kNoVectorRegister);
213 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
214 operation << kMsaOperationShift |
215 df_m << kDfMShift |
216 static_cast<uint32_t>(ws) << kWsShift |
217 static_cast<uint32_t>(wd) << kWdShift |
218 minor_opcode;
219 Emit(encoding);
220}
221
222void Mips64Assembler::EmitMsaELM(int operation,
223 int df_n,
224 VectorRegister ws,
225 VectorRegister wd,
226 int minor_opcode) {
227 CHECK_NE(ws, kNoVectorRegister);
228 CHECK_NE(wd, kNoVectorRegister);
229 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
230 operation << kMsaELMOperationShift |
231 df_n << kDfNShift |
232 static_cast<uint32_t>(ws) << kWsShift |
233 static_cast<uint32_t>(wd) << kWdShift |
234 minor_opcode;
235 Emit(encoding);
236}
237
238void Mips64Assembler::EmitMsaMI10(int s10,
239 GpuRegister rs,
240 VectorRegister wd,
241 int minor_opcode,
242 int df) {
243 CHECK_NE(rs, kNoGpuRegister);
244 CHECK_NE(wd, kNoVectorRegister);
245 CHECK(IsUint<10>(s10)) << s10;
246 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
247 s10 << kS10Shift |
248 static_cast<uint32_t>(rs) << kWsShift |
249 static_cast<uint32_t>(wd) << kWdShift |
250 minor_opcode << kS10MinorShift |
251 df;
252 Emit(encoding);
253}
254
255void Mips64Assembler::EmitMsa2R(int operation,
256 int df,
257 VectorRegister ws,
258 VectorRegister wd,
259 int minor_opcode) {
260 CHECK_NE(ws, kNoVectorRegister);
261 CHECK_NE(wd, kNoVectorRegister);
262 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
263 operation << kMsa2ROperationShift |
264 df << kDf2RShift |
265 static_cast<uint32_t>(ws) << kWsShift |
266 static_cast<uint32_t>(wd) << kWdShift |
267 minor_opcode;
268 Emit(encoding);
269}
270
271void Mips64Assembler::EmitMsa2RF(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 << kMsa2RFOperationShift |
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
Andreas Gampe57b34292015-01-14 15:45:59 -0800287void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
288 EmitR(0, rs, rt, rd, 0, 0x21);
289}
290
291void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
292 EmitI(0x9, rs, rt, imm16);
293}
294
Alexey Frunze4dda3372015-06-01 18:31:49 -0700295void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
296 EmitR(0, rs, rt, rd, 0, 0x2d);
297}
298
Andreas Gampe57b34292015-01-14 15:45:59 -0800299void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
300 EmitI(0x19, rs, rt, imm16);
301}
302
Andreas Gampe57b34292015-01-14 15:45:59 -0800303void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
304 EmitR(0, rs, rt, rd, 0, 0x23);
305}
306
Alexey Frunze4dda3372015-06-01 18:31:49 -0700307void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
308 EmitR(0, rs, rt, rd, 0, 0x2f);
309}
310
Alexey Frunze4dda3372015-06-01 18:31:49 -0700311void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
312 EmitR(0, rs, rt, rd, 2, 0x18);
313}
314
Alexey Frunzec857c742015-09-23 15:12:39 -0700315void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
316 EmitR(0, rs, rt, rd, 3, 0x18);
317}
318
Alexey Frunze4dda3372015-06-01 18:31:49 -0700319void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
320 EmitR(0, rs, rt, rd, 2, 0x1a);
321}
322
323void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
324 EmitR(0, rs, rt, rd, 3, 0x1a);
325}
326
327void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
328 EmitR(0, rs, rt, rd, 2, 0x1b);
329}
330
331void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
332 EmitR(0, rs, rt, rd, 3, 0x1b);
333}
334
335void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
336 EmitR(0, rs, rt, rd, 2, 0x1c);
337}
338
Alexey Frunzec857c742015-09-23 15:12:39 -0700339void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
340 EmitR(0, rs, rt, rd, 3, 0x1c);
341}
342
Alexey Frunze4dda3372015-06-01 18:31:49 -0700343void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
344 EmitR(0, rs, rt, rd, 2, 0x1e);
345}
346
347void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
348 EmitR(0, rs, rt, rd, 3, 0x1e);
349}
350
351void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
352 EmitR(0, rs, rt, rd, 2, 0x1f);
353}
354
355void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
356 EmitR(0, rs, rt, rd, 3, 0x1f);
357}
358
Andreas Gampe57b34292015-01-14 15:45:59 -0800359void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
360 EmitR(0, rs, rt, rd, 0, 0x24);
361}
362
363void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
364 EmitI(0xc, rs, rt, imm16);
365}
366
367void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
368 EmitR(0, rs, rt, rd, 0, 0x25);
369}
370
371void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
372 EmitI(0xd, rs, rt, imm16);
373}
374
375void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
376 EmitR(0, rs, rt, rd, 0, 0x26);
377}
378
379void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
380 EmitI(0xe, rs, rt, imm16);
381}
382
383void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
384 EmitR(0, rs, rt, rd, 0, 0x27);
385}
386
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700387void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
388 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
389}
390
391void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
392 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
393}
394
Alexey Frunze4dda3372015-06-01 18:31:49 -0700395void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
396 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800397}
398
Alexey Frunze4dda3372015-06-01 18:31:49 -0700399void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
400 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800401}
402
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700403void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
404 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
405}
406
407void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
408 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
409}
410
Lazar Trsicd9672662015-09-03 17:33:01 +0200411void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
412 CHECK(IsUint<5>(pos)) << pos;
413 CHECK(IsUint<5>(size - 1)) << size;
414 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
415}
416
417void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
418 CHECK(IsUint<5>(pos - 32)) << pos;
419 CHECK(IsUint<5>(size - 1)) << size;
420 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
421 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800422}
423
Chris Larsene3660592016-11-09 11:13:42 -0800424void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
425 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
426 int sa = saPlusOne - 1;
427 EmitR(0x0, rs, rt, rd, sa, 0x05);
428}
429
430void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
431 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
432 int sa = saPlusOne - 1;
433 EmitR(0x0, rs, rt, rd, sa, 0x15);
434}
435
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700436void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
437 EmitRtd(0x1f, rt, rd, 2, 0x20);
438}
439
440void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200441 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700442 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
443}
444
445void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200446 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700447 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
448}
449
450void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200451 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700452 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
453}
454
455void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200456 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700457 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
458}
459
Alexey Frunze4dda3372015-06-01 18:31:49 -0700460void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
461 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
462}
463
464void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
465 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
466}
467
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700468void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
469 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
470}
471
Alexey Frunze4dda3372015-06-01 18:31:49 -0700472void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
473 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
474}
475
476void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800477 EmitR(0, rs, rt, rd, 0, 0x04);
478}
479
Chris Larsen9aebff22015-09-22 17:54:15 -0700480void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
481 EmitR(0, rs, rt, rd, 1, 0x06);
482}
483
Alexey Frunze4dda3372015-06-01 18:31:49 -0700484void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800485 EmitR(0, rs, rt, rd, 0, 0x06);
486}
487
Alexey Frunze4dda3372015-06-01 18:31:49 -0700488void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800489 EmitR(0, rs, rt, rd, 0, 0x07);
490}
491
Alexey Frunze4dda3372015-06-01 18:31:49 -0700492void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
493 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
494}
495
496void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
497 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
498}
499
Chris Larsen9aebff22015-09-22 17:54:15 -0700500void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
501 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
502}
503
Alexey Frunze4dda3372015-06-01 18:31:49 -0700504void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
505 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
506}
507
508void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
509 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
510}
511
512void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
513 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
514}
515
Chris Larsen9aebff22015-09-22 17:54:15 -0700516void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
517 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
518}
519
Alexey Frunze4dda3372015-06-01 18:31:49 -0700520void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
521 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
522}
523
524void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
525 EmitR(0, rs, rt, rd, 0, 0x14);
526}
527
528void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
529 EmitR(0, rs, rt, rd, 0, 0x16);
530}
531
Chris Larsen9aebff22015-09-22 17:54:15 -0700532void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
533 EmitR(0, rs, rt, rd, 1, 0x16);
534}
535
Alexey Frunze4dda3372015-06-01 18:31:49 -0700536void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
537 EmitR(0, rs, rt, rd, 0, 0x17);
538}
539
Andreas Gampe57b34292015-01-14 15:45:59 -0800540void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
541 EmitI(0x20, rs, rt, imm16);
542}
543
544void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
545 EmitI(0x21, rs, rt, imm16);
546}
547
548void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
549 EmitI(0x23, rs, rt, imm16);
550}
551
552void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
553 EmitI(0x37, rs, rt, imm16);
554}
555
556void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
557 EmitI(0x24, rs, rt, imm16);
558}
559
560void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
561 EmitI(0x25, rs, rt, imm16);
562}
563
Douglas Leungd90957f2015-04-30 19:22:49 -0700564void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
565 EmitI(0x27, rs, rt, imm16);
566}
567
Alexey Frunze19f6c692016-11-30 19:19:55 -0800568void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
569 CHECK(IsUint<19>(imm19)) << imm19;
570 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
571}
572
573void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
574 CHECK(IsUint<19>(imm19)) << imm19;
575 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
576}
577
578void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
579 CHECK(IsUint<18>(imm18)) << imm18;
580 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
581}
582
Andreas Gampe57b34292015-01-14 15:45:59 -0800583void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
584 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
585}
586
Alexey Frunze0960ac52016-12-20 17:24:59 -0800587void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
588 EmitI(0xf, rs, rt, imm16);
589}
590
Alexey Frunzec061de12017-02-14 13:27:23 -0800591void Mips64Assembler::Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
592 CHECK_NE(rs, ZERO);
593 EmitI(0x1d, rs, rt, imm16);
594}
595
Alexey Frunze4dda3372015-06-01 18:31:49 -0700596void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
597 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
598}
599
600void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
601 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
602}
603
604void Mips64Assembler::Sync(uint32_t stype) {
605 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
606 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
607}
608
Andreas Gampe57b34292015-01-14 15:45:59 -0800609void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
610 EmitI(0x28, rs, rt, imm16);
611}
612
613void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
614 EmitI(0x29, rs, rt, imm16);
615}
616
617void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
618 EmitI(0x2b, rs, rt, imm16);
619}
620
621void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
622 EmitI(0x3f, rs, rt, imm16);
623}
624
625void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
626 EmitR(0, rs, rt, rd, 0, 0x2a);
627}
628
629void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
630 EmitR(0, rs, rt, rd, 0, 0x2b);
631}
632
633void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
634 EmitI(0xa, rs, rt, imm16);
635}
636
637void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
638 EmitI(0xb, rs, rt, imm16);
639}
640
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700641void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
642 EmitR(0, rs, rt, rd, 0, 0x35);
643}
644
645void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
646 EmitR(0, rs, rt, rd, 0, 0x37);
647}
648
649void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
650 EmitRsd(0, rs, rd, 0x01, 0x10);
651}
652
653void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
654 EmitRsd(0, rs, rd, 0x01, 0x11);
655}
656
657void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
658 EmitRsd(0, rs, rd, 0x01, 0x12);
659}
660
661void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
662 EmitRsd(0, rs, rd, 0x01, 0x13);
663}
664
Alexey Frunze4dda3372015-06-01 18:31:49 -0700665void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
666 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800667}
668
669void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700670 Jalr(RA, rs);
671}
672
673void Mips64Assembler::Jr(GpuRegister rs) {
674 Jalr(ZERO, rs);
675}
676
677void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
678 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
679}
680
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700681void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
682 CHECK(IsUint<19>(imm19)) << imm19;
683 EmitI21(0x3B, rs, imm19);
684}
685
686void Mips64Assembler::Bc(uint32_t imm26) {
687 EmitI26(0x32, imm26);
688}
689
Alexey Frunze19f6c692016-11-30 19:19:55 -0800690void Mips64Assembler::Balc(uint32_t imm26) {
691 EmitI26(0x3A, imm26);
692}
693
Alexey Frunze4dda3372015-06-01 18:31:49 -0700694void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
695 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
696}
697
698void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
699 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
700}
701
702void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
703 CHECK_NE(rs, ZERO);
704 CHECK_NE(rt, ZERO);
705 CHECK_NE(rs, rt);
706 EmitI(0x17, rs, rt, imm16);
707}
708
709void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
710 CHECK_NE(rt, ZERO);
711 EmitI(0x17, rt, rt, imm16);
712}
713
714void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
715 CHECK_NE(rt, ZERO);
716 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
717}
718
719void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
720 CHECK_NE(rs, ZERO);
721 CHECK_NE(rt, ZERO);
722 CHECK_NE(rs, rt);
723 EmitI(0x16, rs, rt, imm16);
724}
725
726void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
727 CHECK_NE(rt, ZERO);
728 EmitI(0x16, rt, rt, imm16);
729}
730
731void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
732 CHECK_NE(rt, ZERO);
733 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
734}
735
736void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
737 CHECK_NE(rs, ZERO);
738 CHECK_NE(rt, ZERO);
739 CHECK_NE(rs, rt);
740 EmitI(0x7, rs, rt, imm16);
741}
742
743void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
744 CHECK_NE(rs, ZERO);
745 CHECK_NE(rt, ZERO);
746 CHECK_NE(rs, rt);
747 EmitI(0x6, rs, rt, imm16);
748}
749
750void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
751 CHECK_NE(rs, ZERO);
752 CHECK_NE(rt, ZERO);
753 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700754 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700755}
756
757void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
758 CHECK_NE(rs, ZERO);
759 CHECK_NE(rt, ZERO);
760 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700761 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700762}
763
764void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
765 CHECK_NE(rs, ZERO);
766 EmitI21(0x36, rs, imm21);
767}
768
769void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
770 CHECK_NE(rs, ZERO);
771 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800772}
773
Alexey Frunze299a9392015-12-08 16:08:02 -0800774void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
775 EmitFI(0x11, 0x9, ft, imm16);
776}
777
778void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
779 EmitFI(0x11, 0xD, ft, imm16);
780}
781
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700782void Mips64Assembler::EmitBcondc(BranchCondition cond,
783 GpuRegister rs,
784 GpuRegister rt,
785 uint32_t imm16_21) {
786 switch (cond) {
787 case kCondLT:
788 Bltc(rs, rt, imm16_21);
789 break;
790 case kCondGE:
791 Bgec(rs, rt, imm16_21);
792 break;
793 case kCondLE:
794 Bgec(rt, rs, imm16_21);
795 break;
796 case kCondGT:
797 Bltc(rt, rs, imm16_21);
798 break;
799 case kCondLTZ:
800 CHECK_EQ(rt, ZERO);
801 Bltzc(rs, imm16_21);
802 break;
803 case kCondGEZ:
804 CHECK_EQ(rt, ZERO);
805 Bgezc(rs, imm16_21);
806 break;
807 case kCondLEZ:
808 CHECK_EQ(rt, ZERO);
809 Blezc(rs, imm16_21);
810 break;
811 case kCondGTZ:
812 CHECK_EQ(rt, ZERO);
813 Bgtzc(rs, imm16_21);
814 break;
815 case kCondEQ:
816 Beqc(rs, rt, imm16_21);
817 break;
818 case kCondNE:
819 Bnec(rs, rt, imm16_21);
820 break;
821 case kCondEQZ:
822 CHECK_EQ(rt, ZERO);
823 Beqzc(rs, imm16_21);
824 break;
825 case kCondNEZ:
826 CHECK_EQ(rt, ZERO);
827 Bnezc(rs, imm16_21);
828 break;
829 case kCondLTU:
830 Bltuc(rs, rt, imm16_21);
831 break;
832 case kCondGEU:
833 Bgeuc(rs, rt, imm16_21);
834 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800835 case kCondF:
836 CHECK_EQ(rt, ZERO);
837 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
838 break;
839 case kCondT:
840 CHECK_EQ(rt, ZERO);
841 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
842 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700843 case kUncond:
844 LOG(FATAL) << "Unexpected branch condition " << cond;
845 UNREACHABLE();
846 }
847}
848
Andreas Gampe57b34292015-01-14 15:45:59 -0800849void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
850 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
851}
852
853void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
854 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
855}
856
857void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
858 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
859}
860
861void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
862 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
863}
864
865void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700866 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800867}
868
869void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700870 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800871}
872
873void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700874 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800875}
876
877void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700878 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800879}
880
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700881void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
882 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
883}
884
885void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
886 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
887}
888
889void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
890 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
891}
892
893void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
894 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
895}
896
Andreas Gampe57b34292015-01-14 15:45:59 -0800897void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
898 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
899}
900
901void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700902 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
903}
904
905void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
906 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
907}
908
909void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
910 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
911}
912
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700913void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
914 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
915}
916
917void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
918 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
919}
920
921void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
922 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
923}
924
925void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
926 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
927}
928
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800929void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
930 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
931}
932
933void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
934 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
935}
936
937void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
938 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
939}
940
941void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
942 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
943}
944
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700945void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
946 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
947}
948
949void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
950 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
951}
952
953void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
954 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
955}
956
957void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
958 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
959}
960
961void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
962 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
963}
964
965void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
966 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
967}
968
969void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
970 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
971}
972
973void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
974 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
975}
976
977void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
978 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
979}
980
981void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
982 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
983}
984
985void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
986 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
987}
988
989void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
990 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
991}
992
993void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
994 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
995}
996
997void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
998 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
999}
1000
1001void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1002 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
1003}
1004
1005void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1006 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
1007}
1008
1009void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1010 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
1011}
1012
1013void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1014 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
1015}
1016
Alexey Frunze299a9392015-12-08 16:08:02 -08001017void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1018 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
1019}
1020
1021void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1022 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
1023}
1024
1025void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1026 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
1027}
1028
1029void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1030 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
1031}
1032
1033void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1034 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
1035}
1036
1037void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1038 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
1039}
1040
1041void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1042 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
1043}
1044
1045void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1046 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
1047}
1048
1049void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1050 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
1051}
1052
1053void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1054 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
1055}
1056
1057void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1058 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
1059}
1060
1061void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1062 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
1063}
1064
1065void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1066 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
1067}
1068
1069void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1070 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
1071}
1072
1073void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1074 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
1075}
1076
1077void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1078 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
1079}
1080
1081void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1082 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
1083}
1084
1085void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1086 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
1087}
1088
1089void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1090 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
1091}
1092
1093void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
1094 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
1095}
1096
Alexey Frunze4dda3372015-06-01 18:31:49 -07001097void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
1098 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
1099}
1100
1101void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
1102 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
1103}
1104
1105void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
1106 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
1107}
1108
1109void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
1110 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -08001111}
1112
Chris Larsen51417632015-10-02 13:24:25 -07001113void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
1114 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
1115}
1116
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001117void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
1118 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
1119}
1120
Andreas Gampe57b34292015-01-14 15:45:59 -08001121void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
1122 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1123}
1124
Lazar Trsicd9672662015-09-03 17:33:01 +02001125void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1126 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1127}
1128
Alexey Frunze4dda3372015-06-01 18:31:49 -07001129void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1130 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1131}
1132
Lazar Trsicd9672662015-09-03 17:33:01 +02001133void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1134 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1135}
1136
Alexey Frunze4dda3372015-06-01 18:31:49 -07001137void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1138 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1139}
1140
1141void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1142 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001143}
1144
1145void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1146 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1147}
1148
1149void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1150 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1151}
1152
1153void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1154 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1155}
1156
1157void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1158 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1159}
1160
1161void Mips64Assembler::Break() {
1162 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1163 static_cast<GpuRegister>(0), 0, 0xD);
1164}
1165
1166void Mips64Assembler::Nop() {
1167 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1168 static_cast<GpuRegister>(0), 0, 0x0);
1169}
1170
Alexey Frunze4dda3372015-06-01 18:31:49 -07001171void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1172 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001173}
1174
Alexey Frunze4dda3372015-06-01 18:31:49 -07001175void Mips64Assembler::Clear(GpuRegister rd) {
1176 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001177}
1178
Alexey Frunze4dda3372015-06-01 18:31:49 -07001179void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1180 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001181}
1182
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001183// TODO: Check for MSA presence in Mips64InstructionSetFeatures for each MSA instruction.
1184
1185void Mips64Assembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1186 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e);
1187}
1188
1189void Mips64Assembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1190 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e);
1191}
1192
1193void Mips64Assembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1194 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e);
1195}
1196
1197void Mips64Assembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1198 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e);
1199}
1200
1201void Mips64Assembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1202 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe);
1203}
1204
1205void Mips64Assembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1206 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe);
1207}
1208
1209void Mips64Assembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1210 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe);
1211}
1212
1213void Mips64Assembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1214 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe);
1215}
1216
1217void Mips64Assembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1218 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe);
1219}
1220
1221void Mips64Assembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1222 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe);
1223}
1224
1225void Mips64Assembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1226 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe);
1227}
1228
1229void Mips64Assembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1230 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe);
1231}
1232
1233void Mips64Assembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1234 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12);
1235}
1236
1237void Mips64Assembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1238 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12);
1239}
1240
1241void Mips64Assembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1242 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12);
1243}
1244
1245void Mips64Assembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1246 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12);
1247}
1248
1249void Mips64Assembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1250 EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12);
1251}
1252
1253void Mips64Assembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1254 EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12);
1255}
1256
1257void Mips64Assembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1258 EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12);
1259}
1260
1261void Mips64Assembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1262 EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12);
1263}
1264
1265void Mips64Assembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1266 EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12);
1267}
1268
1269void Mips64Assembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1270 EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12);
1271}
1272
1273void Mips64Assembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1274 EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12);
1275}
1276
1277void Mips64Assembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1278 EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12);
1279}
1280
1281void Mips64Assembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1282 EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12);
1283}
1284
1285void Mips64Assembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1286 EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12);
1287}
1288
1289void Mips64Assembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1290 EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12);
1291}
1292
1293void Mips64Assembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1294 EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12);
1295}
1296
1297void Mips64Assembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1298 EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12);
1299}
1300
1301void Mips64Assembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1302 EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12);
1303}
1304
1305void Mips64Assembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1306 EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12);
1307}
1308
1309void Mips64Assembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1310 EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12);
1311}
1312
1313void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1314 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b);
1315}
1316
1317void Mips64Assembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1318 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b);
1319}
1320
1321void Mips64Assembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1322 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b);
1323}
1324
1325void Mips64Assembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1326 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b);
1327}
1328
1329void Mips64Assembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1330 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b);
1331}
1332
1333void Mips64Assembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1334 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b);
1335}
1336
1337void Mips64Assembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1338 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b);
1339}
1340
1341void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1342 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b);
1343}
1344
1345void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
1346 EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e);
1347}
1348
1349void Mips64Assembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
1350 EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e);
1351}
1352
1353void Mips64Assembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
1354 EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e);
1355}
1356
1357void Mips64Assembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
1358 EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e);
1359}
1360
1361void Mips64Assembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1362 EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd);
1363}
1364
1365void Mips64Assembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1366 EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd);
1367}
1368
1369void Mips64Assembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1370 EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd);
1371}
1372
1373void Mips64Assembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1374 EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd);
1375}
1376
1377void Mips64Assembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1378 EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd);
1379}
1380
1381void Mips64Assembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1382 EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd);
1383}
1384
1385void Mips64Assembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1386 EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd);
1387}
1388
1389void Mips64Assembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1390 EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd);
1391}
1392
1393void Mips64Assembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1394 EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd);
1395}
1396
1397void Mips64Assembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1398 EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd);
1399}
1400
1401void Mips64Assembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1402 EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd);
1403}
1404
1405void Mips64Assembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1406 EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd);
1407}
1408
1409void Mips64Assembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
1410 CHECK(IsUint<3>(shamt3)) << shamt3;
1411 EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1412}
1413
1414void Mips64Assembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
1415 CHECK(IsUint<4>(shamt4)) << shamt4;
1416 EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1417}
1418
1419void Mips64Assembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
1420 CHECK(IsUint<5>(shamt5)) << shamt5;
1421 EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1422}
1423
1424void Mips64Assembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
1425 CHECK(IsUint<6>(shamt6)) << shamt6;
1426 EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1427}
1428
1429void Mips64Assembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
1430 CHECK(IsUint<3>(shamt3)) << shamt3;
1431 EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1432}
1433
1434void Mips64Assembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
1435 CHECK(IsUint<4>(shamt4)) << shamt4;
1436 EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1437}
1438
1439void Mips64Assembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
1440 CHECK(IsUint<5>(shamt5)) << shamt5;
1441 EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1442}
1443
1444void Mips64Assembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
1445 CHECK(IsUint<6>(shamt6)) << shamt6;
1446 EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1447}
1448
1449void Mips64Assembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
1450 CHECK(IsUint<3>(shamt3)) << shamt3;
1451 EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
1452}
1453
1454void Mips64Assembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
1455 CHECK(IsUint<4>(shamt4)) << shamt4;
1456 EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
1457}
1458
1459void Mips64Assembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
1460 CHECK(IsUint<5>(shamt5)) << shamt5;
1461 EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
1462}
1463
1464void Mips64Assembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
1465 CHECK(IsUint<6>(shamt6)) << shamt6;
1466 EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
1467}
1468
1469void Mips64Assembler::MoveV(VectorRegister wd, VectorRegister ws) {
1470 EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19);
1471}
1472
1473void Mips64Assembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
1474 CHECK(IsUint<4>(n4)) << n4;
1475 EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19);
1476}
1477
1478void Mips64Assembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
1479 CHECK(IsUint<3>(n3)) << n3;
1480 EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19);
1481}
1482
1483void Mips64Assembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
1484 CHECK(IsUint<2>(n2)) << n2;
1485 EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19);
1486}
1487
1488void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
1489 CHECK(IsUint<1>(n1)) << n1;
1490 EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19);
1491}
1492
1493void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) {
1494 EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e);
1495}
1496
1497void Mips64Assembler::FillH(VectorRegister wd, GpuRegister rs) {
1498 EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e);
1499}
1500
1501void Mips64Assembler::FillW(VectorRegister wd, GpuRegister rs) {
1502 EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e);
1503}
1504
1505void Mips64Assembler::FillD(VectorRegister wd, GpuRegister rs) {
1506 EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e);
1507}
1508
1509void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) {
1510 CHECK(IsInt<10>(offset)) << offset;
1511 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0);
1512}
1513
1514void Mips64Assembler::LdH(VectorRegister wd, GpuRegister rs, int offset) {
1515 CHECK(IsInt<11>(offset)) << offset;
1516 CHECK_ALIGNED(offset, kMips64HalfwordSize);
1517 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1);
1518}
1519
1520void Mips64Assembler::LdW(VectorRegister wd, GpuRegister rs, int offset) {
1521 CHECK(IsInt<12>(offset)) << offset;
1522 CHECK_ALIGNED(offset, kMips64WordSize);
1523 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2);
1524}
1525
1526void Mips64Assembler::LdD(VectorRegister wd, GpuRegister rs, int offset) {
1527 CHECK(IsInt<13>(offset)) << offset;
1528 CHECK_ALIGNED(offset, kMips64DoublewordSize);
1529 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3);
1530}
1531
1532void Mips64Assembler::StB(VectorRegister wd, GpuRegister rs, int offset) {
1533 CHECK(IsInt<10>(offset)) << offset;
1534 EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0);
1535}
1536
1537void Mips64Assembler::StH(VectorRegister wd, GpuRegister rs, int offset) {
1538 CHECK(IsInt<11>(offset)) << offset;
1539 CHECK_ALIGNED(offset, kMips64HalfwordSize);
1540 EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1);
1541}
1542
1543void Mips64Assembler::StW(VectorRegister wd, GpuRegister rs, int offset) {
1544 CHECK(IsInt<12>(offset)) << offset;
1545 CHECK_ALIGNED(offset, kMips64WordSize);
1546 EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2);
1547}
1548
1549void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) {
1550 CHECK(IsInt<13>(offset)) << offset;
1551 CHECK_ALIGNED(offset, kMips64DoublewordSize);
1552 EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3);
1553}
1554
Alexey Frunze4dda3372015-06-01 18:31:49 -07001555void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001556 TemplateLoadConst32(this, rd, value);
1557}
1558
1559// This function is only used for testing purposes.
1560void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001561}
1562
Alexey Frunze4dda3372015-06-01 18:31:49 -07001563void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001564 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001565}
1566
Alexey Frunze0960ac52016-12-20 17:24:59 -08001567void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) {
1568 if (IsInt<16>(value)) {
1569 Addiu(rt, rs, value);
1570 } else {
1571 int16_t high = High16Bits(value);
1572 int16_t low = Low16Bits(value);
1573 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
1574 Aui(rt, rs, high);
1575 if (low != 0) {
1576 Addiu(rt, rt, low);
1577 }
1578 }
1579}
1580
Alexey Frunze4dda3372015-06-01 18:31:49 -07001581void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1582 if (IsInt<16>(value)) {
1583 Daddiu(rt, rs, value);
1584 } else {
1585 LoadConst64(rtmp, value);
1586 Daddu(rt, rs, rtmp);
1587 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001588}
1589
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001590void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1591 Mips64Assembler::Branch::Type short_type,
1592 Mips64Assembler::Branch::Type long_type) {
1593 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1594}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001595
Alexey Frunze19f6c692016-11-30 19:19:55 -08001596void Mips64Assembler::Branch::InitializeType(Type initial_type) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001597 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001598 switch (initial_type) {
1599 case kLabel:
1600 case kLiteral:
1601 case kLiteralUnsigned:
1602 case kLiteralLong:
1603 CHECK(!IsResolved());
1604 type_ = initial_type;
1605 break;
1606 case kCall:
1607 InitShortOrLong(offset_size, kCall, kLongCall);
1608 break;
1609 case kCondBranch:
1610 switch (condition_) {
1611 case kUncond:
1612 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1613 break;
1614 case kCondEQZ:
1615 case kCondNEZ:
1616 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1617 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1618 break;
1619 default:
1620 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1621 break;
1622 }
1623 break;
1624 default:
1625 LOG(FATAL) << "Unexpected branch type " << initial_type;
1626 UNREACHABLE();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001627 }
1628 old_type_ = type_;
1629}
1630
1631bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1632 switch (condition) {
1633 case kCondLT:
1634 case kCondGT:
1635 case kCondNE:
1636 case kCondLTU:
1637 return lhs == rhs;
1638 default:
1639 return false;
1640 }
1641}
1642
1643bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1644 GpuRegister lhs,
1645 GpuRegister rhs) {
1646 switch (condition) {
1647 case kUncond:
1648 return true;
1649 case kCondGE:
1650 case kCondLE:
1651 case kCondEQ:
1652 case kCondGEU:
1653 return lhs == rhs;
1654 default:
1655 return false;
1656 }
1657}
1658
Alexey Frunze19f6c692016-11-30 19:19:55 -08001659Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001660 : old_location_(location),
1661 location_(location),
1662 target_(target),
1663 lhs_reg_(ZERO),
1664 rhs_reg_(ZERO),
1665 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001666 InitializeType(is_call ? kCall : kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001667}
1668
1669Mips64Assembler::Branch::Branch(uint32_t location,
1670 uint32_t target,
1671 Mips64Assembler::BranchCondition condition,
1672 GpuRegister lhs_reg,
1673 GpuRegister rhs_reg)
1674 : old_location_(location),
1675 location_(location),
1676 target_(target),
1677 lhs_reg_(lhs_reg),
1678 rhs_reg_(rhs_reg),
1679 condition_(condition) {
1680 CHECK_NE(condition, kUncond);
1681 switch (condition) {
1682 case kCondEQ:
1683 case kCondNE:
1684 case kCondLT:
1685 case kCondGE:
1686 case kCondLE:
1687 case kCondGT:
1688 case kCondLTU:
1689 case kCondGEU:
1690 CHECK_NE(lhs_reg, ZERO);
1691 CHECK_NE(rhs_reg, ZERO);
1692 break;
1693 case kCondLTZ:
1694 case kCondGEZ:
1695 case kCondLEZ:
1696 case kCondGTZ:
1697 case kCondEQZ:
1698 case kCondNEZ:
1699 CHECK_NE(lhs_reg, ZERO);
1700 CHECK_EQ(rhs_reg, ZERO);
1701 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001702 case kCondF:
1703 case kCondT:
1704 CHECK_EQ(rhs_reg, ZERO);
1705 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001706 case kUncond:
1707 UNREACHABLE();
1708 }
1709 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1710 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1711 // Branch condition is always true, make the branch unconditional.
1712 condition_ = kUncond;
1713 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001714 InitializeType(kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001715}
1716
Alexey Frunze19f6c692016-11-30 19:19:55 -08001717Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001718 : old_location_(location),
1719 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08001720 target_(kUnresolved),
1721 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001722 rhs_reg_(ZERO),
1723 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001724 CHECK_NE(dest_reg, ZERO);
1725 InitializeType(label_or_literal_type);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001726}
1727
1728Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1729 Mips64Assembler::BranchCondition cond) {
1730 switch (cond) {
1731 case kCondLT:
1732 return kCondGE;
1733 case kCondGE:
1734 return kCondLT;
1735 case kCondLE:
1736 return kCondGT;
1737 case kCondGT:
1738 return kCondLE;
1739 case kCondLTZ:
1740 return kCondGEZ;
1741 case kCondGEZ:
1742 return kCondLTZ;
1743 case kCondLEZ:
1744 return kCondGTZ;
1745 case kCondGTZ:
1746 return kCondLEZ;
1747 case kCondEQ:
1748 return kCondNE;
1749 case kCondNE:
1750 return kCondEQ;
1751 case kCondEQZ:
1752 return kCondNEZ;
1753 case kCondNEZ:
1754 return kCondEQZ;
1755 case kCondLTU:
1756 return kCondGEU;
1757 case kCondGEU:
1758 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001759 case kCondF:
1760 return kCondT;
1761 case kCondT:
1762 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001763 case kUncond:
1764 LOG(FATAL) << "Unexpected branch condition " << cond;
1765 }
1766 UNREACHABLE();
1767}
1768
1769Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1770 return type_;
1771}
1772
1773Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1774 return condition_;
1775}
1776
1777GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1778 return lhs_reg_;
1779}
1780
1781GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1782 return rhs_reg_;
1783}
1784
1785uint32_t Mips64Assembler::Branch::GetTarget() const {
1786 return target_;
1787}
1788
1789uint32_t Mips64Assembler::Branch::GetLocation() const {
1790 return location_;
1791}
1792
1793uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1794 return old_location_;
1795}
1796
1797uint32_t Mips64Assembler::Branch::GetLength() const {
1798 return branch_info_[type_].length;
1799}
1800
1801uint32_t Mips64Assembler::Branch::GetOldLength() const {
1802 return branch_info_[old_type_].length;
1803}
1804
1805uint32_t Mips64Assembler::Branch::GetSize() const {
1806 return GetLength() * sizeof(uint32_t);
1807}
1808
1809uint32_t Mips64Assembler::Branch::GetOldSize() const {
1810 return GetOldLength() * sizeof(uint32_t);
1811}
1812
1813uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1814 return GetLocation() + GetSize();
1815}
1816
1817uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1818 return GetOldLocation() + GetOldSize();
1819}
1820
1821bool Mips64Assembler::Branch::IsLong() const {
1822 switch (type_) {
1823 // Short branches.
1824 case kUncondBranch:
1825 case kCondBranch:
1826 case kCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001827 // Near label.
1828 case kLabel:
1829 // Near literals.
1830 case kLiteral:
1831 case kLiteralUnsigned:
1832 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001833 return false;
1834 // Long branches.
1835 case kLongUncondBranch:
1836 case kLongCondBranch:
1837 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001838 // Far label.
1839 case kFarLabel:
1840 // Far literals.
1841 case kFarLiteral:
1842 case kFarLiteralUnsigned:
1843 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001844 return true;
1845 }
1846 UNREACHABLE();
1847}
1848
1849bool Mips64Assembler::Branch::IsResolved() const {
1850 return target_ != kUnresolved;
1851}
1852
1853Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1854 OffsetBits offset_size =
1855 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1856 ? kOffset23
1857 : branch_info_[type_].offset_size;
1858 return offset_size;
1859}
1860
1861Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1862 uint32_t target) {
1863 // For unresolved targets assume the shortest encoding
1864 // (later it will be made longer if needed).
1865 if (target == kUnresolved)
1866 return kOffset16;
1867 int64_t distance = static_cast<int64_t>(target) - location;
1868 // To simplify calculations in composite branches consisting of multiple instructions
1869 // bump up the distance by a value larger than the max byte size of a composite branch.
1870 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1871 if (IsInt<kOffset16>(distance))
1872 return kOffset16;
1873 else if (IsInt<kOffset18>(distance))
1874 return kOffset18;
1875 else if (IsInt<kOffset21>(distance))
1876 return kOffset21;
1877 else if (IsInt<kOffset23>(distance))
1878 return kOffset23;
1879 else if (IsInt<kOffset28>(distance))
1880 return kOffset28;
1881 return kOffset32;
1882}
1883
1884void Mips64Assembler::Branch::Resolve(uint32_t target) {
1885 target_ = target;
1886}
1887
1888void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1889 if (location_ > expand_location) {
1890 location_ += delta;
1891 }
1892 if (!IsResolved()) {
1893 return; // Don't know the target yet.
1894 }
1895 if (target_ > expand_location) {
1896 target_ += delta;
1897 }
1898}
1899
1900void Mips64Assembler::Branch::PromoteToLong() {
1901 switch (type_) {
1902 // Short branches.
1903 case kUncondBranch:
1904 type_ = kLongUncondBranch;
1905 break;
1906 case kCondBranch:
1907 type_ = kLongCondBranch;
1908 break;
1909 case kCall:
1910 type_ = kLongCall;
1911 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001912 // Near label.
1913 case kLabel:
1914 type_ = kFarLabel;
1915 break;
1916 // Near literals.
1917 case kLiteral:
1918 type_ = kFarLiteral;
1919 break;
1920 case kLiteralUnsigned:
1921 type_ = kFarLiteralUnsigned;
1922 break;
1923 case kLiteralLong:
1924 type_ = kFarLiteralLong;
1925 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001926 default:
1927 // Note: 'type_' is already long.
1928 break;
1929 }
1930 CHECK(IsLong());
1931}
1932
1933uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1934 // If the branch is still unresolved or already long, nothing to do.
1935 if (IsLong() || !IsResolved()) {
1936 return 0;
1937 }
1938 // Promote the short branch to long if the offset size is too small
1939 // to hold the distance between location_ and target_.
1940 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1941 PromoteToLong();
1942 uint32_t old_size = GetOldSize();
1943 uint32_t new_size = GetSize();
1944 CHECK_GT(new_size, old_size);
1945 return new_size - old_size;
1946 }
1947 // The following logic is for debugging/testing purposes.
1948 // Promote some short branches to long when it's not really required.
1949 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1950 int64_t distance = static_cast<int64_t>(target_) - location_;
1951 distance = (distance >= 0) ? distance : -distance;
1952 if (distance >= max_short_distance) {
1953 PromoteToLong();
1954 uint32_t old_size = GetOldSize();
1955 uint32_t new_size = GetSize();
1956 CHECK_GT(new_size, old_size);
1957 return new_size - old_size;
1958 }
1959 }
1960 return 0;
1961}
1962
1963uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1964 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1965}
1966
1967uint32_t Mips64Assembler::Branch::GetOffset() const {
1968 CHECK(IsResolved());
1969 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1970 // Calculate the byte distance between instructions and also account for
1971 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001972 uint32_t offset_location = GetOffsetLocation();
1973 if (type_ == kLiteralLong) {
1974 // Special case for the ldpc instruction, whose address (PC) is rounded down to
1975 // a multiple of 8 before adding the offset.
1976 // Note, branch promotion has already taken care of aligning `target_` to an
1977 // address that's a multiple of 8.
1978 offset_location = RoundDown(offset_location, sizeof(uint64_t));
1979 }
1980 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001981 // Prepare the offset for encoding into the instruction(s).
1982 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1983 return offset;
1984}
1985
1986Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1987 CHECK_LT(branch_id, branches_.size());
1988 return &branches_[branch_id];
1989}
1990
1991const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1992 CHECK_LT(branch_id, branches_.size());
1993 return &branches_[branch_id];
1994}
1995
1996void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001997 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001998 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001999
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002000 // Walk the list of branches referring to and preceding this label.
2001 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07002002 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002003 uint32_t branch_id = label->Position();
2004 Branch* branch = GetBranch(branch_id);
2005 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002006
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002007 uint32_t branch_location = branch->GetLocation();
2008 // Extract the location of the previous branch in the list (walking the list backwards;
2009 // the previous branch ID was stored in the space reserved for this branch).
2010 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002011
2012 // On to the previous branch in the list...
2013 label->position_ = prev;
2014 }
2015
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002016 // Now make the label object contain its own location (relative to the end of the preceding
2017 // branch, if any; it will be used by the branches referring to and following this label).
2018 label->prev_branch_id_plus_one_ = branches_.size();
2019 if (label->prev_branch_id_plus_one_) {
2020 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2021 const Branch* branch = GetBranch(branch_id);
2022 bound_pc -= branch->GetEndLocation();
2023 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002024 label->BindTo(bound_pc);
2025}
2026
Alexey Frunze19f6c692016-11-30 19:19:55 -08002027uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002028 CHECK(label->IsBound());
2029 uint32_t target = label->Position();
2030 if (label->prev_branch_id_plus_one_) {
2031 // Get label location based on the branch preceding it.
2032 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2033 const Branch* branch = GetBranch(branch_id);
2034 target += branch->GetEndLocation();
2035 }
2036 return target;
2037}
2038
2039uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
2040 // We can reconstruct the adjustment by going through all the branches from the beginning
2041 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
2042 // with increasing old_position, we can use the data from last AdjustedPosition() to
2043 // continue where we left off and the whole loop should be O(m+n) where m is the number
2044 // of positions to adjust and n is the number of branches.
2045 if (old_position < last_old_position_) {
2046 last_position_adjustment_ = 0;
2047 last_old_position_ = 0;
2048 last_branch_id_ = 0;
2049 }
2050 while (last_branch_id_ != branches_.size()) {
2051 const Branch* branch = GetBranch(last_branch_id_);
2052 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
2053 break;
2054 }
2055 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
2056 ++last_branch_id_;
2057 }
2058 last_old_position_ = old_position;
2059 return old_position + last_position_adjustment_;
2060}
2061
2062void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
2063 uint32_t length = branches_.back().GetLength();
2064 if (!label->IsBound()) {
2065 // Branch forward (to a following label), distance is unknown.
2066 // The first branch forward will contain 0, serving as the terminator of
2067 // the list of forward-reaching branches.
2068 Emit(label->position_);
2069 length--;
2070 // Now make the label object point to this branch
2071 // (this forms a linked list of branches preceding this label).
2072 uint32_t branch_id = branches_.size() - 1;
2073 label->LinkTo(branch_id);
2074 }
2075 // Reserve space for the branch.
2076 while (length--) {
2077 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002078 }
2079}
2080
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002081void Mips64Assembler::Buncond(Mips64Label* label) {
2082 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002083 branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002084 FinalizeLabeledBranch(label);
2085}
2086
2087void Mips64Assembler::Bcond(Mips64Label* label,
2088 BranchCondition condition,
2089 GpuRegister lhs,
2090 GpuRegister rhs) {
2091 // If lhs = rhs, this can be a NOP.
2092 if (Branch::IsNop(condition, lhs, rhs)) {
2093 return;
2094 }
2095 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
2096 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
2097 FinalizeLabeledBranch(label);
2098}
2099
Alexey Frunze19f6c692016-11-30 19:19:55 -08002100void Mips64Assembler::Call(Mips64Label* label) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002101 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08002102 branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002103 FinalizeLabeledBranch(label);
2104}
2105
Alexey Frunze19f6c692016-11-30 19:19:55 -08002106void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
2107 // Label address loads are treated as pseudo branches since they require very similar handling.
2108 DCHECK(!label->IsBound());
2109 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
2110 FinalizeLabeledBranch(label);
2111}
2112
2113Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
2114 // We don't support byte and half-word literals.
2115 if (size == 4u) {
2116 literals_.emplace_back(size, data);
2117 return &literals_.back();
2118 } else {
2119 DCHECK_EQ(size, 8u);
2120 long_literals_.emplace_back(size, data);
2121 return &long_literals_.back();
2122 }
2123}
2124
2125void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
2126 LoadOperandType load_type,
2127 Literal* literal) {
2128 // Literal loads are treated as pseudo branches since they require very similar handling.
2129 Branch::Type literal_type;
2130 switch (load_type) {
2131 case kLoadWord:
2132 DCHECK_EQ(literal->GetSize(), 4u);
2133 literal_type = Branch::kLiteral;
2134 break;
2135 case kLoadUnsignedWord:
2136 DCHECK_EQ(literal->GetSize(), 4u);
2137 literal_type = Branch::kLiteralUnsigned;
2138 break;
2139 case kLoadDoubleword:
2140 DCHECK_EQ(literal->GetSize(), 8u);
2141 literal_type = Branch::kLiteralLong;
2142 break;
2143 default:
2144 LOG(FATAL) << "Unexpected literal load type " << load_type;
2145 UNREACHABLE();
2146 }
2147 Mips64Label* label = literal->GetLabel();
2148 DCHECK(!label->IsBound());
2149 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
2150 FinalizeLabeledBranch(label);
2151}
2152
Alexey Frunze0960ac52016-12-20 17:24:59 -08002153JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) {
2154 jump_tables_.emplace_back(std::move(labels));
2155 JumpTable* table = &jump_tables_.back();
2156 DCHECK(!table->GetLabel()->IsBound());
2157 return table;
2158}
2159
2160void Mips64Assembler::ReserveJumpTableSpace() {
2161 if (!jump_tables_.empty()) {
2162 for (JumpTable& table : jump_tables_) {
2163 Mips64Label* label = table.GetLabel();
2164 Bind(label);
2165
2166 // Bulk ensure capacity, as this may be large.
2167 size_t orig_size = buffer_.Size();
2168 size_t required_capacity = orig_size + table.GetSize();
2169 if (required_capacity > buffer_.Capacity()) {
2170 buffer_.ExtendCapacity(required_capacity);
2171 }
2172#ifndef NDEBUG
2173 buffer_.has_ensured_capacity_ = true;
2174#endif
2175
2176 // Fill the space with dummy data as the data is not final
2177 // until the branches have been promoted. And we shouldn't
2178 // be moving uninitialized data during branch promotion.
2179 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
2180 buffer_.Emit<uint32_t>(0x1abe1234u);
2181 }
2182
2183#ifndef NDEBUG
2184 buffer_.has_ensured_capacity_ = false;
2185#endif
2186 }
2187 }
2188}
2189
2190void Mips64Assembler::EmitJumpTables() {
2191 if (!jump_tables_.empty()) {
2192 CHECK(!overwriting_);
2193 // Switch from appending instructions at the end of the buffer to overwriting
2194 // existing instructions (here, jump tables) in the buffer.
2195 overwriting_ = true;
2196
2197 for (JumpTable& table : jump_tables_) {
2198 Mips64Label* table_label = table.GetLabel();
2199 uint32_t start = GetLabelLocation(table_label);
2200 overwrite_location_ = start;
2201
2202 for (Mips64Label* target : table.GetData()) {
2203 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
2204 // The table will contain target addresses relative to the table start.
2205 uint32_t offset = GetLabelLocation(target) - start;
2206 Emit(offset);
2207 }
2208 }
2209
2210 overwriting_ = false;
2211 }
2212}
2213
Alexey Frunze19f6c692016-11-30 19:19:55 -08002214void Mips64Assembler::EmitLiterals() {
2215 if (!literals_.empty()) {
2216 for (Literal& literal : literals_) {
2217 Mips64Label* label = literal.GetLabel();
2218 Bind(label);
2219 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2220 DCHECK_EQ(literal.GetSize(), 4u);
2221 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
2222 buffer_.Emit<uint8_t>(literal.GetData()[i]);
2223 }
2224 }
2225 }
2226 if (!long_literals_.empty()) {
2227 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
2228 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
2229 Emit(0); // NOP.
2230 for (Literal& literal : long_literals_) {
2231 Mips64Label* label = literal.GetLabel();
2232 Bind(label);
2233 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2234 DCHECK_EQ(literal.GetSize(), 8u);
2235 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
2236 buffer_.Emit<uint8_t>(literal.GetData()[i]);
2237 }
2238 }
2239 }
2240}
2241
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002242void Mips64Assembler::PromoteBranches() {
2243 // Promote short branches to long as necessary.
2244 bool changed;
2245 do {
2246 changed = false;
2247 for (auto& branch : branches_) {
2248 CHECK(branch.IsResolved());
2249 uint32_t delta = branch.PromoteIfNeeded();
2250 // If this branch has been promoted and needs to expand in size,
2251 // relocate all branches by the expansion size.
2252 if (delta) {
2253 changed = true;
2254 uint32_t expand_location = branch.GetLocation();
2255 for (auto& branch2 : branches_) {
2256 branch2.Relocate(expand_location, delta);
2257 }
2258 }
2259 }
2260 } while (changed);
2261
2262 // Account for branch expansion by resizing the code buffer
2263 // and moving the code in it to its final location.
2264 size_t branch_count = branches_.size();
2265 if (branch_count > 0) {
2266 // Resize.
2267 Branch& last_branch = branches_[branch_count - 1];
2268 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
2269 uint32_t old_size = buffer_.Size();
2270 buffer_.Resize(old_size + size_delta);
2271 // Move the code residing between branch placeholders.
2272 uint32_t end = old_size;
2273 for (size_t i = branch_count; i > 0; ) {
2274 Branch& branch = branches_[--i];
2275 uint32_t size = end - branch.GetOldEndLocation();
2276 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
2277 end = branch.GetOldLocation();
2278 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002279 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08002280
2281 // Align 64-bit literals by moving them down by 4 bytes if needed.
2282 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
2283 if (!long_literals_.empty()) {
2284 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
2285 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
2286 size_t buf_size = buffer_.Size();
2287 // 64-bit literals must be at the very end of the buffer.
2288 CHECK_EQ(first_literal_location + lit_size, buf_size);
2289 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
2290 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
2291 // The 4 reserved bytes proved useless, reduce the buffer size.
2292 buffer_.Resize(buf_size - sizeof(uint32_t));
2293 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
2294 // offsets from PC to be generated.
2295 for (auto& branch : branches_) {
2296 uint32_t target = branch.GetTarget();
2297 if (target >= first_literal_location) {
2298 branch.Resolve(target - sizeof(uint32_t));
2299 }
2300 }
2301 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
2302 // we need to adjust the location of the literal's label as well.
2303 for (Literal& literal : long_literals_) {
2304 // Bound label's position is negative, hence incrementing it instead of decrementing.
2305 literal.GetLabel()->position_ += sizeof(uint32_t);
2306 }
2307 }
2308 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002309}
2310
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002311// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2312const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
2313 // Short branches.
2314 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
2315 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
2316 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08002317 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
2318 // Near label.
2319 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
2320 // Near literals.
2321 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
2322 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
2323 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002324 // Long branches.
2325 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
2326 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08002327 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
2328 // Far label.
2329 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
2330 // Far literals.
2331 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
2332 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
2333 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002334};
2335
2336// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2337void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
2338 CHECK(overwriting_);
2339 overwrite_location_ = branch->GetLocation();
2340 uint32_t offset = branch->GetOffset();
2341 BranchCondition condition = branch->GetCondition();
2342 GpuRegister lhs = branch->GetLeftRegister();
2343 GpuRegister rhs = branch->GetRightRegister();
2344 switch (branch->GetType()) {
2345 // Short branches.
2346 case Branch::kUncondBranch:
2347 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2348 Bc(offset);
2349 break;
2350 case Branch::kCondBranch:
2351 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2352 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08002353 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002354 break;
2355 case Branch::kCall:
2356 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08002357 Balc(offset);
2358 break;
2359
2360 // Near label.
2361 case Branch::kLabel:
2362 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002363 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08002364 break;
2365 // Near literals.
2366 case Branch::kLiteral:
2367 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2368 Lwpc(lhs, offset);
2369 break;
2370 case Branch::kLiteralUnsigned:
2371 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2372 Lwupc(lhs, offset);
2373 break;
2374 case Branch::kLiteralLong:
2375 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2376 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002377 break;
2378
2379 // Long branches.
2380 case Branch::kLongUncondBranch:
2381 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2382 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2383 Auipc(AT, High16Bits(offset));
2384 Jic(AT, Low16Bits(offset));
2385 break;
2386 case Branch::kLongCondBranch:
2387 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
2388 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
2389 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2390 Auipc(AT, High16Bits(offset));
2391 Jic(AT, Low16Bits(offset));
2392 break;
2393 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08002394 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002395 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08002396 Auipc(AT, High16Bits(offset));
2397 Jialc(AT, Low16Bits(offset));
2398 break;
2399
2400 // Far label.
2401 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08002402 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08002403 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2404 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08002405 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08002406 break;
2407 // Far literals.
2408 case Branch::kFarLiteral:
2409 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
2410 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2411 Auipc(AT, High16Bits(offset));
2412 Lw(lhs, AT, Low16Bits(offset));
2413 break;
2414 case Branch::kFarLiteralUnsigned:
2415 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
2416 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2417 Auipc(AT, High16Bits(offset));
2418 Lwu(lhs, AT, Low16Bits(offset));
2419 break;
2420 case Branch::kFarLiteralLong:
2421 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
2422 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2423 Auipc(AT, High16Bits(offset));
2424 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002425 break;
2426 }
2427 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2428 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07002429}
2430
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002431void Mips64Assembler::Bc(Mips64Label* label) {
2432 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002433}
2434
Alexey Frunze19f6c692016-11-30 19:19:55 -08002435void Mips64Assembler::Balc(Mips64Label* label) {
2436 Call(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002437}
2438
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002439void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2440 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002441}
2442
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002443void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
2444 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002445}
2446
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002447void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
2448 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002449}
2450
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002451void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2452 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002453}
2454
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002455void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
2456 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002457}
2458
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002459void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
2460 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002461}
2462
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002463void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2464 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002465}
2466
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002467void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2468 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002469}
2470
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002471void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2472 Bcond(label, kCondEQ, rs, rt);
2473}
2474
2475void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2476 Bcond(label, kCondNE, rs, rt);
2477}
2478
2479void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
2480 Bcond(label, kCondEQZ, rs);
2481}
2482
2483void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
2484 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08002485}
2486
Alexey Frunze299a9392015-12-08 16:08:02 -08002487void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
2488 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
2489}
2490
2491void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
2492 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
2493}
2494
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002495void Mips64Assembler::LoadFromOffset(LoadOperandType type,
2496 GpuRegister reg,
2497 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002498 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002499 LoadFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002500}
2501
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002502void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type,
2503 FpuRegister reg,
2504 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002505 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002506 LoadFpuFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002507}
2508
2509void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
2510 size_t size) {
2511 Mips64ManagedRegister dst = m_dst.AsMips64();
2512 if (dst.IsNoRegister()) {
2513 CHECK_EQ(0u, size) << dst;
2514 } else if (dst.IsGpuRegister()) {
2515 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002516 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
2517 } else if (size == 8) {
2518 CHECK_EQ(8u, size) << dst;
2519 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
2520 } else {
2521 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2522 }
2523 } else if (dst.IsFpuRegister()) {
2524 if (size == 4) {
2525 CHECK_EQ(4u, size) << dst;
2526 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
2527 } else if (size == 8) {
2528 CHECK_EQ(8u, size) << dst;
2529 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
2530 } else {
2531 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2532 }
2533 }
2534}
2535
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002536void Mips64Assembler::StoreToOffset(StoreOperandType type,
2537 GpuRegister reg,
2538 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002539 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002540 StoreToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002541}
2542
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002543void Mips64Assembler::StoreFpuToOffset(StoreOperandType type,
2544 FpuRegister reg,
2545 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002546 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002547 StoreFpuToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002548}
2549
David Srbeckydd973932015-04-07 20:29:48 +01002550static dwarf::Reg DWARFReg(GpuRegister reg) {
2551 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
2552}
2553
Andreas Gampe57b34292015-01-14 15:45:59 -08002554constexpr size_t kFramePointerSize = 8;
2555
Vladimir Marko32248382016-05-19 10:37:24 +01002556void Mips64Assembler::BuildFrame(size_t frame_size,
2557 ManagedRegister method_reg,
2558 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002559 const ManagedRegisterEntrySpills& entry_spills) {
2560 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002561 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002562
2563 // Increase frame to required size.
2564 IncreaseFrameSize(frame_size);
2565
2566 // Push callee saves and return address
2567 int stack_offset = frame_size - kFramePointerSize;
2568 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002569 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002570 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2571 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002572 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002573 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002574 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002575 }
2576
2577 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002578 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002579
2580 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002581 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002582 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002583 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002584 ManagedRegisterSpill spill = entry_spills.at(i);
2585 int32_t size = spill.getSize();
2586 if (reg.IsNoRegister()) {
2587 // only increment stack offset.
2588 offset += size;
2589 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002590 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2591 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002592 offset += size;
2593 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002594 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2595 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002596 offset += size;
2597 }
2598 }
2599}
2600
2601void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002602 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002603 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002604 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002605 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002606
2607 // Pop callee saves and return address
2608 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2609 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002610 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002611 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002612 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002613 stack_offset += kFramePointerSize;
2614 }
2615 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002616 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002617
2618 // Decrease frame to required size.
2619 DecreaseFrameSize(frame_size);
2620
2621 // Then jump to the return address.
2622 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002623 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002624
2625 // The CFI should be restored for any code that follows the exit block.
2626 cfi_.RestoreState();
2627 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002628}
2629
2630void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002631 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002632 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002633 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002634 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002635}
2636
2637void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002638 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002639 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002640 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002641 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002642}
2643
2644void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2645 Mips64ManagedRegister src = msrc.AsMips64();
2646 if (src.IsNoRegister()) {
2647 CHECK_EQ(0u, size);
2648 } else if (src.IsGpuRegister()) {
2649 CHECK(size == 4 || size == 8) << size;
2650 if (size == 8) {
2651 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2652 } else if (size == 4) {
2653 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2654 } else {
2655 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2656 }
2657 } else if (src.IsFpuRegister()) {
2658 CHECK(size == 4 || size == 8) << size;
2659 if (size == 8) {
2660 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2661 } else if (size == 4) {
2662 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2663 } else {
2664 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2665 }
2666 }
2667}
2668
2669void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2670 Mips64ManagedRegister src = msrc.AsMips64();
2671 CHECK(src.IsGpuRegister());
2672 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2673}
2674
2675void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2676 Mips64ManagedRegister src = msrc.AsMips64();
2677 CHECK(src.IsGpuRegister());
2678 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2679}
2680
2681void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2682 ManagedRegister mscratch) {
2683 Mips64ManagedRegister scratch = mscratch.AsMips64();
2684 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002685 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002686 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2687}
2688
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002689void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2690 FrameOffset fr_offs,
2691 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002692 Mips64ManagedRegister scratch = mscratch.AsMips64();
2693 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002694 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002695 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2696}
2697
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002698void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002699 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2700}
2701
2702void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2703 FrameOffset in_off, ManagedRegister mscratch) {
2704 Mips64ManagedRegister src = msrc.AsMips64();
2705 Mips64ManagedRegister scratch = mscratch.AsMips64();
2706 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2707 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2708 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2709}
2710
2711void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2712 return EmitLoad(mdest, SP, src.Int32Value(), size);
2713}
2714
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002715void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002716 return EmitLoad(mdest, S1, src.Int32Value(), size);
2717}
2718
2719void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2720 Mips64ManagedRegister dest = mdest.AsMips64();
2721 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002722 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002723}
2724
Mathieu Chartiere401d142015-04-22 13:56:20 -07002725void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002726 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002727 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002728 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2729 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002730 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08002731 if (unpoison_reference) {
2732 MaybeUnpoisonHeapReference(dest.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002733 }
2734}
2735
2736void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002737 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002738 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002739 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002740 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2741 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2742}
2743
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002744void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002745 Mips64ManagedRegister dest = mdest.AsMips64();
2746 CHECK(dest.IsGpuRegister());
2747 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2748}
2749
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002750void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2751 size_t size ATTRIBUTE_UNUSED) {
2752 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002753}
2754
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002755void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2756 size_t size ATTRIBUTE_UNUSED) {
2757 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002758}
2759
2760void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2761 Mips64ManagedRegister dest = mdest.AsMips64();
2762 Mips64ManagedRegister src = msrc.AsMips64();
2763 if (!dest.Equals(src)) {
2764 if (dest.IsGpuRegister()) {
2765 CHECK(src.IsGpuRegister()) << src;
2766 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2767 } else if (dest.IsFpuRegister()) {
2768 CHECK(src.IsFpuRegister()) << src;
2769 if (size == 4) {
2770 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2771 } else if (size == 8) {
2772 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2773 } else {
2774 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2775 }
2776 }
2777 }
2778}
2779
2780void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2781 ManagedRegister mscratch) {
2782 Mips64ManagedRegister scratch = mscratch.AsMips64();
2783 CHECK(scratch.IsGpuRegister()) << scratch;
2784 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2785 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2786}
2787
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002788void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2789 ThreadOffset64 thr_offs,
2790 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002791 Mips64ManagedRegister scratch = mscratch.AsMips64();
2792 CHECK(scratch.IsGpuRegister()) << scratch;
2793 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2794 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2795}
2796
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002797void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2798 FrameOffset fr_offs,
2799 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002800 Mips64ManagedRegister scratch = mscratch.AsMips64();
2801 CHECK(scratch.IsGpuRegister()) << scratch;
2802 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2803 SP, fr_offs.Int32Value());
2804 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2805 S1, thr_offs.Int32Value());
2806}
2807
2808void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2809 ManagedRegister mscratch, size_t size) {
2810 Mips64ManagedRegister scratch = mscratch.AsMips64();
2811 CHECK(scratch.IsGpuRegister()) << scratch;
2812 CHECK(size == 4 || size == 8) << size;
2813 if (size == 4) {
2814 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002815 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002816 } else if (size == 8) {
2817 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2818 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2819 } else {
2820 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2821 }
2822}
2823
2824void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002825 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002826 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2827 CHECK(size == 4 || size == 8) << size;
2828 if (size == 4) {
2829 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2830 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002831 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002832 } else if (size == 8) {
2833 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2834 src_offset.Int32Value());
2835 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2836 } else {
2837 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2838 }
2839}
2840
2841void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002842 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002843 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2844 CHECK(size == 4 || size == 8) << size;
2845 if (size == 4) {
2846 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002847 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002848 dest_offset.Int32Value());
2849 } else if (size == 8) {
2850 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2851 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2852 dest_offset.Int32Value());
2853 } else {
2854 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2855 }
2856}
2857
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002858void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2859 FrameOffset src_base ATTRIBUTE_UNUSED,
2860 Offset src_offset ATTRIBUTE_UNUSED,
2861 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2862 size_t size ATTRIBUTE_UNUSED) {
2863 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002864}
2865
2866void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002867 ManagedRegister src, Offset src_offset,
2868 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002869 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2870 CHECK(size == 4 || size == 8) << size;
2871 if (size == 4) {
2872 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002873 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002874 } else if (size == 8) {
2875 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2876 src_offset.Int32Value());
2877 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2878 dest_offset.Int32Value());
2879 } else {
2880 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2881 }
2882}
2883
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002884void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2885 Offset dest_offset ATTRIBUTE_UNUSED,
2886 FrameOffset src ATTRIBUTE_UNUSED,
2887 Offset src_offset ATTRIBUTE_UNUSED,
2888 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2889 size_t size ATTRIBUTE_UNUSED) {
2890 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002891}
2892
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002893void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002894 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002895 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002896}
2897
2898void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002899 FrameOffset handle_scope_offset,
2900 ManagedRegister min_reg,
2901 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002902 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2903 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2904 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2905 CHECK(out_reg.IsGpuRegister()) << out_reg;
2906 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002907 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002908 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2909 // the address in the handle scope holding the reference.
2910 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2911 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002912 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002913 SP, handle_scope_offset.Int32Value());
2914 in_reg = out_reg;
2915 }
2916 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002917 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002918 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002919 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2920 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2921 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002922 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002923 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002924 }
2925}
2926
2927void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002928 FrameOffset handle_scope_offset,
2929 ManagedRegister mscratch,
2930 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002931 Mips64ManagedRegister scratch = mscratch.AsMips64();
2932 CHECK(scratch.IsGpuRegister()) << scratch;
2933 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002934 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002935 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002936 handle_scope_offset.Int32Value());
2937 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2938 // the address in the handle scope holding the reference.
2939 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002940 Beqzc(scratch.AsGpuRegister(), &null_arg);
2941 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2942 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002943 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002944 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002945 }
2946 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2947}
2948
2949// Given a handle scope entry, load the associated reference.
2950void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002951 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002952 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2953 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2954 CHECK(out_reg.IsGpuRegister()) << out_reg;
2955 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002956 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002957 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002958 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002959 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002960 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002961 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2962 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002963 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002964}
2965
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002966void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2967 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002968 // TODO: not validating references
2969}
2970
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002971void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2972 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002973 // TODO: not validating references
2974}
2975
2976void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2977 Mips64ManagedRegister base = mbase.AsMips64();
2978 Mips64ManagedRegister scratch = mscratch.AsMips64();
2979 CHECK(base.IsGpuRegister()) << base;
2980 CHECK(scratch.IsGpuRegister()) << scratch;
2981 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2982 base.AsGpuRegister(), offset.Int32Value());
2983 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002984 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002985 // TODO: place reference map on call
2986}
2987
2988void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2989 Mips64ManagedRegister scratch = mscratch.AsMips64();
2990 CHECK(scratch.IsGpuRegister()) << scratch;
2991 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002992 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002993 SP, base.Int32Value());
2994 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2995 scratch.AsGpuRegister(), offset.Int32Value());
2996 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002997 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002998 // TODO: place reference map on call
2999}
3000
Andreas Gampe3b165bc2016-08-01 22:07:04 -07003001void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
3002 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003003 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08003004}
3005
3006void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
3007 Move(tr.AsMips64().AsGpuRegister(), S1);
3008}
3009
3010void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003011 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08003012 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
3013}
3014
3015void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
3016 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003017 exception_blocks_.emplace_back(scratch, stack_adjust);
3018 LoadFromOffset(kLoadDoubleword,
3019 scratch.AsGpuRegister(),
3020 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07003021 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003022 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08003023}
3024
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003025void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
3026 Bind(exception->Entry());
3027 if (exception->stack_adjust_ != 0) { // Fix up the frame.
3028 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08003029 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003030 // Pass exception object as argument.
3031 // Don't care about preserving A0 as this call won't return.
3032 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
3033 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08003034 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003035 LoadFromOffset(kLoadDoubleword,
3036 T9,
3037 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07003038 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003039 Jr(T9);
3040 Nop();
3041
Andreas Gampe57b34292015-01-14 15:45:59 -08003042 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07003043 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08003044}
3045
3046} // namespace mips64
3047} // namespace art