blob: 39eb5893d87e7237c0723a90f8dbdd853a31b7ad [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
Andreas Gampe57b34292015-01-14 15:45:59 -0800187void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
188 EmitR(0, rs, rt, rd, 0, 0x21);
189}
190
191void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
192 EmitI(0x9, rs, rt, imm16);
193}
194
Alexey Frunze4dda3372015-06-01 18:31:49 -0700195void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
196 EmitR(0, rs, rt, rd, 0, 0x2d);
197}
198
Andreas Gampe57b34292015-01-14 15:45:59 -0800199void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
200 EmitI(0x19, rs, rt, imm16);
201}
202
Andreas Gampe57b34292015-01-14 15:45:59 -0800203void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
204 EmitR(0, rs, rt, rd, 0, 0x23);
205}
206
Alexey Frunze4dda3372015-06-01 18:31:49 -0700207void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
208 EmitR(0, rs, rt, rd, 0, 0x2f);
209}
210
Alexey Frunze4dda3372015-06-01 18:31:49 -0700211void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
212 EmitR(0, rs, rt, rd, 2, 0x18);
213}
214
Alexey Frunzec857c742015-09-23 15:12:39 -0700215void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
216 EmitR(0, rs, rt, rd, 3, 0x18);
217}
218
Alexey Frunze4dda3372015-06-01 18:31:49 -0700219void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
220 EmitR(0, rs, rt, rd, 2, 0x1a);
221}
222
223void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
224 EmitR(0, rs, rt, rd, 3, 0x1a);
225}
226
227void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
228 EmitR(0, rs, rt, rd, 2, 0x1b);
229}
230
231void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
232 EmitR(0, rs, rt, rd, 3, 0x1b);
233}
234
235void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
236 EmitR(0, rs, rt, rd, 2, 0x1c);
237}
238
Alexey Frunzec857c742015-09-23 15:12:39 -0700239void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
240 EmitR(0, rs, rt, rd, 3, 0x1c);
241}
242
Alexey Frunze4dda3372015-06-01 18:31:49 -0700243void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
244 EmitR(0, rs, rt, rd, 2, 0x1e);
245}
246
247void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
248 EmitR(0, rs, rt, rd, 3, 0x1e);
249}
250
251void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
252 EmitR(0, rs, rt, rd, 2, 0x1f);
253}
254
255void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
256 EmitR(0, rs, rt, rd, 3, 0x1f);
257}
258
Andreas Gampe57b34292015-01-14 15:45:59 -0800259void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
260 EmitR(0, rs, rt, rd, 0, 0x24);
261}
262
263void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
264 EmitI(0xc, rs, rt, imm16);
265}
266
267void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
268 EmitR(0, rs, rt, rd, 0, 0x25);
269}
270
271void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
272 EmitI(0xd, rs, rt, imm16);
273}
274
275void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
276 EmitR(0, rs, rt, rd, 0, 0x26);
277}
278
279void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
280 EmitI(0xe, rs, rt, imm16);
281}
282
283void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
284 EmitR(0, rs, rt, rd, 0, 0x27);
285}
286
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700287void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
288 EmitRtd(0x1f, rt, rd, 0x0, 0x20);
289}
290
291void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
292 EmitRtd(0x1f, rt, rd, 0x0, 0x24);
293}
294
Alexey Frunze4dda3372015-06-01 18:31:49 -0700295void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
296 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800297}
298
Alexey Frunze4dda3372015-06-01 18:31:49 -0700299void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
300 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
Andreas Gampe57b34292015-01-14 15:45:59 -0800301}
302
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700303void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
304 EmitRtd(0x1f, rt, rd, 0x2, 0x24);
305}
306
307void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
308 EmitRtd(0x1f, rt, rd, 0x5, 0x24);
309}
310
Lazar Trsicd9672662015-09-03 17:33:01 +0200311void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
312 CHECK(IsUint<5>(pos)) << pos;
313 CHECK(IsUint<5>(size - 1)) << size;
314 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
315}
316
317void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
318 CHECK(IsUint<5>(pos - 32)) << pos;
319 CHECK(IsUint<5>(size - 1)) << size;
320 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
321 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
Andreas Gampe57b34292015-01-14 15:45:59 -0800322}
323
Chris Larsene3660592016-11-09 11:13:42 -0800324void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
325 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
326 int sa = saPlusOne - 1;
327 EmitR(0x0, rs, rt, rd, sa, 0x05);
328}
329
330void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
331 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
332 int sa = saPlusOne - 1;
333 EmitR(0x0, rs, rt, rd, sa, 0x15);
334}
335
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700336void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
337 EmitRtd(0x1f, rt, rd, 2, 0x20);
338}
339
340void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200341 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700342 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
343}
344
345void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200346 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700347 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
348}
349
350void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200351 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700352 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
353}
354
355void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200356 CHECK(IsInt<9>(imm9));
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700357 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
358}
359
Alexey Frunze4dda3372015-06-01 18:31:49 -0700360void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
361 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
362}
363
364void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
365 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
366}
367
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700368void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
369 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
370}
371
Alexey Frunze4dda3372015-06-01 18:31:49 -0700372void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
373 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
374}
375
376void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800377 EmitR(0, rs, rt, rd, 0, 0x04);
378}
379
Chris Larsen9aebff22015-09-22 17:54:15 -0700380void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
381 EmitR(0, rs, rt, rd, 1, 0x06);
382}
383
Alexey Frunze4dda3372015-06-01 18:31:49 -0700384void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800385 EmitR(0, rs, rt, rd, 0, 0x06);
386}
387
Alexey Frunze4dda3372015-06-01 18:31:49 -0700388void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
Andreas Gampe57b34292015-01-14 15:45:59 -0800389 EmitR(0, rs, rt, rd, 0, 0x07);
390}
391
Alexey Frunze4dda3372015-06-01 18:31:49 -0700392void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) {
393 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38);
394}
395
396void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) {
397 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
398}
399
Chris Larsen9aebff22015-09-22 17:54:15 -0700400void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
401 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
402}
403
Alexey Frunze4dda3372015-06-01 18:31:49 -0700404void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
405 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
406}
407
408void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) {
409 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c);
410}
411
412void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) {
413 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
414}
415
Chris Larsen9aebff22015-09-22 17:54:15 -0700416void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
417 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
418}
419
Alexey Frunze4dda3372015-06-01 18:31:49 -0700420void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
421 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
422}
423
424void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
425 EmitR(0, rs, rt, rd, 0, 0x14);
426}
427
428void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
429 EmitR(0, rs, rt, rd, 0, 0x16);
430}
431
Chris Larsen9aebff22015-09-22 17:54:15 -0700432void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
433 EmitR(0, rs, rt, rd, 1, 0x16);
434}
435
Alexey Frunze4dda3372015-06-01 18:31:49 -0700436void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
437 EmitR(0, rs, rt, rd, 0, 0x17);
438}
439
Andreas Gampe57b34292015-01-14 15:45:59 -0800440void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
441 EmitI(0x20, rs, rt, imm16);
442}
443
444void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
445 EmitI(0x21, rs, rt, imm16);
446}
447
448void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
449 EmitI(0x23, rs, rt, imm16);
450}
451
452void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
453 EmitI(0x37, rs, rt, imm16);
454}
455
456void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
457 EmitI(0x24, rs, rt, imm16);
458}
459
460void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
461 EmitI(0x25, rs, rt, imm16);
462}
463
Douglas Leungd90957f2015-04-30 19:22:49 -0700464void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
465 EmitI(0x27, rs, rt, imm16);
466}
467
Alexey Frunze19f6c692016-11-30 19:19:55 -0800468void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) {
469 CHECK(IsUint<19>(imm19)) << imm19;
470 EmitI21(0x3B, rs, (0x01 << 19) | imm19);
471}
472
473void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) {
474 CHECK(IsUint<19>(imm19)) << imm19;
475 EmitI21(0x3B, rs, (0x02 << 19) | imm19);
476}
477
478void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) {
479 CHECK(IsUint<18>(imm18)) << imm18;
480 EmitI21(0x3B, rs, (0x06 << 18) | imm18);
481}
482
Andreas Gampe57b34292015-01-14 15:45:59 -0800483void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
484 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
485}
486
Alexey Frunze0960ac52016-12-20 17:24:59 -0800487void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
488 EmitI(0xf, rs, rt, imm16);
489}
490
Alexey Frunzec061de12017-02-14 13:27:23 -0800491void Mips64Assembler::Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
492 CHECK_NE(rs, ZERO);
493 EmitI(0x1d, rs, rt, imm16);
494}
495
Alexey Frunze4dda3372015-06-01 18:31:49 -0700496void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) {
497 EmitI(1, rs, static_cast<GpuRegister>(6), imm16);
498}
499
500void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) {
501 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16);
502}
503
504void Mips64Assembler::Sync(uint32_t stype) {
505 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
506 static_cast<GpuRegister>(0), stype & 0x1f, 0xf);
507}
508
Andreas Gampe57b34292015-01-14 15:45:59 -0800509void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
510 EmitI(0x28, rs, rt, imm16);
511}
512
513void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
514 EmitI(0x29, rs, rt, imm16);
515}
516
517void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
518 EmitI(0x2b, rs, rt, imm16);
519}
520
521void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
522 EmitI(0x3f, rs, rt, imm16);
523}
524
525void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
526 EmitR(0, rs, rt, rd, 0, 0x2a);
527}
528
529void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
530 EmitR(0, rs, rt, rd, 0, 0x2b);
531}
532
533void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
534 EmitI(0xa, rs, rt, imm16);
535}
536
537void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
538 EmitI(0xb, rs, rt, imm16);
539}
540
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700541void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
542 EmitR(0, rs, rt, rd, 0, 0x35);
543}
544
545void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
546 EmitR(0, rs, rt, rd, 0, 0x37);
547}
548
549void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
550 EmitRsd(0, rs, rd, 0x01, 0x10);
551}
552
553void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
554 EmitRsd(0, rs, rd, 0x01, 0x11);
555}
556
557void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
558 EmitRsd(0, rs, rd, 0x01, 0x12);
559}
560
561void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
562 EmitRsd(0, rs, rd, 0x01, 0x13);
563}
564
Alexey Frunze4dda3372015-06-01 18:31:49 -0700565void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
566 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Andreas Gampe57b34292015-01-14 15:45:59 -0800567}
568
569void Mips64Assembler::Jalr(GpuRegister rs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700570 Jalr(RA, rs);
571}
572
573void Mips64Assembler::Jr(GpuRegister rs) {
574 Jalr(ZERO, rs);
575}
576
577void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) {
578 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16);
579}
580
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700581void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) {
582 CHECK(IsUint<19>(imm19)) << imm19;
583 EmitI21(0x3B, rs, imm19);
584}
585
586void Mips64Assembler::Bc(uint32_t imm26) {
587 EmitI26(0x32, imm26);
588}
589
Alexey Frunze19f6c692016-11-30 19:19:55 -0800590void Mips64Assembler::Balc(uint32_t imm26) {
591 EmitI26(0x3A, imm26);
592}
593
Alexey Frunze4dda3372015-06-01 18:31:49 -0700594void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) {
595 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16);
596}
597
598void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) {
599 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16);
600}
601
602void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
603 CHECK_NE(rs, ZERO);
604 CHECK_NE(rt, ZERO);
605 CHECK_NE(rs, rt);
606 EmitI(0x17, rs, rt, imm16);
607}
608
609void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) {
610 CHECK_NE(rt, ZERO);
611 EmitI(0x17, rt, rt, imm16);
612}
613
614void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) {
615 CHECK_NE(rt, ZERO);
616 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16);
617}
618
619void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
620 CHECK_NE(rs, ZERO);
621 CHECK_NE(rt, ZERO);
622 CHECK_NE(rs, rt);
623 EmitI(0x16, rs, rt, imm16);
624}
625
626void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) {
627 CHECK_NE(rt, ZERO);
628 EmitI(0x16, rt, rt, imm16);
629}
630
631void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) {
632 CHECK_NE(rt, ZERO);
633 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16);
634}
635
636void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
637 CHECK_NE(rs, ZERO);
638 CHECK_NE(rt, ZERO);
639 CHECK_NE(rs, rt);
640 EmitI(0x7, rs, rt, imm16);
641}
642
643void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
644 CHECK_NE(rs, ZERO);
645 CHECK_NE(rt, ZERO);
646 CHECK_NE(rs, rt);
647 EmitI(0x6, rs, rt, imm16);
648}
649
650void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
651 CHECK_NE(rs, ZERO);
652 CHECK_NE(rt, ZERO);
653 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700654 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700655}
656
657void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
658 CHECK_NE(rs, ZERO);
659 CHECK_NE(rt, ZERO);
660 CHECK_NE(rs, rt);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700661 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700662}
663
664void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) {
665 CHECK_NE(rs, ZERO);
666 EmitI21(0x36, rs, imm21);
667}
668
669void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) {
670 CHECK_NE(rs, ZERO);
671 EmitI21(0x3E, rs, imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800672}
673
Alexey Frunze299a9392015-12-08 16:08:02 -0800674void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) {
675 EmitFI(0x11, 0x9, ft, imm16);
676}
677
678void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
679 EmitFI(0x11, 0xD, ft, imm16);
680}
681
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700682void Mips64Assembler::EmitBcondc(BranchCondition cond,
683 GpuRegister rs,
684 GpuRegister rt,
685 uint32_t imm16_21) {
686 switch (cond) {
687 case kCondLT:
688 Bltc(rs, rt, imm16_21);
689 break;
690 case kCondGE:
691 Bgec(rs, rt, imm16_21);
692 break;
693 case kCondLE:
694 Bgec(rt, rs, imm16_21);
695 break;
696 case kCondGT:
697 Bltc(rt, rs, imm16_21);
698 break;
699 case kCondLTZ:
700 CHECK_EQ(rt, ZERO);
701 Bltzc(rs, imm16_21);
702 break;
703 case kCondGEZ:
704 CHECK_EQ(rt, ZERO);
705 Bgezc(rs, imm16_21);
706 break;
707 case kCondLEZ:
708 CHECK_EQ(rt, ZERO);
709 Blezc(rs, imm16_21);
710 break;
711 case kCondGTZ:
712 CHECK_EQ(rt, ZERO);
713 Bgtzc(rs, imm16_21);
714 break;
715 case kCondEQ:
716 Beqc(rs, rt, imm16_21);
717 break;
718 case kCondNE:
719 Bnec(rs, rt, imm16_21);
720 break;
721 case kCondEQZ:
722 CHECK_EQ(rt, ZERO);
723 Beqzc(rs, imm16_21);
724 break;
725 case kCondNEZ:
726 CHECK_EQ(rt, ZERO);
727 Bnezc(rs, imm16_21);
728 break;
729 case kCondLTU:
730 Bltuc(rs, rt, imm16_21);
731 break;
732 case kCondGEU:
733 Bgeuc(rs, rt, imm16_21);
734 break;
Alexey Frunze299a9392015-12-08 16:08:02 -0800735 case kCondF:
736 CHECK_EQ(rt, ZERO);
737 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21);
738 break;
739 case kCondT:
740 CHECK_EQ(rt, ZERO);
741 Bc1nez(static_cast<FpuRegister>(rs), imm16_21);
742 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700743 case kUncond:
744 LOG(FATAL) << "Unexpected branch condition " << cond;
745 UNREACHABLE();
746 }
747}
748
Andreas Gampe57b34292015-01-14 15:45:59 -0800749void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
750 EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
751}
752
753void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
754 EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
755}
756
757void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
758 EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
759}
760
761void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
762 EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
763}
764
765void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700766 EmitFR(0x11, 0x11, ft, fs, fd, 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -0800767}
768
769void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700770 EmitFR(0x11, 0x11, ft, fs, fd, 0x1);
Andreas Gampe57b34292015-01-14 15:45:59 -0800771}
772
773void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700774 EmitFR(0x11, 0x11, ft, fs, fd, 0x2);
Andreas Gampe57b34292015-01-14 15:45:59 -0800775}
776
777void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700778 EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
Andreas Gampe57b34292015-01-14 15:45:59 -0800779}
780
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700781void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
782 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
783}
784
785void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
786 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
787}
788
789void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
790 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
791}
792
793void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
794 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
795}
796
Andreas Gampe57b34292015-01-14 15:45:59 -0800797void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
798 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
799}
800
801void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700802 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6);
803}
804
805void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) {
806 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7);
807}
808
809void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
810 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
811}
812
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700813void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
814 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
815}
816
817void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
818 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
819}
820
821void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
822 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
823}
824
825void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
826 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
827}
828
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800829void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) {
830 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9);
831}
832
833void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) {
834 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9);
835}
836
837void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) {
838 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd);
839}
840
841void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) {
842 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd);
843}
844
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700845void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
846 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
847}
848
849void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
850 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
851}
852
853void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
854 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
855}
856
857void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
858 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
859}
860
861void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
862 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
863}
864
865void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
866 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
867}
868
869void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
870 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
871}
872
873void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
874 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
875}
876
877void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
878 EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
879}
880
881void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
882 EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
883}
884
885void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
886 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
887}
888
889void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
890 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
891}
892
893void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
894 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
895}
896
897void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
898 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
899}
900
901void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
902 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
903}
904
905void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
906 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
907}
908
909void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
910 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
911}
912
913void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
914 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
915}
916
Alexey Frunze299a9392015-12-08 16:08:02 -0800917void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
918 EmitFR(0x11, 0x14, ft, fs, fd, 0x01);
919}
920
921void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
922 EmitFR(0x11, 0x14, ft, fs, fd, 0x02);
923}
924
925void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
926 EmitFR(0x11, 0x14, ft, fs, fd, 0x03);
927}
928
929void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
930 EmitFR(0x11, 0x14, ft, fs, fd, 0x04);
931}
932
933void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
934 EmitFR(0x11, 0x14, ft, fs, fd, 0x05);
935}
936
937void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
938 EmitFR(0x11, 0x14, ft, fs, fd, 0x06);
939}
940
941void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
942 EmitFR(0x11, 0x14, ft, fs, fd, 0x07);
943}
944
945void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
946 EmitFR(0x11, 0x14, ft, fs, fd, 0x11);
947}
948
949void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
950 EmitFR(0x11, 0x14, ft, fs, fd, 0x12);
951}
952
953void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
954 EmitFR(0x11, 0x14, ft, fs, fd, 0x13);
955}
956
957void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
958 EmitFR(0x11, 0x15, ft, fs, fd, 0x01);
959}
960
961void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
962 EmitFR(0x11, 0x15, ft, fs, fd, 0x02);
963}
964
965void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
966 EmitFR(0x11, 0x15, ft, fs, fd, 0x03);
967}
968
969void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
970 EmitFR(0x11, 0x15, ft, fs, fd, 0x04);
971}
972
973void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
974 EmitFR(0x11, 0x15, ft, fs, fd, 0x05);
975}
976
977void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
978 EmitFR(0x11, 0x15, ft, fs, fd, 0x06);
979}
980
981void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
982 EmitFR(0x11, 0x15, ft, fs, fd, 0x07);
983}
984
985void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
986 EmitFR(0x11, 0x15, ft, fs, fd, 0x11);
987}
988
989void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
990 EmitFR(0x11, 0x15, ft, fs, fd, 0x12);
991}
992
993void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
994 EmitFR(0x11, 0x15, ft, fs, fd, 0x13);
995}
996
Alexey Frunze4dda3372015-06-01 18:31:49 -0700997void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
998 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
999}
1000
1001void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) {
1002 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21);
1003}
1004
1005void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) {
1006 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20);
1007}
1008
1009void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
1010 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
Andreas Gampe57b34292015-01-14 15:45:59 -08001011}
1012
Chris Larsen51417632015-10-02 13:24:25 -07001013void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) {
1014 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20);
1015}
1016
Chris Larsen2fadd7b2015-08-14 14:56:10 -07001017void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
1018 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
1019}
1020
Andreas Gampe57b34292015-01-14 15:45:59 -08001021void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
1022 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1023}
1024
Lazar Trsicd9672662015-09-03 17:33:01 +02001025void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
1026 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1027}
1028
Alexey Frunze4dda3372015-06-01 18:31:49 -07001029void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
1030 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1031}
1032
Lazar Trsicd9672662015-09-03 17:33:01 +02001033void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
1034 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1035}
1036
Alexey Frunze4dda3372015-06-01 18:31:49 -07001037void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
1038 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
1039}
1040
1041void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) {
1042 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
Andreas Gampe57b34292015-01-14 15:45:59 -08001043}
1044
1045void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1046 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
1047}
1048
1049void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1050 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
1051}
1052
1053void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1054 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
1055}
1056
1057void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
1058 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
1059}
1060
1061void Mips64Assembler::Break() {
1062 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1063 static_cast<GpuRegister>(0), 0, 0xD);
1064}
1065
1066void Mips64Assembler::Nop() {
1067 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
1068 static_cast<GpuRegister>(0), 0, 0x0);
1069}
1070
Alexey Frunze4dda3372015-06-01 18:31:49 -07001071void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) {
1072 Or(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001073}
1074
Alexey Frunze4dda3372015-06-01 18:31:49 -07001075void Mips64Assembler::Clear(GpuRegister rd) {
1076 Move(rd, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001077}
1078
Alexey Frunze4dda3372015-06-01 18:31:49 -07001079void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) {
1080 Nor(rd, rs, ZERO);
Andreas Gampe57b34292015-01-14 15:45:59 -08001081}
1082
Alexey Frunze4dda3372015-06-01 18:31:49 -07001083void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001084 TemplateLoadConst32(this, rd, value);
1085}
1086
1087// This function is only used for testing purposes.
1088void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08001089}
1090
Alexey Frunze4dda3372015-06-01 18:31:49 -07001091void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
Chris Larsenc733dca2016-05-13 16:11:47 -07001092 TemplateLoadConst64(this, rd, value);
Andreas Gampe57b34292015-01-14 15:45:59 -08001093}
1094
Alexey Frunze0960ac52016-12-20 17:24:59 -08001095void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) {
1096 if (IsInt<16>(value)) {
1097 Addiu(rt, rs, value);
1098 } else {
1099 int16_t high = High16Bits(value);
1100 int16_t low = Low16Bits(value);
1101 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
1102 Aui(rt, rs, high);
1103 if (low != 0) {
1104 Addiu(rt, rt, low);
1105 }
1106 }
1107}
1108
Alexey Frunze4dda3372015-06-01 18:31:49 -07001109void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
1110 if (IsInt<16>(value)) {
1111 Daddiu(rt, rs, value);
1112 } else {
1113 LoadConst64(rtmp, value);
1114 Daddu(rt, rs, rtmp);
1115 }
Andreas Gampe57b34292015-01-14 15:45:59 -08001116}
1117
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001118void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size,
1119 Mips64Assembler::Branch::Type short_type,
1120 Mips64Assembler::Branch::Type long_type) {
1121 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1122}
Alexey Frunze4dda3372015-06-01 18:31:49 -07001123
Alexey Frunze19f6c692016-11-30 19:19:55 -08001124void Mips64Assembler::Branch::InitializeType(Type initial_type) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001125 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001126 switch (initial_type) {
1127 case kLabel:
1128 case kLiteral:
1129 case kLiteralUnsigned:
1130 case kLiteralLong:
1131 CHECK(!IsResolved());
1132 type_ = initial_type;
1133 break;
1134 case kCall:
1135 InitShortOrLong(offset_size, kCall, kLongCall);
1136 break;
1137 case kCondBranch:
1138 switch (condition_) {
1139 case kUncond:
1140 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1141 break;
1142 case kCondEQZ:
1143 case kCondNEZ:
1144 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1145 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
1146 break;
1147 default:
1148 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1149 break;
1150 }
1151 break;
1152 default:
1153 LOG(FATAL) << "Unexpected branch type " << initial_type;
1154 UNREACHABLE();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001155 }
1156 old_type_ = type_;
1157}
1158
1159bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) {
1160 switch (condition) {
1161 case kCondLT:
1162 case kCondGT:
1163 case kCondNE:
1164 case kCondLTU:
1165 return lhs == rhs;
1166 default:
1167 return false;
1168 }
1169}
1170
1171bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
1172 GpuRegister lhs,
1173 GpuRegister rhs) {
1174 switch (condition) {
1175 case kUncond:
1176 return true;
1177 case kCondGE:
1178 case kCondLE:
1179 case kCondEQ:
1180 case kCondGEU:
1181 return lhs == rhs;
1182 default:
1183 return false;
1184 }
1185}
1186
Alexey Frunze19f6c692016-11-30 19:19:55 -08001187Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001188 : old_location_(location),
1189 location_(location),
1190 target_(target),
1191 lhs_reg_(ZERO),
1192 rhs_reg_(ZERO),
1193 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001194 InitializeType(is_call ? kCall : kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001195}
1196
1197Mips64Assembler::Branch::Branch(uint32_t location,
1198 uint32_t target,
1199 Mips64Assembler::BranchCondition condition,
1200 GpuRegister lhs_reg,
1201 GpuRegister rhs_reg)
1202 : old_location_(location),
1203 location_(location),
1204 target_(target),
1205 lhs_reg_(lhs_reg),
1206 rhs_reg_(rhs_reg),
1207 condition_(condition) {
1208 CHECK_NE(condition, kUncond);
1209 switch (condition) {
1210 case kCondEQ:
1211 case kCondNE:
1212 case kCondLT:
1213 case kCondGE:
1214 case kCondLE:
1215 case kCondGT:
1216 case kCondLTU:
1217 case kCondGEU:
1218 CHECK_NE(lhs_reg, ZERO);
1219 CHECK_NE(rhs_reg, ZERO);
1220 break;
1221 case kCondLTZ:
1222 case kCondGEZ:
1223 case kCondLEZ:
1224 case kCondGTZ:
1225 case kCondEQZ:
1226 case kCondNEZ:
1227 CHECK_NE(lhs_reg, ZERO);
1228 CHECK_EQ(rhs_reg, ZERO);
1229 break;
Alexey Frunze299a9392015-12-08 16:08:02 -08001230 case kCondF:
1231 case kCondT:
1232 CHECK_EQ(rhs_reg, ZERO);
1233 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001234 case kUncond:
1235 UNREACHABLE();
1236 }
1237 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1238 if (IsUncond(condition, lhs_reg, rhs_reg)) {
1239 // Branch condition is always true, make the branch unconditional.
1240 condition_ = kUncond;
1241 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001242 InitializeType(kCondBranch);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001243}
1244
Alexey Frunze19f6c692016-11-30 19:19:55 -08001245Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001246 : old_location_(location),
1247 location_(location),
Alexey Frunze19f6c692016-11-30 19:19:55 -08001248 target_(kUnresolved),
1249 lhs_reg_(dest_reg),
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001250 rhs_reg_(ZERO),
1251 condition_(kUncond) {
Alexey Frunze19f6c692016-11-30 19:19:55 -08001252 CHECK_NE(dest_reg, ZERO);
1253 InitializeType(label_or_literal_type);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001254}
1255
1256Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
1257 Mips64Assembler::BranchCondition cond) {
1258 switch (cond) {
1259 case kCondLT:
1260 return kCondGE;
1261 case kCondGE:
1262 return kCondLT;
1263 case kCondLE:
1264 return kCondGT;
1265 case kCondGT:
1266 return kCondLE;
1267 case kCondLTZ:
1268 return kCondGEZ;
1269 case kCondGEZ:
1270 return kCondLTZ;
1271 case kCondLEZ:
1272 return kCondGTZ;
1273 case kCondGTZ:
1274 return kCondLEZ;
1275 case kCondEQ:
1276 return kCondNE;
1277 case kCondNE:
1278 return kCondEQ;
1279 case kCondEQZ:
1280 return kCondNEZ;
1281 case kCondNEZ:
1282 return kCondEQZ;
1283 case kCondLTU:
1284 return kCondGEU;
1285 case kCondGEU:
1286 return kCondLTU;
Alexey Frunze299a9392015-12-08 16:08:02 -08001287 case kCondF:
1288 return kCondT;
1289 case kCondT:
1290 return kCondF;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001291 case kUncond:
1292 LOG(FATAL) << "Unexpected branch condition " << cond;
1293 }
1294 UNREACHABLE();
1295}
1296
1297Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const {
1298 return type_;
1299}
1300
1301Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const {
1302 return condition_;
1303}
1304
1305GpuRegister Mips64Assembler::Branch::GetLeftRegister() const {
1306 return lhs_reg_;
1307}
1308
1309GpuRegister Mips64Assembler::Branch::GetRightRegister() const {
1310 return rhs_reg_;
1311}
1312
1313uint32_t Mips64Assembler::Branch::GetTarget() const {
1314 return target_;
1315}
1316
1317uint32_t Mips64Assembler::Branch::GetLocation() const {
1318 return location_;
1319}
1320
1321uint32_t Mips64Assembler::Branch::GetOldLocation() const {
1322 return old_location_;
1323}
1324
1325uint32_t Mips64Assembler::Branch::GetLength() const {
1326 return branch_info_[type_].length;
1327}
1328
1329uint32_t Mips64Assembler::Branch::GetOldLength() const {
1330 return branch_info_[old_type_].length;
1331}
1332
1333uint32_t Mips64Assembler::Branch::GetSize() const {
1334 return GetLength() * sizeof(uint32_t);
1335}
1336
1337uint32_t Mips64Assembler::Branch::GetOldSize() const {
1338 return GetOldLength() * sizeof(uint32_t);
1339}
1340
1341uint32_t Mips64Assembler::Branch::GetEndLocation() const {
1342 return GetLocation() + GetSize();
1343}
1344
1345uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
1346 return GetOldLocation() + GetOldSize();
1347}
1348
1349bool Mips64Assembler::Branch::IsLong() const {
1350 switch (type_) {
1351 // Short branches.
1352 case kUncondBranch:
1353 case kCondBranch:
1354 case kCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001355 // Near label.
1356 case kLabel:
1357 // Near literals.
1358 case kLiteral:
1359 case kLiteralUnsigned:
1360 case kLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001361 return false;
1362 // Long branches.
1363 case kLongUncondBranch:
1364 case kLongCondBranch:
1365 case kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001366 // Far label.
1367 case kFarLabel:
1368 // Far literals.
1369 case kFarLiteral:
1370 case kFarLiteralUnsigned:
1371 case kFarLiteralLong:
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001372 return true;
1373 }
1374 UNREACHABLE();
1375}
1376
1377bool Mips64Assembler::Branch::IsResolved() const {
1378 return target_ != kUnresolved;
1379}
1380
1381Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
1382 OffsetBits offset_size =
1383 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
1384 ? kOffset23
1385 : branch_info_[type_].offset_size;
1386 return offset_size;
1387}
1388
1389Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location,
1390 uint32_t target) {
1391 // For unresolved targets assume the shortest encoding
1392 // (later it will be made longer if needed).
1393 if (target == kUnresolved)
1394 return kOffset16;
1395 int64_t distance = static_cast<int64_t>(target) - location;
1396 // To simplify calculations in composite branches consisting of multiple instructions
1397 // bump up the distance by a value larger than the max byte size of a composite branch.
1398 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
1399 if (IsInt<kOffset16>(distance))
1400 return kOffset16;
1401 else if (IsInt<kOffset18>(distance))
1402 return kOffset18;
1403 else if (IsInt<kOffset21>(distance))
1404 return kOffset21;
1405 else if (IsInt<kOffset23>(distance))
1406 return kOffset23;
1407 else if (IsInt<kOffset28>(distance))
1408 return kOffset28;
1409 return kOffset32;
1410}
1411
1412void Mips64Assembler::Branch::Resolve(uint32_t target) {
1413 target_ = target;
1414}
1415
1416void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
1417 if (location_ > expand_location) {
1418 location_ += delta;
1419 }
1420 if (!IsResolved()) {
1421 return; // Don't know the target yet.
1422 }
1423 if (target_ > expand_location) {
1424 target_ += delta;
1425 }
1426}
1427
1428void Mips64Assembler::Branch::PromoteToLong() {
1429 switch (type_) {
1430 // Short branches.
1431 case kUncondBranch:
1432 type_ = kLongUncondBranch;
1433 break;
1434 case kCondBranch:
1435 type_ = kLongCondBranch;
1436 break;
1437 case kCall:
1438 type_ = kLongCall;
1439 break;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001440 // Near label.
1441 case kLabel:
1442 type_ = kFarLabel;
1443 break;
1444 // Near literals.
1445 case kLiteral:
1446 type_ = kFarLiteral;
1447 break;
1448 case kLiteralUnsigned:
1449 type_ = kFarLiteralUnsigned;
1450 break;
1451 case kLiteralLong:
1452 type_ = kFarLiteralLong;
1453 break;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001454 default:
1455 // Note: 'type_' is already long.
1456 break;
1457 }
1458 CHECK(IsLong());
1459}
1460
1461uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
1462 // If the branch is still unresolved or already long, nothing to do.
1463 if (IsLong() || !IsResolved()) {
1464 return 0;
1465 }
1466 // Promote the short branch to long if the offset size is too small
1467 // to hold the distance between location_ and target_.
1468 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) {
1469 PromoteToLong();
1470 uint32_t old_size = GetOldSize();
1471 uint32_t new_size = GetSize();
1472 CHECK_GT(new_size, old_size);
1473 return new_size - old_size;
1474 }
1475 // The following logic is for debugging/testing purposes.
1476 // Promote some short branches to long when it's not really required.
1477 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
1478 int64_t distance = static_cast<int64_t>(target_) - location_;
1479 distance = (distance >= 0) ? distance : -distance;
1480 if (distance >= max_short_distance) {
1481 PromoteToLong();
1482 uint32_t old_size = GetOldSize();
1483 uint32_t new_size = GetSize();
1484 CHECK_GT(new_size, old_size);
1485 return new_size - old_size;
1486 }
1487 }
1488 return 0;
1489}
1490
1491uint32_t Mips64Assembler::Branch::GetOffsetLocation() const {
1492 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t);
1493}
1494
1495uint32_t Mips64Assembler::Branch::GetOffset() const {
1496 CHECK(IsResolved());
1497 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
1498 // Calculate the byte distance between instructions and also account for
1499 // different PC-relative origins.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001500 uint32_t offset_location = GetOffsetLocation();
1501 if (type_ == kLiteralLong) {
1502 // Special case for the ldpc instruction, whose address (PC) is rounded down to
1503 // a multiple of 8 before adding the offset.
1504 // Note, branch promotion has already taken care of aligning `target_` to an
1505 // address that's a multiple of 8.
1506 offset_location = RoundDown(offset_location, sizeof(uint64_t));
1507 }
1508 uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001509 // Prepare the offset for encoding into the instruction(s).
1510 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
1511 return offset;
1512}
1513
1514Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) {
1515 CHECK_LT(branch_id, branches_.size());
1516 return &branches_[branch_id];
1517}
1518
1519const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const {
1520 CHECK_LT(branch_id, branches_.size());
1521 return &branches_[branch_id];
1522}
1523
1524void Mips64Assembler::Bind(Mips64Label* label) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07001525 CHECK(!label->IsBound());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001526 uint32_t bound_pc = buffer_.Size();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001527
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001528 // Walk the list of branches referring to and preceding this label.
1529 // Store the previously unknown target addresses in them.
Alexey Frunze4dda3372015-06-01 18:31:49 -07001530 while (label->IsLinked()) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001531 uint32_t branch_id = label->Position();
1532 Branch* branch = GetBranch(branch_id);
1533 branch->Resolve(bound_pc);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001534
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001535 uint32_t branch_location = branch->GetLocation();
1536 // Extract the location of the previous branch in the list (walking the list backwards;
1537 // the previous branch ID was stored in the space reserved for this branch).
1538 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001539
1540 // On to the previous branch in the list...
1541 label->position_ = prev;
1542 }
1543
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001544 // Now make the label object contain its own location (relative to the end of the preceding
1545 // branch, if any; it will be used by the branches referring to and following this label).
1546 label->prev_branch_id_plus_one_ = branches_.size();
1547 if (label->prev_branch_id_plus_one_) {
1548 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1549 const Branch* branch = GetBranch(branch_id);
1550 bound_pc -= branch->GetEndLocation();
1551 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001552 label->BindTo(bound_pc);
1553}
1554
Alexey Frunze19f6c692016-11-30 19:19:55 -08001555uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001556 CHECK(label->IsBound());
1557 uint32_t target = label->Position();
1558 if (label->prev_branch_id_plus_one_) {
1559 // Get label location based on the branch preceding it.
1560 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
1561 const Branch* branch = GetBranch(branch_id);
1562 target += branch->GetEndLocation();
1563 }
1564 return target;
1565}
1566
1567uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) {
1568 // We can reconstruct the adjustment by going through all the branches from the beginning
1569 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
1570 // with increasing old_position, we can use the data from last AdjustedPosition() to
1571 // continue where we left off and the whole loop should be O(m+n) where m is the number
1572 // of positions to adjust and n is the number of branches.
1573 if (old_position < last_old_position_) {
1574 last_position_adjustment_ = 0;
1575 last_old_position_ = 0;
1576 last_branch_id_ = 0;
1577 }
1578 while (last_branch_id_ != branches_.size()) {
1579 const Branch* branch = GetBranch(last_branch_id_);
1580 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
1581 break;
1582 }
1583 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
1584 ++last_branch_id_;
1585 }
1586 last_old_position_ = old_position;
1587 return old_position + last_position_adjustment_;
1588}
1589
1590void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
1591 uint32_t length = branches_.back().GetLength();
1592 if (!label->IsBound()) {
1593 // Branch forward (to a following label), distance is unknown.
1594 // The first branch forward will contain 0, serving as the terminator of
1595 // the list of forward-reaching branches.
1596 Emit(label->position_);
1597 length--;
1598 // Now make the label object point to this branch
1599 // (this forms a linked list of branches preceding this label).
1600 uint32_t branch_id = branches_.size() - 1;
1601 label->LinkTo(branch_id);
1602 }
1603 // Reserve space for the branch.
1604 while (length--) {
1605 Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -07001606 }
1607}
1608
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001609void Mips64Assembler::Buncond(Mips64Label* label) {
1610 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001611 branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001612 FinalizeLabeledBranch(label);
1613}
1614
1615void Mips64Assembler::Bcond(Mips64Label* label,
1616 BranchCondition condition,
1617 GpuRegister lhs,
1618 GpuRegister rhs) {
1619 // If lhs = rhs, this can be a NOP.
1620 if (Branch::IsNop(condition, lhs, rhs)) {
1621 return;
1622 }
1623 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
1624 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
1625 FinalizeLabeledBranch(label);
1626}
1627
Alexey Frunze19f6c692016-11-30 19:19:55 -08001628void Mips64Assembler::Call(Mips64Label* label) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001629 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze19f6c692016-11-30 19:19:55 -08001630 branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001631 FinalizeLabeledBranch(label);
1632}
1633
Alexey Frunze19f6c692016-11-30 19:19:55 -08001634void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) {
1635 // Label address loads are treated as pseudo branches since they require very similar handling.
1636 DCHECK(!label->IsBound());
1637 branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel);
1638 FinalizeLabeledBranch(label);
1639}
1640
1641Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) {
1642 // We don't support byte and half-word literals.
1643 if (size == 4u) {
1644 literals_.emplace_back(size, data);
1645 return &literals_.back();
1646 } else {
1647 DCHECK_EQ(size, 8u);
1648 long_literals_.emplace_back(size, data);
1649 return &long_literals_.back();
1650 }
1651}
1652
1653void Mips64Assembler::LoadLiteral(GpuRegister dest_reg,
1654 LoadOperandType load_type,
1655 Literal* literal) {
1656 // Literal loads are treated as pseudo branches since they require very similar handling.
1657 Branch::Type literal_type;
1658 switch (load_type) {
1659 case kLoadWord:
1660 DCHECK_EQ(literal->GetSize(), 4u);
1661 literal_type = Branch::kLiteral;
1662 break;
1663 case kLoadUnsignedWord:
1664 DCHECK_EQ(literal->GetSize(), 4u);
1665 literal_type = Branch::kLiteralUnsigned;
1666 break;
1667 case kLoadDoubleword:
1668 DCHECK_EQ(literal->GetSize(), 8u);
1669 literal_type = Branch::kLiteralLong;
1670 break;
1671 default:
1672 LOG(FATAL) << "Unexpected literal load type " << load_type;
1673 UNREACHABLE();
1674 }
1675 Mips64Label* label = literal->GetLabel();
1676 DCHECK(!label->IsBound());
1677 branches_.emplace_back(buffer_.Size(), dest_reg, literal_type);
1678 FinalizeLabeledBranch(label);
1679}
1680
Alexey Frunze0960ac52016-12-20 17:24:59 -08001681JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) {
1682 jump_tables_.emplace_back(std::move(labels));
1683 JumpTable* table = &jump_tables_.back();
1684 DCHECK(!table->GetLabel()->IsBound());
1685 return table;
1686}
1687
1688void Mips64Assembler::ReserveJumpTableSpace() {
1689 if (!jump_tables_.empty()) {
1690 for (JumpTable& table : jump_tables_) {
1691 Mips64Label* label = table.GetLabel();
1692 Bind(label);
1693
1694 // Bulk ensure capacity, as this may be large.
1695 size_t orig_size = buffer_.Size();
1696 size_t required_capacity = orig_size + table.GetSize();
1697 if (required_capacity > buffer_.Capacity()) {
1698 buffer_.ExtendCapacity(required_capacity);
1699 }
1700#ifndef NDEBUG
1701 buffer_.has_ensured_capacity_ = true;
1702#endif
1703
1704 // Fill the space with dummy data as the data is not final
1705 // until the branches have been promoted. And we shouldn't
1706 // be moving uninitialized data during branch promotion.
1707 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
1708 buffer_.Emit<uint32_t>(0x1abe1234u);
1709 }
1710
1711#ifndef NDEBUG
1712 buffer_.has_ensured_capacity_ = false;
1713#endif
1714 }
1715 }
1716}
1717
1718void Mips64Assembler::EmitJumpTables() {
1719 if (!jump_tables_.empty()) {
1720 CHECK(!overwriting_);
1721 // Switch from appending instructions at the end of the buffer to overwriting
1722 // existing instructions (here, jump tables) in the buffer.
1723 overwriting_ = true;
1724
1725 for (JumpTable& table : jump_tables_) {
1726 Mips64Label* table_label = table.GetLabel();
1727 uint32_t start = GetLabelLocation(table_label);
1728 overwrite_location_ = start;
1729
1730 for (Mips64Label* target : table.GetData()) {
1731 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
1732 // The table will contain target addresses relative to the table start.
1733 uint32_t offset = GetLabelLocation(target) - start;
1734 Emit(offset);
1735 }
1736 }
1737
1738 overwriting_ = false;
1739 }
1740}
1741
Alexey Frunze19f6c692016-11-30 19:19:55 -08001742void Mips64Assembler::EmitLiterals() {
1743 if (!literals_.empty()) {
1744 for (Literal& literal : literals_) {
1745 Mips64Label* label = literal.GetLabel();
1746 Bind(label);
1747 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1748 DCHECK_EQ(literal.GetSize(), 4u);
1749 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1750 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1751 }
1752 }
1753 }
1754 if (!long_literals_.empty()) {
1755 // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit
1756 // literals don't end up 8-byte-aligned, they will be moved down 4 bytes.
1757 Emit(0); // NOP.
1758 for (Literal& literal : long_literals_) {
1759 Mips64Label* label = literal.GetLabel();
1760 Bind(label);
1761 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1762 DCHECK_EQ(literal.GetSize(), 8u);
1763 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
1764 buffer_.Emit<uint8_t>(literal.GetData()[i]);
1765 }
1766 }
1767 }
1768}
1769
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001770void Mips64Assembler::PromoteBranches() {
1771 // Promote short branches to long as necessary.
1772 bool changed;
1773 do {
1774 changed = false;
1775 for (auto& branch : branches_) {
1776 CHECK(branch.IsResolved());
1777 uint32_t delta = branch.PromoteIfNeeded();
1778 // If this branch has been promoted and needs to expand in size,
1779 // relocate all branches by the expansion size.
1780 if (delta) {
1781 changed = true;
1782 uint32_t expand_location = branch.GetLocation();
1783 for (auto& branch2 : branches_) {
1784 branch2.Relocate(expand_location, delta);
1785 }
1786 }
1787 }
1788 } while (changed);
1789
1790 // Account for branch expansion by resizing the code buffer
1791 // and moving the code in it to its final location.
1792 size_t branch_count = branches_.size();
1793 if (branch_count > 0) {
1794 // Resize.
1795 Branch& last_branch = branches_[branch_count - 1];
1796 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
1797 uint32_t old_size = buffer_.Size();
1798 buffer_.Resize(old_size + size_delta);
1799 // Move the code residing between branch placeholders.
1800 uint32_t end = old_size;
1801 for (size_t i = branch_count; i > 0; ) {
1802 Branch& branch = branches_[--i];
1803 uint32_t size = end - branch.GetOldEndLocation();
1804 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
1805 end = branch.GetOldLocation();
1806 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001807 }
Alexey Frunze19f6c692016-11-30 19:19:55 -08001808
1809 // Align 64-bit literals by moving them down by 4 bytes if needed.
1810 // This will reduce the PC-relative distance, which should be safe for both near and far literals.
1811 if (!long_literals_.empty()) {
1812 uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel());
1813 size_t lit_size = long_literals_.size() * sizeof(uint64_t);
1814 size_t buf_size = buffer_.Size();
1815 // 64-bit literals must be at the very end of the buffer.
1816 CHECK_EQ(first_literal_location + lit_size, buf_size);
1817 if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) {
1818 buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size);
1819 // The 4 reserved bytes proved useless, reduce the buffer size.
1820 buffer_.Resize(buf_size - sizeof(uint32_t));
1821 // Reduce target addresses in literal and address loads by 4 bytes in order for correct
1822 // offsets from PC to be generated.
1823 for (auto& branch : branches_) {
1824 uint32_t target = branch.GetTarget();
1825 if (target >= first_literal_location) {
1826 branch.Resolve(target - sizeof(uint32_t));
1827 }
1828 }
1829 // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal,
1830 // we need to adjust the location of the literal's label as well.
1831 for (Literal& literal : long_literals_) {
1832 // Bound label's position is negative, hence incrementing it instead of decrementing.
1833 literal.GetLabel()->position_ += sizeof(uint32_t);
1834 }
1835 }
1836 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07001837}
1838
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001839// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1840const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
1841 // Short branches.
1842 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
1843 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
1844 // Exception: kOffset23 for beqzc/bnezc
Alexey Frunze19f6c692016-11-30 19:19:55 -08001845 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
1846 // Near label.
1847 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
1848 // Near literals.
1849 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral
1850 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned
1851 { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001852 // Long branches.
1853 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch
1854 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch
Alexey Frunze19f6c692016-11-30 19:19:55 -08001855 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall
1856 // Far label.
1857 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel
1858 // Far literals.
1859 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral
1860 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned
1861 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001862};
1863
1864// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
1865void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
1866 CHECK(overwriting_);
1867 overwrite_location_ = branch->GetLocation();
1868 uint32_t offset = branch->GetOffset();
1869 BranchCondition condition = branch->GetCondition();
1870 GpuRegister lhs = branch->GetLeftRegister();
1871 GpuRegister rhs = branch->GetRightRegister();
1872 switch (branch->GetType()) {
1873 // Short branches.
1874 case Branch::kUncondBranch:
1875 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1876 Bc(offset);
1877 break;
1878 case Branch::kCondBranch:
1879 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1880 EmitBcondc(condition, lhs, rhs, offset);
Alexey Frunze299a9392015-12-08 16:08:02 -08001881 Nop(); // TODO: improve by filling the forbidden/delay slot.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001882 break;
1883 case Branch::kCall:
1884 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001885 Balc(offset);
1886 break;
1887
1888 // Near label.
1889 case Branch::kLabel:
1890 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001891 Addiupc(lhs, offset);
Alexey Frunze19f6c692016-11-30 19:19:55 -08001892 break;
1893 // Near literals.
1894 case Branch::kLiteral:
1895 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1896 Lwpc(lhs, offset);
1897 break;
1898 case Branch::kLiteralUnsigned:
1899 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1900 Lwupc(lhs, offset);
1901 break;
1902 case Branch::kLiteralLong:
1903 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1904 Ldpc(lhs, offset);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001905 break;
1906
1907 // Long branches.
1908 case Branch::kLongUncondBranch:
1909 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1910 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1911 Auipc(AT, High16Bits(offset));
1912 Jic(AT, Low16Bits(offset));
1913 break;
1914 case Branch::kLongCondBranch:
1915 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
1916 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
1917 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1918 Auipc(AT, High16Bits(offset));
1919 Jic(AT, Low16Bits(offset));
1920 break;
1921 case Branch::kLongCall:
Alexey Frunze19f6c692016-11-30 19:19:55 -08001922 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001923 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze19f6c692016-11-30 19:19:55 -08001924 Auipc(AT, High16Bits(offset));
1925 Jialc(AT, Low16Bits(offset));
1926 break;
1927
1928 // Far label.
1929 case Branch::kFarLabel:
Alexey Frunzef63f5692016-12-13 17:43:11 -08001930 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu.
Alexey Frunze19f6c692016-11-30 19:19:55 -08001931 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1932 Auipc(AT, High16Bits(offset));
Alexey Frunzef63f5692016-12-13 17:43:11 -08001933 Daddiu(lhs, AT, Low16Bits(offset));
Alexey Frunze19f6c692016-11-30 19:19:55 -08001934 break;
1935 // Far literals.
1936 case Branch::kFarLiteral:
1937 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
1938 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1939 Auipc(AT, High16Bits(offset));
1940 Lw(lhs, AT, Low16Bits(offset));
1941 break;
1942 case Branch::kFarLiteralUnsigned:
1943 offset += (offset & 0x8000) << 1; // Account for sign extension in lwu.
1944 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1945 Auipc(AT, High16Bits(offset));
1946 Lwu(lhs, AT, Low16Bits(offset));
1947 break;
1948 case Branch::kFarLiteralLong:
1949 offset += (offset & 0x8000) << 1; // Account for sign extension in ld.
1950 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
1951 Auipc(AT, High16Bits(offset));
1952 Ld(lhs, AT, Low16Bits(offset));
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001953 break;
1954 }
1955 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
1956 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunze4dda3372015-06-01 18:31:49 -07001957}
1958
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001959void Mips64Assembler::Bc(Mips64Label* label) {
1960 Buncond(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001961}
1962
Alexey Frunze19f6c692016-11-30 19:19:55 -08001963void Mips64Assembler::Balc(Mips64Label* label) {
1964 Call(label);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001965}
1966
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001967void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1968 Bcond(label, kCondLT, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001969}
1970
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001971void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
1972 Bcond(label, kCondLTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001973}
1974
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001975void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
1976 Bcond(label, kCondGTZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001977}
1978
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001979void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1980 Bcond(label, kCondGE, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001981}
1982
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001983void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
1984 Bcond(label, kCondGEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001985}
1986
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001987void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
1988 Bcond(label, kCondLEZ, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001989}
1990
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001991void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1992 Bcond(label, kCondLTU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001993}
1994
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001995void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
1996 Bcond(label, kCondGEU, rs, rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -07001997}
1998
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001999void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2000 Bcond(label, kCondEQ, rs, rt);
2001}
2002
2003void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
2004 Bcond(label, kCondNE, rs, rt);
2005}
2006
2007void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
2008 Bcond(label, kCondEQZ, rs);
2009}
2010
2011void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
2012 Bcond(label, kCondNEZ, rs);
Andreas Gampe57b34292015-01-14 15:45:59 -08002013}
2014
Alexey Frunze299a9392015-12-08 16:08:02 -08002015void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
2016 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
2017}
2018
2019void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
2020 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
2021}
2022
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002023void Mips64Assembler::LoadFromOffset(LoadOperandType type,
2024 GpuRegister reg,
2025 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002026 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002027 LoadFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002028}
2029
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002030void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type,
2031 FpuRegister reg,
2032 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002033 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002034 LoadFpuFromOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002035}
2036
2037void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
2038 size_t size) {
2039 Mips64ManagedRegister dst = m_dst.AsMips64();
2040 if (dst.IsNoRegister()) {
2041 CHECK_EQ(0u, size) << dst;
2042 } else if (dst.IsGpuRegister()) {
2043 if (size == 4) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002044 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
2045 } else if (size == 8) {
2046 CHECK_EQ(8u, size) << dst;
2047 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
2048 } else {
2049 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2050 }
2051 } else if (dst.IsFpuRegister()) {
2052 if (size == 4) {
2053 CHECK_EQ(4u, size) << dst;
2054 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
2055 } else if (size == 8) {
2056 CHECK_EQ(8u, size) << dst;
2057 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
2058 } else {
2059 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
2060 }
2061 }
2062}
2063
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002064void Mips64Assembler::StoreToOffset(StoreOperandType type,
2065 GpuRegister reg,
2066 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002067 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002068 StoreToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002069}
2070
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002071void Mips64Assembler::StoreFpuToOffset(StoreOperandType type,
2072 FpuRegister reg,
2073 GpuRegister base,
Andreas Gampe57b34292015-01-14 15:45:59 -08002074 int32_t offset) {
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002075 StoreFpuToOffset<>(type, reg, base, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002076}
2077
David Srbeckydd973932015-04-07 20:29:48 +01002078static dwarf::Reg DWARFReg(GpuRegister reg) {
2079 return dwarf::Reg::Mips64Core(static_cast<int>(reg));
2080}
2081
Andreas Gampe57b34292015-01-14 15:45:59 -08002082constexpr size_t kFramePointerSize = 8;
2083
Vladimir Marko32248382016-05-19 10:37:24 +01002084void Mips64Assembler::BuildFrame(size_t frame_size,
2085 ManagedRegister method_reg,
2086 ArrayRef<const ManagedRegister> callee_save_regs,
Andreas Gampe57b34292015-01-14 15:45:59 -08002087 const ManagedRegisterEntrySpills& entry_spills) {
2088 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002089 DCHECK(!overwriting_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002090
2091 // Increase frame to required size.
2092 IncreaseFrameSize(frame_size);
2093
2094 // Push callee saves and return address
2095 int stack_offset = frame_size - kFramePointerSize;
2096 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002097 cfi_.RelOffset(DWARFReg(RA), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002098 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
2099 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01002100 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002101 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002102 cfi_.RelOffset(DWARFReg(reg), stack_offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002103 }
2104
2105 // Write out Method*.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002106 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002107
2108 // Write out entry spills.
Mathieu Chartiere401d142015-04-22 13:56:20 -07002109 int32_t offset = frame_size + kFramePointerSize;
Andreas Gampe57b34292015-01-14 15:45:59 -08002110 for (size_t i = 0; i < entry_spills.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002111 Mips64ManagedRegister reg = entry_spills[i].AsMips64();
Andreas Gampe57b34292015-01-14 15:45:59 -08002112 ManagedRegisterSpill spill = entry_spills.at(i);
2113 int32_t size = spill.getSize();
2114 if (reg.IsNoRegister()) {
2115 // only increment stack offset.
2116 offset += size;
2117 } else if (reg.IsFpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002118 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2119 reg.AsFpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002120 offset += size;
2121 } else if (reg.IsGpuRegister()) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002122 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword,
2123 reg.AsGpuRegister(), SP, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -08002124 offset += size;
2125 }
2126 }
2127}
2128
2129void Mips64Assembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01002130 ArrayRef<const ManagedRegister> callee_save_regs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002131 CHECK_ALIGNED(frame_size, kStackAlignment);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002132 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01002133 cfi_.RememberState();
Andreas Gampe57b34292015-01-14 15:45:59 -08002134
2135 // Pop callee saves and return address
2136 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
2137 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01002138 GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
Andreas Gampe57b34292015-01-14 15:45:59 -08002139 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002140 cfi_.Restore(DWARFReg(reg));
Andreas Gampe57b34292015-01-14 15:45:59 -08002141 stack_offset += kFramePointerSize;
2142 }
2143 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01002144 cfi_.Restore(DWARFReg(RA));
Andreas Gampe57b34292015-01-14 15:45:59 -08002145
2146 // Decrease frame to required size.
2147 DecreaseFrameSize(frame_size);
2148
2149 // Then jump to the return address.
2150 Jr(RA);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002151 Nop();
David Srbeckydd973932015-04-07 20:29:48 +01002152
2153 // The CFI should be restored for any code that follows the exit block.
2154 cfi_.RestoreState();
2155 cfi_.DefCFAOffset(frame_size);
Andreas Gampe57b34292015-01-14 15:45:59 -08002156}
2157
2158void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002159 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002160 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002161 Daddiu64(SP, SP, static_cast<int32_t>(-adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002162 cfi_.AdjustCFAOffset(adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002163}
2164
2165void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002166 CHECK_ALIGNED(adjust, kFramePointerSize);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002167 DCHECK(!overwriting_);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002168 Daddiu64(SP, SP, static_cast<int32_t>(adjust));
David Srbeckydd973932015-04-07 20:29:48 +01002169 cfi_.AdjustCFAOffset(-adjust);
Andreas Gampe57b34292015-01-14 15:45:59 -08002170}
2171
2172void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
2173 Mips64ManagedRegister src = msrc.AsMips64();
2174 if (src.IsNoRegister()) {
2175 CHECK_EQ(0u, size);
2176 } else if (src.IsGpuRegister()) {
2177 CHECK(size == 4 || size == 8) << size;
2178 if (size == 8) {
2179 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2180 } else if (size == 4) {
2181 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2182 } else {
2183 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2184 }
2185 } else if (src.IsFpuRegister()) {
2186 CHECK(size == 4 || size == 8) << size;
2187 if (size == 8) {
2188 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
2189 } else if (size == 4) {
2190 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
2191 } else {
2192 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
2193 }
2194 }
2195}
2196
2197void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
2198 Mips64ManagedRegister src = msrc.AsMips64();
2199 CHECK(src.IsGpuRegister());
2200 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
2201}
2202
2203void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
2204 Mips64ManagedRegister src = msrc.AsMips64();
2205 CHECK(src.IsGpuRegister());
2206 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2207}
2208
2209void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
2210 ManagedRegister mscratch) {
2211 Mips64ManagedRegister scratch = mscratch.AsMips64();
2212 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002213 LoadConst32(scratch.AsGpuRegister(), imm);
Andreas Gampe57b34292015-01-14 15:45:59 -08002214 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2215}
2216
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002217void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
2218 FrameOffset fr_offs,
2219 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002220 Mips64ManagedRegister scratch = mscratch.AsMips64();
2221 CHECK(scratch.IsGpuRegister()) << scratch;
Alexey Frunze4dda3372015-06-01 18:31:49 -07002222 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002223 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2224}
2225
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002226void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002227 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
2228}
2229
2230void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
2231 FrameOffset in_off, ManagedRegister mscratch) {
2232 Mips64ManagedRegister src = msrc.AsMips64();
2233 Mips64ManagedRegister scratch = mscratch.AsMips64();
2234 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
2235 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
2236 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
2237}
2238
2239void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
2240 return EmitLoad(mdest, SP, src.Int32Value(), size);
2241}
2242
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002243void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002244 return EmitLoad(mdest, S1, src.Int32Value(), size);
2245}
2246
2247void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
2248 Mips64ManagedRegister dest = mdest.AsMips64();
2249 CHECK(dest.IsGpuRegister());
Douglas Leungd90957f2015-04-30 19:22:49 -07002250 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002251}
2252
Mathieu Chartiere401d142015-04-22 13:56:20 -07002253void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01002254 bool unpoison_reference) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002255 Mips64ManagedRegister dest = mdest.AsMips64();
Douglas Leungd90957f2015-04-30 19:22:49 -07002256 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
2257 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002258 base.AsMips64().AsGpuRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08002259 if (unpoison_reference) {
2260 MaybeUnpoisonHeapReference(dest.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002261 }
2262}
2263
2264void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002265 Offset offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002266 Mips64ManagedRegister dest = mdest.AsMips64();
Alexey Frunze4dda3372015-06-01 18:31:49 -07002267 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002268 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
2269 base.AsMips64().AsGpuRegister(), offs.Int32Value());
2270}
2271
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002272void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002273 Mips64ManagedRegister dest = mdest.AsMips64();
2274 CHECK(dest.IsGpuRegister());
2275 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
2276}
2277
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002278void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2279 size_t size ATTRIBUTE_UNUSED) {
2280 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002281}
2282
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002283void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
2284 size_t size ATTRIBUTE_UNUSED) {
2285 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64";
Andreas Gampe57b34292015-01-14 15:45:59 -08002286}
2287
2288void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
2289 Mips64ManagedRegister dest = mdest.AsMips64();
2290 Mips64ManagedRegister src = msrc.AsMips64();
2291 if (!dest.Equals(src)) {
2292 if (dest.IsGpuRegister()) {
2293 CHECK(src.IsGpuRegister()) << src;
2294 Move(dest.AsGpuRegister(), src.AsGpuRegister());
2295 } else if (dest.IsFpuRegister()) {
2296 CHECK(src.IsFpuRegister()) << src;
2297 if (size == 4) {
2298 MovS(dest.AsFpuRegister(), src.AsFpuRegister());
2299 } else if (size == 8) {
2300 MovD(dest.AsFpuRegister(), src.AsFpuRegister());
2301 } else {
2302 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2303 }
2304 }
2305 }
2306}
2307
2308void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
2309 ManagedRegister mscratch) {
2310 Mips64ManagedRegister scratch = mscratch.AsMips64();
2311 CHECK(scratch.IsGpuRegister()) << scratch;
2312 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
2313 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
2314}
2315
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002316void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
2317 ThreadOffset64 thr_offs,
2318 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002319 Mips64ManagedRegister scratch = mscratch.AsMips64();
2320 CHECK(scratch.IsGpuRegister()) << scratch;
2321 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
2322 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
2323}
2324
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002325void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
2326 FrameOffset fr_offs,
2327 ManagedRegister mscratch) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002328 Mips64ManagedRegister scratch = mscratch.AsMips64();
2329 CHECK(scratch.IsGpuRegister()) << scratch;
2330 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2331 SP, fr_offs.Int32Value());
2332 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
2333 S1, thr_offs.Int32Value());
2334}
2335
2336void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
2337 ManagedRegister mscratch, size_t size) {
2338 Mips64ManagedRegister scratch = mscratch.AsMips64();
2339 CHECK(scratch.IsGpuRegister()) << scratch;
2340 CHECK(size == 4 || size == 8) << size;
2341 if (size == 4) {
2342 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002343 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002344 } else if (size == 8) {
2345 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
2346 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
2347 } else {
2348 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2349 }
2350}
2351
2352void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002353 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002354 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2355 CHECK(size == 4 || size == 8) << size;
2356 if (size == 4) {
2357 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
2358 src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002359 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002360 } else if (size == 8) {
2361 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
2362 src_offset.Int32Value());
2363 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
2364 } else {
2365 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2366 }
2367}
2368
2369void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002370 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002371 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2372 CHECK(size == 4 || size == 8) << size;
2373 if (size == 4) {
2374 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002375 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002376 dest_offset.Int32Value());
2377 } else if (size == 8) {
2378 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
2379 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
2380 dest_offset.Int32Value());
2381 } else {
2382 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2383 }
2384}
2385
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002386void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2387 FrameOffset src_base ATTRIBUTE_UNUSED,
2388 Offset src_offset ATTRIBUTE_UNUSED,
2389 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2390 size_t size ATTRIBUTE_UNUSED) {
2391 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002392}
2393
2394void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002395 ManagedRegister src, Offset src_offset,
2396 ManagedRegister mscratch, size_t size) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002397 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
2398 CHECK(size == 4 || size == 8) << size;
2399 if (size == 4) {
2400 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
Lazar Trsicf652d602015-06-24 16:30:21 +02002401 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002402 } else if (size == 8) {
2403 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
2404 src_offset.Int32Value());
2405 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
2406 dest_offset.Int32Value());
2407 } else {
2408 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
2409 }
2410}
2411
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002412void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
2413 Offset dest_offset ATTRIBUTE_UNUSED,
2414 FrameOffset src ATTRIBUTE_UNUSED,
2415 Offset src_offset ATTRIBUTE_UNUSED,
2416 ManagedRegister mscratch ATTRIBUTE_UNUSED,
2417 size_t size ATTRIBUTE_UNUSED) {
2418 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002419}
2420
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002421void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002422 // TODO: sync?
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002423 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002424}
2425
2426void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002427 FrameOffset handle_scope_offset,
2428 ManagedRegister min_reg,
2429 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002430 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2431 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2432 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
2433 CHECK(out_reg.IsGpuRegister()) << out_reg;
2434 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002435 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002436 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2437 // the address in the handle scope holding the reference.
2438 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
2439 if (in_reg.IsNoRegister()) {
Douglas Leungd90957f2015-04-30 19:22:49 -07002440 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002441 SP, handle_scope_offset.Int32Value());
2442 in_reg = out_reg;
2443 }
2444 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002445 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002446 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002447 Beqzc(in_reg.AsGpuRegister(), &null_arg);
2448 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2449 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002450 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002451 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002452 }
2453}
2454
2455void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002456 FrameOffset handle_scope_offset,
2457 ManagedRegister mscratch,
2458 bool null_allowed) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002459 Mips64ManagedRegister scratch = mscratch.AsMips64();
2460 CHECK(scratch.IsGpuRegister()) << scratch;
2461 if (null_allowed) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002462 Mips64Label null_arg;
Douglas Leungd90957f2015-04-30 19:22:49 -07002463 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP,
Andreas Gampe57b34292015-01-14 15:45:59 -08002464 handle_scope_offset.Int32Value());
2465 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
2466 // the address in the handle scope holding the reference.
2467 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Alexey Frunze4dda3372015-06-01 18:31:49 -07002468 Beqzc(scratch.AsGpuRegister(), &null_arg);
2469 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
2470 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002471 } else {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002472 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -08002473 }
2474 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
2475}
2476
2477// Given a handle scope entry, load the associated reference.
2478void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Alexey Frunze4dda3372015-06-01 18:31:49 -07002479 ManagedRegister min_reg) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002480 Mips64ManagedRegister out_reg = mout_reg.AsMips64();
2481 Mips64ManagedRegister in_reg = min_reg.AsMips64();
2482 CHECK(out_reg.IsGpuRegister()) << out_reg;
2483 CHECK(in_reg.IsGpuRegister()) << in_reg;
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002484 Mips64Label null_arg;
Andreas Gampe57b34292015-01-14 15:45:59 -08002485 if (!out_reg.Equals(in_reg)) {
Alexey Frunze4dda3372015-06-01 18:31:49 -07002486 LoadConst32(out_reg.AsGpuRegister(), 0);
Andreas Gampe57b34292015-01-14 15:45:59 -08002487 }
Alexey Frunze4dda3372015-06-01 18:31:49 -07002488 Beqzc(in_reg.AsGpuRegister(), &null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002489 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
2490 in_reg.AsGpuRegister(), 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -07002491 Bind(&null_arg);
Andreas Gampe57b34292015-01-14 15:45:59 -08002492}
2493
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002494void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
2495 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002496 // TODO: not validating references
2497}
2498
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002499void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
2500 bool could_be_null ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002501 // TODO: not validating references
2502}
2503
2504void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
2505 Mips64ManagedRegister base = mbase.AsMips64();
2506 Mips64ManagedRegister scratch = mscratch.AsMips64();
2507 CHECK(base.IsGpuRegister()) << base;
2508 CHECK(scratch.IsGpuRegister()) << scratch;
2509 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2510 base.AsGpuRegister(), offset.Int32Value());
2511 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002512 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002513 // TODO: place reference map on call
2514}
2515
2516void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
2517 Mips64ManagedRegister scratch = mscratch.AsMips64();
2518 CHECK(scratch.IsGpuRegister()) << scratch;
2519 // Call *(*(SP + base) + offset)
Mathieu Chartiere401d142015-04-22 13:56:20 -07002520 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
Andreas Gampe57b34292015-01-14 15:45:59 -08002521 SP, base.Int32Value());
2522 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
2523 scratch.AsGpuRegister(), offset.Int32Value());
2524 Jalr(scratch.AsGpuRegister());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002525 Nop();
Andreas Gampe57b34292015-01-14 15:45:59 -08002526 // TODO: place reference map on call
2527}
2528
Andreas Gampe3b165bc2016-08-01 22:07:04 -07002529void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
2530 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002531 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
Andreas Gampe57b34292015-01-14 15:45:59 -08002532}
2533
2534void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
2535 Move(tr.AsMips64().AsGpuRegister(), S1);
2536}
2537
2538void Mips64Assembler::GetCurrentThread(FrameOffset offset,
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002539 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Andreas Gampe57b34292015-01-14 15:45:59 -08002540 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
2541}
2542
2543void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
2544 Mips64ManagedRegister scratch = mscratch.AsMips64();
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002545 exception_blocks_.emplace_back(scratch, stack_adjust);
2546 LoadFromOffset(kLoadDoubleword,
2547 scratch.AsGpuRegister(),
2548 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002549 Thread::ExceptionOffset<kMips64PointerSize>().Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002550 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
Andreas Gampe57b34292015-01-14 15:45:59 -08002551}
2552
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002553void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
2554 Bind(exception->Entry());
2555 if (exception->stack_adjust_ != 0) { // Fix up the frame.
2556 DecreaseFrameSize(exception->stack_adjust_);
Andreas Gampe57b34292015-01-14 15:45:59 -08002557 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002558 // Pass exception object as argument.
2559 // Don't care about preserving A0 as this call won't return.
2560 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2561 Move(A0, exception->scratch_.AsGpuRegister());
Andreas Gampe57b34292015-01-14 15:45:59 -08002562 // Set up call to Thread::Current()->pDeliverException
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002563 LoadFromOffset(kLoadDoubleword,
2564 T9,
2565 S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07002566 QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value());
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002567 Jr(T9);
2568 Nop();
2569
Andreas Gampe57b34292015-01-14 15:45:59 -08002570 // Call never returns
Alexey Frunzea0e87b02015-09-24 22:57:20 -07002571 Break();
Andreas Gampe57b34292015-01-14 15:45:59 -08002572}
2573
2574} // namespace mips64
2575} // namespace art