blob: eb75f8b67c8826637f243692d6d617cd929ef065 [file] [log] [blame]
jeffhao7fbee072012-08-24 17:56:54 -07001/*
2 * Copyright (C) 2011 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_mips.h"
18
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080020#include "base/casts.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "entrypoints/quick/quick_entrypoints.h"
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020022#include "entrypoints/quick/quick_entrypoints_enum.h"
jeffhao7fbee072012-08-24 17:56:54 -070023#include "memory_region.h"
jeffhao7fbee072012-08-24 17:56:54 -070024#include "thread.h"
25
26namespace art {
27namespace mips {
jeffhao7fbee072012-08-24 17:56:54 -070028
Andreas Gampe542451c2016-07-26 09:02:02 -070029static_assert(static_cast<size_t>(kMipsPointerSize) == kMipsWordSize,
30 "Unexpected Mips pointer size.");
31static_assert(kMipsPointerSize == PointerSize::k32, "Unexpected Mips pointer size.");
32
33
jeffhao7fbee072012-08-24 17:56:54 -070034std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
35 if (rhs >= D0 && rhs < kNumberOfDRegisters) {
36 os << "d" << static_cast<int>(rhs);
37 } else {
38 os << "DRegister[" << static_cast<int>(rhs) << "]";
39 }
40 return os;
41}
42
Alexey Frunze57eb0f52016-07-29 22:04:46 -070043MipsAssembler::DelaySlot::DelaySlot()
44 : instruction_(0),
45 gpr_outs_mask_(0),
46 gpr_ins_mask_(0),
47 fpr_outs_mask_(0),
48 fpr_ins_mask_(0),
49 cc_outs_mask_(0),
Alexey Frunzea663d9d2017-07-31 18:43:18 -070050 cc_ins_mask_(0),
51 patcher_label_(nullptr) {}
Alexey Frunze57eb0f52016-07-29 22:04:46 -070052
53void MipsAssembler::DsFsmInstr(uint32_t instruction,
54 uint32_t gpr_outs_mask,
55 uint32_t gpr_ins_mask,
56 uint32_t fpr_outs_mask,
57 uint32_t fpr_ins_mask,
58 uint32_t cc_outs_mask,
Alexey Frunzea663d9d2017-07-31 18:43:18 -070059 uint32_t cc_ins_mask,
60 MipsLabel* patcher_label) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -070061 if (!reordering_) {
62 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
63 CHECK_EQ(delay_slot_.instruction_, 0u);
64 return;
65 }
66 switch (ds_fsm_state_) {
67 case kExpectingLabel:
68 break;
69 case kExpectingInstruction:
70 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
71 // If the last instruction is not suitable for delay slots, drop
72 // the PC of the label preceding it so that no unconditional branch
73 // uses this instruction to fill its delay slot.
74 if (instruction == 0) {
75 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
76 } else {
77 // Otherwise wait for another instruction or label before we can
78 // commit the label PC. The label PC will be dropped if instead
79 // of another instruction or label there's a call from the code
80 // generator to CodePosition() to record the buffer size.
81 // Instructions after which the buffer size is recorded cannot
82 // be moved into delay slots or anywhere else because they may
83 // trigger signals and the signal handlers expect these signals
84 // to be coming from the instructions immediately preceding the
85 // recorded buffer locations.
86 ds_fsm_state_ = kExpectingCommit;
87 }
88 break;
89 case kExpectingCommit:
90 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size());
91 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
92 break;
93 }
94 delay_slot_.instruction_ = instruction;
95 delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u; // Ignore register ZERO.
96 delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u; // Ignore register ZERO.
97 delay_slot_.fpr_outs_mask_ = fpr_outs_mask;
98 delay_slot_.fpr_ins_mask_ = fpr_ins_mask;
99 delay_slot_.cc_outs_mask_ = cc_outs_mask;
100 delay_slot_.cc_ins_mask_ = cc_ins_mask;
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700101 delay_slot_.patcher_label_ = patcher_label;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700102}
103
104void MipsAssembler::DsFsmLabel() {
105 if (!reordering_) {
106 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
107 CHECK_EQ(delay_slot_.instruction_, 0u);
108 return;
109 }
110 switch (ds_fsm_state_) {
111 case kExpectingLabel:
112 ds_fsm_target_pc_ = buffer_.Size();
113 ds_fsm_state_ = kExpectingInstruction;
114 break;
115 case kExpectingInstruction:
116 // Allow consecutive labels.
117 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size());
118 break;
119 case kExpectingCommit:
120 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
121 DsFsmCommitLabel();
122 ds_fsm_target_pc_ = buffer_.Size();
123 ds_fsm_state_ = kExpectingInstruction;
124 break;
125 }
126 // We cannot move instructions into delay slots across labels.
127 delay_slot_.instruction_ = 0;
128}
129
130void MipsAssembler::DsFsmCommitLabel() {
131 if (ds_fsm_state_ == kExpectingCommit) {
132 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_);
133 }
134 ds_fsm_state_ = kExpectingLabel;
135}
136
137void MipsAssembler::DsFsmDropLabel() {
138 ds_fsm_state_ = kExpectingLabel;
139}
140
141bool MipsAssembler::SetReorder(bool enable) {
142 bool last_state = reordering_;
143 if (last_state != enable) {
144 DsFsmCommitLabel();
145 DsFsmInstrNop(0);
146 }
147 reordering_ = enable;
148 return last_state;
149}
150
151size_t MipsAssembler::CodePosition() {
152 // The last instruction cannot be used in a delay slot, do not commit
153 // the label before it (if any) and clear the delay slot.
154 DsFsmDropLabel();
155 DsFsmInstrNop(0);
156 size_t size = buffer_.Size();
157 // In theory we can get the following sequence:
158 // label1:
159 // instr
160 // label2: # label1 gets committed when label2 is seen
161 // CodePosition() call
162 // and we need to uncommit label1.
163 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) {
164 ds_fsm_target_pcs_.pop_back();
165 }
166 return size;
167}
168
169void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
170 DsFsmInstr(0, 0, 0, 0, 0, 0, 0);
171}
172
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700173void MipsAssembler::DsFsmInstrRrr(uint32_t instruction,
174 Register out,
175 Register in1,
176 Register in2,
177 MipsLabel* patcher_label) {
178 DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0, patcher_label);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700179}
180
181void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction,
182 Register in1_out,
183 Register in2,
184 Register in3) {
185 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0);
186}
187
188void MipsAssembler::DsFsmInstrFff(uint32_t instruction,
189 FRegister out,
190 FRegister in1,
191 FRegister in2) {
192 DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0);
193}
194
195void MipsAssembler::DsFsmInstrFfff(uint32_t instruction,
196 FRegister in1_out,
197 FRegister in2,
198 FRegister in3) {
199 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0);
200}
201
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700202void MipsAssembler::DsFsmInstrFffr(uint32_t instruction,
203 FRegister in1_out,
204 FRegister in2,
205 Register in3) {
206 DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0);
207}
208
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700209void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) {
210 DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0);
211}
212
213void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) {
214 DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0);
215}
216
217void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) {
218 DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0);
219}
220
221void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) {
222 DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0);
223}
224
225void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction,
226 Register in1_out,
227 Register in2,
228 int cc_in) {
229 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in));
230}
231
232void MipsAssembler::DsFsmInstrFffc(uint32_t instruction,
233 FRegister in1_out,
234 FRegister in2,
235 int cc_in) {
236 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in));
237}
238
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200239void MipsAssembler::FinalizeCode() {
240 for (auto& exception_block : exception_blocks_) {
241 EmitExceptionPoll(&exception_block);
242 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700243 // Commit the last branch target label (if any) and disable instruction reordering.
244 DsFsmCommitLabel();
245 SetReorder(false);
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700246 EmitLiterals();
Alexey Frunze96b66822016-09-10 02:32:44 -0700247 ReserveJumpTableSpace();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200248 PromoteBranches();
249}
250
251void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
Vladimir Marko10ef6942015-10-22 15:25:54 +0100252 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200253 EmitBranches();
Alexey Frunze96b66822016-09-10 02:32:44 -0700254 EmitJumpTables();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200255 Assembler::FinalizeInstructions(region);
Vladimir Marko10ef6942015-10-22 15:25:54 +0100256 PatchCFI(number_of_delayed_adjust_pcs);
257}
258
259void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
260 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
261 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
262 return;
263 }
264
265 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
266 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
267 const std::vector<uint8_t>& old_stream = data.first;
268 const std::vector<DelayedAdvancePC>& advances = data.second;
269
270 // PCs recorded before EmitBranches() need to be adjusted.
271 // PCs recorded during EmitBranches() are already adjusted.
272 // Both ranges are separately sorted but they may overlap.
273 if (kIsDebugBuild) {
274 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
275 return lhs.pc < rhs.pc;
276 };
277 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
278 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
279 }
280
281 // Append initial CFI data if any.
282 size_t size = advances.size();
283 DCHECK_NE(size, 0u);
284 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
285 // Emit PC adjustments interleaved with the old CFI stream.
286 size_t adjust_pos = 0u;
287 size_t late_emit_pos = number_of_delayed_adjust_pcs;
288 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
289 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
290 ? GetAdjustedPosition(advances[adjust_pos].pc)
291 : static_cast<size_t>(-1);
292 size_t late_emit_pc = (late_emit_pos != size)
293 ? advances[late_emit_pos].pc
294 : static_cast<size_t>(-1);
295 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
296 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
297 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
298 if (adjusted_pc <= late_emit_pc) {
299 ++adjust_pos;
300 } else {
301 ++late_emit_pos;
302 }
303 cfi().AdvancePC(advance_pc);
304 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
305 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
306 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200307}
308
309void MipsAssembler::EmitBranches() {
310 CHECK(!overwriting_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700311 CHECK(!reordering_);
312 // Now that everything has its final position in the buffer (the branches have
313 // been promoted), adjust the target label PCs.
314 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) {
315 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]);
316 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200317 // Switch from appending instructions at the end of the buffer to overwriting
318 // existing instructions (branch placeholders) in the buffer.
319 overwriting_ = true;
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700320 for (size_t id = 0; id < branches_.size(); id++) {
321 EmitBranch(id);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200322 }
323 overwriting_ = false;
324}
325
326void MipsAssembler::Emit(uint32_t value) {
327 if (overwriting_) {
328 // Branches to labels are emitted into their placeholders here.
329 buffer_.Store<uint32_t>(overwrite_location_, value);
330 overwrite_location_ += sizeof(uint32_t);
331 } else {
332 // Other instructions are simply appended at the end here.
333 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
334 buffer_.Emit<uint32_t>(value);
335 }
jeffhao7fbee072012-08-24 17:56:54 -0700336}
337
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700338uint32_t MipsAssembler::EmitR(int opcode,
339 Register rs,
340 Register rt,
341 Register rd,
342 int shamt,
343 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700344 CHECK_NE(rs, kNoRegister);
345 CHECK_NE(rt, kNoRegister);
346 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200347 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
348 static_cast<uint32_t>(rs) << kRsShift |
349 static_cast<uint32_t>(rt) << kRtShift |
350 static_cast<uint32_t>(rd) << kRdShift |
351 shamt << kShamtShift |
352 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700353 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700354 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700355}
356
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700357uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
jeffhao7fbee072012-08-24 17:56:54 -0700358 CHECK_NE(rs, kNoRegister);
359 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200360 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
361 static_cast<uint32_t>(rs) << kRsShift |
362 static_cast<uint32_t>(rt) << kRtShift |
363 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700364 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700365 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700366}
367
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700368uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200369 CHECK_NE(rs, kNoRegister);
370 CHECK(IsUint<21>(imm21)) << imm21;
371 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
372 static_cast<uint32_t>(rs) << kRsShift |
373 imm21;
jeffhao7fbee072012-08-24 17:56:54 -0700374 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700375 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700376}
377
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700378uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200379 CHECK(IsUint<26>(imm26)) << imm26;
380 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
381 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700382 return encoding;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200383}
384
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700385uint32_t MipsAssembler::EmitFR(int opcode,
386 int fmt,
387 FRegister ft,
388 FRegister fs,
389 FRegister fd,
390 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700391 CHECK_NE(ft, kNoFRegister);
392 CHECK_NE(fs, kNoFRegister);
393 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200394 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
395 fmt << kFmtShift |
396 static_cast<uint32_t>(ft) << kFtShift |
397 static_cast<uint32_t>(fs) << kFsShift |
398 static_cast<uint32_t>(fd) << kFdShift |
399 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700400 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700401 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700402}
403
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700404uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200405 CHECK_NE(ft, kNoFRegister);
406 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
407 fmt << kFmtShift |
408 static_cast<uint32_t>(ft) << kFtShift |
409 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700410 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700411 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700412}
413
Lena Djokic0758ae72017-05-23 11:06:23 +0200414uint32_t MipsAssembler::EmitMsa3R(int operation,
415 int df,
416 VectorRegister wt,
417 VectorRegister ws,
418 VectorRegister wd,
419 int minor_opcode) {
420 CHECK_NE(wt, kNoVectorRegister);
421 CHECK_NE(ws, kNoVectorRegister);
422 CHECK_NE(wd, kNoVectorRegister);
423 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
424 operation << kMsaOperationShift |
425 df << kDfShift |
426 static_cast<uint32_t>(wt) << kWtShift |
427 static_cast<uint32_t>(ws) << kWsShift |
428 static_cast<uint32_t>(wd) << kWdShift |
429 minor_opcode;
430 Emit(encoding);
431 return encoding;
432}
433
434uint32_t MipsAssembler::EmitMsaBIT(int operation,
435 int df_m,
436 VectorRegister ws,
437 VectorRegister wd,
438 int minor_opcode) {
439 CHECK_NE(ws, kNoVectorRegister);
440 CHECK_NE(wd, kNoVectorRegister);
441 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
442 operation << kMsaOperationShift |
443 df_m << kDfMShift |
444 static_cast<uint32_t>(ws) << kWsShift |
445 static_cast<uint32_t>(wd) << kWdShift |
446 minor_opcode;
447 Emit(encoding);
448 return encoding;
449}
450
451uint32_t MipsAssembler::EmitMsaELM(int operation,
452 int df_n,
453 VectorRegister ws,
454 VectorRegister wd,
455 int minor_opcode) {
456 CHECK_NE(ws, kNoVectorRegister);
457 CHECK_NE(wd, kNoVectorRegister);
458 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
459 operation << kMsaELMOperationShift |
460 df_n << kDfNShift |
461 static_cast<uint32_t>(ws) << kWsShift |
462 static_cast<uint32_t>(wd) << kWdShift |
463 minor_opcode;
464 Emit(encoding);
465 return encoding;
466}
467
468uint32_t MipsAssembler::EmitMsaMI10(int s10,
469 Register rs,
470 VectorRegister wd,
471 int minor_opcode,
472 int df) {
473 CHECK_NE(rs, kNoRegister);
474 CHECK_NE(wd, kNoVectorRegister);
475 CHECK(IsUint<10>(s10)) << s10;
476 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
477 s10 << kS10Shift |
478 static_cast<uint32_t>(rs) << kWsShift |
479 static_cast<uint32_t>(wd) << kWdShift |
480 minor_opcode << kS10MinorShift |
481 df;
482 Emit(encoding);
483 return encoding;
484}
485
486uint32_t MipsAssembler::EmitMsaI10(int operation,
487 int df,
488 int i10,
489 VectorRegister wd,
490 int minor_opcode) {
491 CHECK_NE(wd, kNoVectorRegister);
492 CHECK(IsUint<10>(i10)) << i10;
493 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
494 operation << kMsaOperationShift |
495 df << kDfShift |
496 i10 << kI10Shift |
497 static_cast<uint32_t>(wd) << kWdShift |
498 minor_opcode;
499 Emit(encoding);
500 return encoding;
501}
502
503uint32_t MipsAssembler::EmitMsa2R(int operation,
504 int df,
505 VectorRegister ws,
506 VectorRegister wd,
507 int minor_opcode) {
508 CHECK_NE(ws, kNoVectorRegister);
509 CHECK_NE(wd, kNoVectorRegister);
510 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
511 operation << kMsa2ROperationShift |
512 df << kDf2RShift |
513 static_cast<uint32_t>(ws) << kWsShift |
514 static_cast<uint32_t>(wd) << kWdShift |
515 minor_opcode;
516 Emit(encoding);
517 return encoding;
518}
519
520uint32_t MipsAssembler::EmitMsa2RF(int operation,
521 int df,
522 VectorRegister ws,
523 VectorRegister wd,
524 int minor_opcode) {
525 CHECK_NE(ws, kNoVectorRegister);
526 CHECK_NE(wd, kNoVectorRegister);
527 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
528 operation << kMsa2RFOperationShift |
529 df << kDf2RShift |
530 static_cast<uint32_t>(ws) << kWsShift |
531 static_cast<uint32_t>(wd) << kWdShift |
532 minor_opcode;
533 Emit(encoding);
534 return encoding;
535}
536
jeffhao7fbee072012-08-24 17:56:54 -0700537void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700538 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700539}
540
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700541void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
542 if (patcher_label != nullptr) {
543 Bind(patcher_label);
544 }
545 DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs, patcher_label);
546}
547
jeffhao7fbee072012-08-24 17:56:54 -0700548void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700549 Addiu(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700550}
551
jeffhao7fbee072012-08-24 17:56:54 -0700552void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700553 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700554}
555
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200556void MipsAssembler::MultR2(Register rs, Register rt) {
557 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700558 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700559}
560
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200561void MipsAssembler::MultuR2(Register rs, Register rt) {
562 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700563 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700564}
565
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200566void MipsAssembler::DivR2(Register rs, Register rt) {
567 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700568 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700569}
570
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200571void MipsAssembler::DivuR2(Register rs, Register rt) {
572 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700573 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700574}
575
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200576void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
577 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700578 DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200579}
580
581void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
582 CHECK(!IsR6());
583 DivR2(rs, rt);
584 Mflo(rd);
585}
586
587void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
588 CHECK(!IsR6());
589 DivR2(rs, rt);
590 Mfhi(rd);
591}
592
593void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
594 CHECK(!IsR6());
595 DivuR2(rs, rt);
596 Mflo(rd);
597}
598
599void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
600 CHECK(!IsR6());
601 DivuR2(rs, rt);
602 Mfhi(rd);
603}
604
605void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
606 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700607 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200608}
609
Alexey Frunze7e99e052015-11-24 19:28:01 -0800610void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
611 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700612 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt);
Alexey Frunze7e99e052015-11-24 19:28:01 -0800613}
614
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200615void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
616 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700617 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200618}
619
620void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
621 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700622 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200623}
624
625void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
626 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700627 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200628}
629
630void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
631 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700632 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200633}
634
635void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
636 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700637 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200638}
639
jeffhao7fbee072012-08-24 17:56:54 -0700640void MipsAssembler::And(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700641 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700642}
643
644void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700645 DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700646}
647
648void MipsAssembler::Or(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700649 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700650}
651
652void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700653 DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700654}
655
656void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700657 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700658}
659
660void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700661 DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700662}
663
664void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700665 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700666}
667
Chris Larsene3845472015-11-18 12:27:15 -0800668void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
669 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700670 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800671}
672
673void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
674 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700675 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800676}
677
678void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
679 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700680 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800681}
682
683void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
684 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700685 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800686}
687
688void MipsAssembler::ClzR6(Register rd, Register rs) {
689 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700690 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800691}
692
693void MipsAssembler::ClzR2(Register rd, Register rs) {
694 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700695 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800696}
697
698void MipsAssembler::CloR6(Register rd, Register rs) {
699 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700700 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800701}
702
703void MipsAssembler::CloR2(Register rd, Register rs) {
704 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700705 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800706}
707
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200708void MipsAssembler::Seb(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700709 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700710}
711
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200712void MipsAssembler::Seh(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700713 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700714}
715
Chris Larsen3f8bf652015-10-28 10:08:56 -0700716void MipsAssembler::Wsbh(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700717 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700718}
719
Chris Larsen70014c82015-11-18 12:26:08 -0800720void MipsAssembler::Bitswap(Register rd, Register rt) {
721 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700722 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt);
Chris Larsen70014c82015-11-18 12:26:08 -0800723}
724
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200725void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700726 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700727 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700728}
729
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200730void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700731 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700732 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200733}
734
Chris Larsen3f8bf652015-10-28 10:08:56 -0700735void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
736 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700737 DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700738}
739
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200740void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700741 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700742 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200743}
744
745void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700746 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700747}
748
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200749void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700750 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700751}
752
Chris Larsene16ce5a2015-11-18 12:30:20 -0800753void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700754 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt);
Chris Larsene16ce5a2015-11-18 12:30:20 -0800755}
756
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200757void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700758 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700759}
760
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800761void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
762 CHECK(IsUint<5>(pos)) << pos;
763 CHECK(0 < size && size <= 32) << size;
764 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700765 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800766}
767
768void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
769 CHECK(IsUint<5>(pos)) << pos;
770 CHECK(0 < size && size <= 32) << size;
771 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700772 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800773}
774
Chris Larsen692235e2016-11-21 16:04:53 -0800775void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
Lena Djokic0758ae72017-05-23 11:06:23 +0200776 CHECK(IsR6() || HasMsa());
Chris Larsen692235e2016-11-21 16:04:53 -0800777 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
778 int sa = saPlusOne - 1;
779 DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
780}
781
Chris Larsencd0295d2017-03-31 15:26:54 -0700782void MipsAssembler::ShiftAndAdd(Register dst,
783 Register src_idx,
784 Register src_base,
785 int shamt,
786 Register tmp) {
787 CHECK(0 <= shamt && shamt <= 4) << shamt;
788 CHECK_NE(src_base, tmp);
789 if (shamt == TIMES_1) {
790 // Catch the special case where the shift amount is zero (0).
791 Addu(dst, src_base, src_idx);
Lena Djokic0758ae72017-05-23 11:06:23 +0200792 } else if (IsR6() || HasMsa()) {
Chris Larsencd0295d2017-03-31 15:26:54 -0700793 Lsa(dst, src_idx, src_base, shamt);
794 } else {
795 Sll(tmp, src_idx, shamt);
796 Addu(dst, src_base, tmp);
797 }
798}
799
jeffhao7fbee072012-08-24 17:56:54 -0700800void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700801 DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700802}
803
804void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700805 DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700806}
807
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700808void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
809 if (patcher_label != nullptr) {
810 Bind(patcher_label);
811 }
812 DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs, patcher_label);
813}
814
jeffhao7fbee072012-08-24 17:56:54 -0700815void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700816 Lw(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700817}
818
Chris Larsen3acee732015-11-18 13:31:08 -0800819void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
820 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700821 DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800822}
823
824void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
825 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700826 DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800827}
828
jeffhao7fbee072012-08-24 17:56:54 -0700829void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700830 DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700831}
832
833void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700834 DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700835}
836
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700837void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
838 CHECK(IsR6());
839 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700840 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700841}
842
jeffhao7fbee072012-08-24 17:56:54 -0700843void MipsAssembler::Lui(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700844 DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700845}
846
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700847void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
848 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700849 DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700850}
851
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700852void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) {
853 bool increment = (rs == rt);
854 if (increment) {
855 CHECK_NE(rs, tmp);
856 }
857 if (IsR6()) {
858 Aui(rt, rs, imm16);
859 } else if (increment) {
860 Lui(tmp, imm16);
861 Addu(rt, rs, tmp);
862 } else {
863 Lui(rt, imm16);
864 Addu(rt, rs, rt);
865 }
866}
867
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200868void MipsAssembler::Sync(uint32_t stype) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700869 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200870}
871
jeffhao7fbee072012-08-24 17:56:54 -0700872void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200873 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700874 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700875}
876
877void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200878 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700879 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700880}
881
882void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700883 DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700884}
885
886void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700887 DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700888}
889
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700890void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
891 if (patcher_label != nullptr) {
892 Bind(patcher_label);
893 }
894 DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs, patcher_label);
895}
896
jeffhao7fbee072012-08-24 17:56:54 -0700897void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700898 Sw(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700899}
900
Chris Larsen3acee732015-11-18 13:31:08 -0800901void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
902 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700903 DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800904}
905
906void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
907 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700908 DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800909}
910
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700911void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
912 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700913 DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700914}
915
916void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
917 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700918 DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700919}
920
921void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
922 CHECK(IsR6());
923 CHECK(IsInt<9>(imm9));
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700924 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700925}
926
927void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
928 CHECK(IsR6());
929 CHECK(IsInt<9>(imm9));
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700930 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700931}
932
jeffhao7fbee072012-08-24 17:56:54 -0700933void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700934 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700935}
936
937void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700938 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700939}
940
941void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700942 DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700943}
944
945void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700946 DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700947}
948
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200949void MipsAssembler::B(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700950 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200951}
952
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700953void MipsAssembler::Bal(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700954 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700955}
956
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200957void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700958 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700959}
960
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200961void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700962 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700963}
964
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200965void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700966 Beq(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700967}
968
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200969void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700970 Bne(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700971}
972
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200973void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700974 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200975}
976
977void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700978 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200979}
980
981void MipsAssembler::Blez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700982 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200983}
984
985void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700986 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200987}
988
Chris Larsenb74353a2015-11-20 09:07:09 -0800989void MipsAssembler::Bc1f(uint16_t imm16) {
990 Bc1f(0, imm16);
991}
992
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800993void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
994 CHECK(!IsR6());
995 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700996 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800997}
998
Chris Larsenb74353a2015-11-20 09:07:09 -0800999void MipsAssembler::Bc1t(uint16_t imm16) {
1000 Bc1t(0, imm16);
1001}
1002
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001003void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
1004 CHECK(!IsR6());
1005 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001006 DsFsmInstrNop(EmitI(0x11,
1007 static_cast<Register>(0x8),
1008 static_cast<Register>((cc << 2) | 1),
1009 imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001010}
1011
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001012void MipsAssembler::J(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001013 DsFsmInstrNop(EmitI26(0x2, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001014}
1015
1016void MipsAssembler::Jal(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001017 DsFsmInstrNop(EmitI26(0x3, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001018}
1019
1020void MipsAssembler::Jalr(Register rd, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001021 uint32_t last_instruction = delay_slot_.instruction_;
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001022 MipsLabel* patcher_label = delay_slot_.patcher_label_;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001023 bool exchange = (last_instruction != 0 &&
1024 (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 &&
1025 ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0);
1026 if (exchange) {
1027 // The last instruction cannot be used in a different delay slot,
1028 // do not commit the label before it (if any).
1029 DsFsmDropLabel();
1030 }
1031 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09));
1032 if (exchange) {
1033 // Exchange the last two instructions in the assembler buffer.
1034 size_t size = buffer_.Size();
1035 CHECK_GE(size, 2 * sizeof(uint32_t));
1036 size_t pos1 = size - 2 * sizeof(uint32_t);
1037 size_t pos2 = size - sizeof(uint32_t);
1038 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
1039 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
1040 CHECK_EQ(instr1, last_instruction);
1041 buffer_.Store<uint32_t>(pos1, instr2);
1042 buffer_.Store<uint32_t>(pos2, instr1);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001043 // Move the patcher label along with the patched instruction.
1044 if (patcher_label != nullptr) {
1045 patcher_label->AdjustBoundPosition(sizeof(uint32_t));
1046 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001047 } else if (reordering_) {
1048 Nop();
1049 }
jeffhao7fbee072012-08-24 17:56:54 -07001050}
1051
1052void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001053 Jalr(RA, rs);
1054}
1055
1056void MipsAssembler::Jr(Register rs) {
1057 Jalr(ZERO, rs);
1058}
1059
1060void MipsAssembler::Nal() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001061 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001062}
1063
1064void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
1065 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001066 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001067}
1068
1069void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
1070 CHECK(IsR6());
1071 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001072 DsFsmInstrNop(EmitI21(0x3B, rs, imm19));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001073}
1074
1075void MipsAssembler::Bc(uint32_t imm26) {
1076 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001077 DsFsmInstrNop(EmitI26(0x32, imm26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001078}
1079
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001080void MipsAssembler::Balc(uint32_t imm26) {
1081 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001082 DsFsmInstrNop(EmitI26(0x3A, imm26));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001083}
1084
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001085void MipsAssembler::Jic(Register rt, uint16_t imm16) {
1086 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001087 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001088}
1089
1090void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
1091 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001092 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001093}
1094
1095void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
1096 CHECK(IsR6());
1097 CHECK_NE(rs, ZERO);
1098 CHECK_NE(rt, ZERO);
1099 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001100 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001101}
1102
1103void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
1104 CHECK(IsR6());
1105 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001106 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001107}
1108
1109void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
1110 CHECK(IsR6());
1111 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001112 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001113}
1114
1115void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
1116 CHECK(IsR6());
1117 CHECK_NE(rs, ZERO);
1118 CHECK_NE(rt, ZERO);
1119 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001120 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001121}
1122
1123void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
1124 CHECK(IsR6());
1125 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001126 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001127}
1128
1129void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
1130 CHECK(IsR6());
1131 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001132 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001133}
1134
1135void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
1136 CHECK(IsR6());
1137 CHECK_NE(rs, ZERO);
1138 CHECK_NE(rt, ZERO);
1139 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001140 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001141}
1142
1143void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
1144 CHECK(IsR6());
1145 CHECK_NE(rs, ZERO);
1146 CHECK_NE(rt, ZERO);
1147 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001148 DsFsmInstrNop(EmitI(0x6, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001149}
1150
1151void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
1152 CHECK(IsR6());
1153 CHECK_NE(rs, ZERO);
1154 CHECK_NE(rt, ZERO);
1155 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001156 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001157}
1158
1159void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
1160 CHECK(IsR6());
1161 CHECK_NE(rs, ZERO);
1162 CHECK_NE(rt, ZERO);
1163 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001164 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001165}
1166
1167void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
1168 CHECK(IsR6());
1169 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001170 DsFsmInstrNop(EmitI21(0x36, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001171}
1172
1173void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
1174 CHECK(IsR6());
1175 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001176 DsFsmInstrNop(EmitI21(0x3E, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001177}
1178
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001179void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
1180 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001181 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001182}
1183
1184void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
1185 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001186 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001187}
1188
1189void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001190 switch (cond) {
1191 case kCondLTZ:
1192 CHECK_EQ(rt, ZERO);
1193 Bltz(rs, imm16);
1194 break;
1195 case kCondGEZ:
1196 CHECK_EQ(rt, ZERO);
1197 Bgez(rs, imm16);
1198 break;
1199 case kCondLEZ:
1200 CHECK_EQ(rt, ZERO);
1201 Blez(rs, imm16);
1202 break;
1203 case kCondGTZ:
1204 CHECK_EQ(rt, ZERO);
1205 Bgtz(rs, imm16);
1206 break;
1207 case kCondEQ:
1208 Beq(rs, rt, imm16);
1209 break;
1210 case kCondNE:
1211 Bne(rs, rt, imm16);
1212 break;
1213 case kCondEQZ:
1214 CHECK_EQ(rt, ZERO);
1215 Beqz(rs, imm16);
1216 break;
1217 case kCondNEZ:
1218 CHECK_EQ(rt, ZERO);
1219 Bnez(rs, imm16);
1220 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001221 case kCondF:
1222 CHECK_EQ(rt, ZERO);
1223 Bc1f(static_cast<int>(rs), imm16);
1224 break;
1225 case kCondT:
1226 CHECK_EQ(rt, ZERO);
1227 Bc1t(static_cast<int>(rs), imm16);
1228 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001229 case kCondLT:
1230 case kCondGE:
1231 case kCondLE:
1232 case kCondGT:
1233 case kCondLTU:
1234 case kCondGEU:
1235 case kUncond:
1236 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1237 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1238 LOG(FATAL) << "Unexpected branch condition " << cond;
1239 UNREACHABLE();
1240 }
1241}
1242
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001243void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001244 switch (cond) {
1245 case kCondLT:
1246 Bltc(rs, rt, imm16_21);
1247 break;
1248 case kCondGE:
1249 Bgec(rs, rt, imm16_21);
1250 break;
1251 case kCondLE:
1252 Bgec(rt, rs, imm16_21);
1253 break;
1254 case kCondGT:
1255 Bltc(rt, rs, imm16_21);
1256 break;
1257 case kCondLTZ:
1258 CHECK_EQ(rt, ZERO);
1259 Bltzc(rs, imm16_21);
1260 break;
1261 case kCondGEZ:
1262 CHECK_EQ(rt, ZERO);
1263 Bgezc(rs, imm16_21);
1264 break;
1265 case kCondLEZ:
1266 CHECK_EQ(rt, ZERO);
1267 Blezc(rs, imm16_21);
1268 break;
1269 case kCondGTZ:
1270 CHECK_EQ(rt, ZERO);
1271 Bgtzc(rs, imm16_21);
1272 break;
1273 case kCondEQ:
1274 Beqc(rs, rt, imm16_21);
1275 break;
1276 case kCondNE:
1277 Bnec(rs, rt, imm16_21);
1278 break;
1279 case kCondEQZ:
1280 CHECK_EQ(rt, ZERO);
1281 Beqzc(rs, imm16_21);
1282 break;
1283 case kCondNEZ:
1284 CHECK_EQ(rt, ZERO);
1285 Bnezc(rs, imm16_21);
1286 break;
1287 case kCondLTU:
1288 Bltuc(rs, rt, imm16_21);
1289 break;
1290 case kCondGEU:
1291 Bgeuc(rs, rt, imm16_21);
1292 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001293 case kCondF:
1294 CHECK_EQ(rt, ZERO);
1295 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
1296 break;
1297 case kCondT:
1298 CHECK_EQ(rt, ZERO);
1299 Bc1nez(static_cast<FRegister>(rs), imm16_21);
1300 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001301 case kUncond:
1302 LOG(FATAL) << "Unexpected branch condition " << cond;
1303 UNREACHABLE();
1304 }
jeffhao7fbee072012-08-24 17:56:54 -07001305}
1306
1307void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001308 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001309}
1310
1311void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001312 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001313}
1314
1315void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001316 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001317}
1318
1319void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001320 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001321}
1322
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001323void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001324 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001325}
1326
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001327void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001328 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001329}
1330
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001331void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001332 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001333}
1334
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001335void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001336 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001337}
1338
Chris Larsenb74353a2015-11-20 09:07:09 -08001339void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001340 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001341}
1342
1343void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001344 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001345}
1346
1347void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001348 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001349}
1350
1351void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001352 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001353}
1354
jeffhao7fbee072012-08-24 17:56:54 -07001355void MipsAssembler::MovS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001356 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
jeffhao7fbee072012-08-24 17:56:54 -07001357}
1358
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001359void MipsAssembler::MovD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001360 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001361}
1362
1363void MipsAssembler::NegS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001364 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001365}
1366
1367void MipsAssembler::NegD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001368 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001369}
1370
Chris Larsenb74353a2015-11-20 09:07:09 -08001371void MipsAssembler::CunS(FRegister fs, FRegister ft) {
1372 CunS(0, fs, ft);
1373}
1374
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001375void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
1376 CHECK(!IsR6());
1377 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001378 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001379}
1380
Chris Larsenb74353a2015-11-20 09:07:09 -08001381void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
1382 CeqS(0, fs, ft);
1383}
1384
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001385void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
1386 CHECK(!IsR6());
1387 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001388 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001389}
1390
Chris Larsenb74353a2015-11-20 09:07:09 -08001391void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
1392 CueqS(0, fs, ft);
1393}
1394
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001395void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
1396 CHECK(!IsR6());
1397 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001398 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001399}
1400
Chris Larsenb74353a2015-11-20 09:07:09 -08001401void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
1402 ColtS(0, fs, ft);
1403}
1404
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001405void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
1406 CHECK(!IsR6());
1407 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001408 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001409}
1410
Chris Larsenb74353a2015-11-20 09:07:09 -08001411void MipsAssembler::CultS(FRegister fs, FRegister ft) {
1412 CultS(0, fs, ft);
1413}
1414
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001415void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
1416 CHECK(!IsR6());
1417 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001418 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001419}
1420
Chris Larsenb74353a2015-11-20 09:07:09 -08001421void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
1422 ColeS(0, fs, ft);
1423}
1424
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001425void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
1426 CHECK(!IsR6());
1427 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001428 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001429}
1430
Chris Larsenb74353a2015-11-20 09:07:09 -08001431void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
1432 CuleS(0, fs, ft);
1433}
1434
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001435void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
1436 CHECK(!IsR6());
1437 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001438 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001439}
1440
Chris Larsenb74353a2015-11-20 09:07:09 -08001441void MipsAssembler::CunD(FRegister fs, FRegister ft) {
1442 CunD(0, fs, ft);
1443}
1444
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001445void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
1446 CHECK(!IsR6());
1447 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001448 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001449}
1450
Chris Larsenb74353a2015-11-20 09:07:09 -08001451void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
1452 CeqD(0, fs, ft);
1453}
1454
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001455void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
1456 CHECK(!IsR6());
1457 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001458 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001459}
1460
Chris Larsenb74353a2015-11-20 09:07:09 -08001461void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
1462 CueqD(0, fs, ft);
1463}
1464
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001465void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1466 CHECK(!IsR6());
1467 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001468 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001469}
1470
Chris Larsenb74353a2015-11-20 09:07:09 -08001471void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1472 ColtD(0, fs, ft);
1473}
1474
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001475void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1476 CHECK(!IsR6());
1477 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001478 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001479}
1480
Chris Larsenb74353a2015-11-20 09:07:09 -08001481void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1482 CultD(0, fs, ft);
1483}
1484
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001485void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1486 CHECK(!IsR6());
1487 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001488 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001489}
1490
Chris Larsenb74353a2015-11-20 09:07:09 -08001491void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1492 ColeD(0, fs, ft);
1493}
1494
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001495void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1496 CHECK(!IsR6());
1497 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001498 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001499}
1500
Chris Larsenb74353a2015-11-20 09:07:09 -08001501void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1502 CuleD(0, fs, ft);
1503}
1504
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001505void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1506 CHECK(!IsR6());
1507 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001508 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001509}
1510
1511void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1512 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001513 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001514}
1515
1516void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1517 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001518 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001519}
1520
1521void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1522 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001523 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001524}
1525
1526void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1527 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001528 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001529}
1530
1531void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1532 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001533 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001534}
1535
1536void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1537 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001538 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001539}
1540
1541void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1542 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001543 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001544}
1545
1546void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1547 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001548 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001549}
1550
1551void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1552 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001553 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001554}
1555
1556void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1557 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001558 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001559}
1560
1561void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1562 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001563 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001564}
1565
1566void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1567 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001568 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001569}
1570
1571void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1572 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001573 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001574}
1575
1576void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1577 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001578 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001579}
1580
1581void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1582 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001583 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001584}
1585
1586void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1587 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001588 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001589}
1590
1591void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1592 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001593 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001594}
1595
1596void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1597 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001598 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001599}
1600
1601void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1602 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001603 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001604}
1605
1606void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1607 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001608 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001609}
1610
1611void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1612 CHECK(!IsR6());
1613 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001614 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001615}
1616
1617void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1618 CHECK(!IsR6());
1619 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001620 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001621}
1622
Chris Larsenb74353a2015-11-20 09:07:09 -08001623void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1624 CHECK(!IsR6());
1625 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001626 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001627}
1628
1629void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1630 CHECK(!IsR6());
1631 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001632 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001633}
1634
1635void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1636 CHECK(!IsR6());
1637 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001638 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1639 fd,
1640 fs,
1641 cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001642}
1643
1644void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1645 CHECK(!IsR6());
1646 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001647 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1648 fd,
1649 fs,
1650 cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001651}
1652
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001653void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
1654 CHECK(!IsR6());
1655 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1656}
1657
1658void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
1659 CHECK(!IsR6());
1660 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1661}
1662
1663void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
1664 CHECK(!IsR6());
1665 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1666}
1667
1668void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
1669 CHECK(!IsR6());
1670 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1671}
1672
Chris Larsenb74353a2015-11-20 09:07:09 -08001673void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1674 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001675 DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001676}
1677
1678void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1679 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001680 DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001681}
1682
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001683void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
1684 CHECK(IsR6());
1685 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft);
1686}
1687
1688void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
1689 CHECK(IsR6());
1690 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft);
1691}
1692
1693void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
1694 CHECK(IsR6());
1695 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft);
1696}
1697
1698void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
1699 CHECK(IsR6());
1700 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft);
1701}
1702
Chris Larsenb74353a2015-11-20 09:07:09 -08001703void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1704 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001705 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001706}
1707
1708void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1709 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001710 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001711}
1712
1713void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1714 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001715 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001716}
1717
1718void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1719 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001720 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001721}
1722
1723void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1724 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001725 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001726}
1727
1728void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1729 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001730 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001731}
1732
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001733void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001734 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001735}
1736
1737void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001738 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001739}
1740
1741void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001742 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001743}
1744
1745void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001746 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001747}
1748
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001749void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001750 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001751}
1752
1753void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001754 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001755}
1756
1757void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001758 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001759}
1760
1761void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001762 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
jeffhao7fbee072012-08-24 17:56:54 -07001763}
1764
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001765void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001766 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001767}
1768
1769void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001770 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001771}
1772
Chris Larsenb74353a2015-11-20 09:07:09 -08001773void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001774 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001775}
1776
1777void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001778 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001779}
1780
jeffhao7fbee072012-08-24 17:56:54 -07001781void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001782 DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1783 rt,
1784 fs);
jeffhao7fbee072012-08-24 17:56:54 -07001785}
1786
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001787void MipsAssembler::Mtc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001788 DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1789 fs,
1790 rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001791}
1792
1793void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001794 DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1795 rt,
1796 fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001797}
1798
1799void MipsAssembler::Mthc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001800 DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1801 fs,
1802 rt);
jeffhao7fbee072012-08-24 17:56:54 -07001803}
1804
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001805void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1806 if (Is32BitFPU()) {
1807 CHECK_EQ(fs % 2, 0) << fs;
1808 Mfc1(rt, static_cast<FRegister>(fs + 1));
1809 } else {
1810 Mfhc1(rt, fs);
1811 }
1812}
1813
1814void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1815 if (Is32BitFPU()) {
1816 CHECK_EQ(fs % 2, 0) << fs;
1817 Mtc1(rt, static_cast<FRegister>(fs + 1));
1818 } else {
1819 Mthc1(rt, fs);
1820 }
1821}
1822
jeffhao7fbee072012-08-24 17:56:54 -07001823void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001824 DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001825}
1826
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001827void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001828 DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001829}
1830
1831void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001832 DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001833}
1834
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001835void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001836 DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001837}
1838
1839void MipsAssembler::Break() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001840 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD));
jeffhao7fbee072012-08-24 17:56:54 -07001841}
1842
jeffhao07030602012-09-26 14:33:14 -07001843void MipsAssembler::Nop() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001844 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0));
1845}
1846
1847void MipsAssembler::NopIfNoReordering() {
1848 if (!reordering_) {
1849 Nop();
1850 }
jeffhao07030602012-09-26 14:33:14 -07001851}
1852
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001853void MipsAssembler::Move(Register rd, Register rs) {
1854 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001855}
1856
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001857void MipsAssembler::Clear(Register rd) {
1858 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001859}
1860
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001861void MipsAssembler::Not(Register rd, Register rs) {
1862 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001863}
1864
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001865void MipsAssembler::Push(Register rs) {
Chris Larsen715f43e2017-10-23 11:00:32 -07001866 IncreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001867 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001868}
1869
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001870void MipsAssembler::Pop(Register rd) {
1871 Lw(rd, SP, 0);
Chris Larsen715f43e2017-10-23 11:00:32 -07001872 DecreaseFrameSize(kStackAlignment);
jeffhao7fbee072012-08-24 17:56:54 -07001873}
1874
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001875void MipsAssembler::PopAndReturn(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001876 bool reordering = SetReorder(false);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001877 Lw(rd, SP, 0);
1878 Jr(rt);
Chris Larsen715f43e2017-10-23 11:00:32 -07001879 DecreaseFrameSize(kStackAlignment); // Single instruction in delay slot.
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001880 SetReorder(reordering);
jeffhao7fbee072012-08-24 17:56:54 -07001881}
1882
Lena Djokic0758ae72017-05-23 11:06:23 +02001883void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1884 CHECK(HasMsa());
1885 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e),
1886 static_cast<FRegister>(wd),
1887 static_cast<FRegister>(ws),
1888 static_cast<FRegister>(wt));
1889}
1890
1891void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1892 CHECK(HasMsa());
1893 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e),
1894 static_cast<FRegister>(wd),
1895 static_cast<FRegister>(ws),
1896 static_cast<FRegister>(wt));
1897}
1898
1899void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1900 CHECK(HasMsa());
1901 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e),
1902 static_cast<FRegister>(wd),
1903 static_cast<FRegister>(ws),
1904 static_cast<FRegister>(wt));
1905}
1906
1907void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1908 CHECK(HasMsa());
1909 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e),
1910 static_cast<FRegister>(wd),
1911 static_cast<FRegister>(ws),
1912 static_cast<FRegister>(wt));
1913}
1914
1915void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1916 CHECK(HasMsa());
1917 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe),
1918 static_cast<FRegister>(wd),
1919 static_cast<FRegister>(ws),
1920 static_cast<FRegister>(wt));
1921}
1922
1923void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1924 CHECK(HasMsa());
1925 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe),
1926 static_cast<FRegister>(wd),
1927 static_cast<FRegister>(ws),
1928 static_cast<FRegister>(wt));
1929}
1930
1931void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1932 CHECK(HasMsa());
1933 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe),
1934 static_cast<FRegister>(wd),
1935 static_cast<FRegister>(ws),
1936 static_cast<FRegister>(wt));
1937}
1938
1939void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1940 CHECK(HasMsa());
1941 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe),
1942 static_cast<FRegister>(wd),
1943 static_cast<FRegister>(ws),
1944 static_cast<FRegister>(wt));
1945}
1946
1947void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1948 CHECK(HasMsa());
1949 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe),
1950 static_cast<FRegister>(wd),
1951 static_cast<FRegister>(ws),
1952 static_cast<FRegister>(wt));
1953}
1954
1955void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1956 CHECK(HasMsa());
1957 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe),
1958 static_cast<FRegister>(wd),
1959 static_cast<FRegister>(ws),
1960 static_cast<FRegister>(wt));
1961}
1962
1963void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1964 CHECK(HasMsa());
1965 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe),
1966 static_cast<FRegister>(wd),
1967 static_cast<FRegister>(ws),
1968 static_cast<FRegister>(wt));
1969}
1970
1971void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1972 CHECK(HasMsa());
1973 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe),
1974 static_cast<FRegister>(wd),
1975 static_cast<FRegister>(ws),
1976 static_cast<FRegister>(wt));
1977}
1978
1979void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1980 CHECK(HasMsa());
1981 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12),
1982 static_cast<FRegister>(wd),
1983 static_cast<FRegister>(ws),
1984 static_cast<FRegister>(wt));
1985}
1986
1987void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1988 CHECK(HasMsa());
1989 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12),
1990 static_cast<FRegister>(wd),
1991 static_cast<FRegister>(ws),
1992 static_cast<FRegister>(wt));
1993}
1994
1995void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1996 CHECK(HasMsa());
1997 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12),
1998 static_cast<FRegister>(wd),
1999 static_cast<FRegister>(ws),
2000 static_cast<FRegister>(wt));
2001}
2002
2003void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2004 CHECK(HasMsa());
2005 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12),
2006 static_cast<FRegister>(wd),
2007 static_cast<FRegister>(ws),
2008 static_cast<FRegister>(wt));
2009}
2010
2011void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2012 CHECK(HasMsa());
2013 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12),
2014 static_cast<FRegister>(wd),
2015 static_cast<FRegister>(ws),
2016 static_cast<FRegister>(wt));
2017}
2018
2019void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2020 CHECK(HasMsa());
2021 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12),
2022 static_cast<FRegister>(wd),
2023 static_cast<FRegister>(ws),
2024 static_cast<FRegister>(wt));
2025}
2026
2027void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2028 CHECK(HasMsa());
2029 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12),
2030 static_cast<FRegister>(wd),
2031 static_cast<FRegister>(ws),
2032 static_cast<FRegister>(wt));
2033}
2034
2035void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2036 CHECK(HasMsa());
2037 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12),
2038 static_cast<FRegister>(wd),
2039 static_cast<FRegister>(ws),
2040 static_cast<FRegister>(wt));
2041}
2042
2043void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2044 CHECK(HasMsa());
2045 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12),
2046 static_cast<FRegister>(wd),
2047 static_cast<FRegister>(ws),
2048 static_cast<FRegister>(wt));
2049}
2050
2051void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2052 CHECK(HasMsa());
2053 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12),
2054 static_cast<FRegister>(wd),
2055 static_cast<FRegister>(ws),
2056 static_cast<FRegister>(wt));
2057}
2058
2059void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2060 CHECK(HasMsa());
2061 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12),
2062 static_cast<FRegister>(wd),
2063 static_cast<FRegister>(ws),
2064 static_cast<FRegister>(wt));
2065}
2066
2067void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2068 CHECK(HasMsa());
2069 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12),
2070 static_cast<FRegister>(wd),
2071 static_cast<FRegister>(ws),
2072 static_cast<FRegister>(wt));
2073}
2074
2075void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2076 CHECK(HasMsa());
2077 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12),
2078 static_cast<FRegister>(wd),
2079 static_cast<FRegister>(ws),
2080 static_cast<FRegister>(wt));
2081}
2082
2083void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2084 CHECK(HasMsa());
2085 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12),
2086 static_cast<FRegister>(wd),
2087 static_cast<FRegister>(ws),
2088 static_cast<FRegister>(wt));
2089}
2090
2091void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2092 CHECK(HasMsa());
2093 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12),
2094 static_cast<FRegister>(wd),
2095 static_cast<FRegister>(ws),
2096 static_cast<FRegister>(wt));
2097}
2098
2099void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2100 CHECK(HasMsa());
2101 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12),
2102 static_cast<FRegister>(wd),
2103 static_cast<FRegister>(ws),
2104 static_cast<FRegister>(wt));
2105}
2106
2107void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2108 CHECK(HasMsa());
2109 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12),
2110 static_cast<FRegister>(wd),
2111 static_cast<FRegister>(ws),
2112 static_cast<FRegister>(wt));
2113}
2114
2115void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2116 CHECK(HasMsa());
2117 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12),
2118 static_cast<FRegister>(wd),
2119 static_cast<FRegister>(ws),
2120 static_cast<FRegister>(wt));
2121}
2122
2123void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2124 CHECK(HasMsa());
2125 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12),
2126 static_cast<FRegister>(wd),
2127 static_cast<FRegister>(ws),
2128 static_cast<FRegister>(wt));
2129}
2130
2131void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2132 CHECK(HasMsa());
2133 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12),
2134 static_cast<FRegister>(wd),
2135 static_cast<FRegister>(ws),
2136 static_cast<FRegister>(wt));
2137}
2138
2139void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2140 CHECK(HasMsa());
2141 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10),
2142 static_cast<FRegister>(wd),
2143 static_cast<FRegister>(ws),
2144 static_cast<FRegister>(wt));
2145}
2146
2147void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2148 CHECK(HasMsa());
2149 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10),
2150 static_cast<FRegister>(wd),
2151 static_cast<FRegister>(ws),
2152 static_cast<FRegister>(wt));
2153}
2154
2155void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2156 CHECK(HasMsa());
2157 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10),
2158 static_cast<FRegister>(wd),
2159 static_cast<FRegister>(ws),
2160 static_cast<FRegister>(wt));
2161}
2162
2163void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2164 CHECK(HasMsa());
2165 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10),
2166 static_cast<FRegister>(wd),
2167 static_cast<FRegister>(ws),
2168 static_cast<FRegister>(wt));
2169}
2170
2171void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2172 CHECK(HasMsa());
2173 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10),
2174 static_cast<FRegister>(wd),
2175 static_cast<FRegister>(ws),
2176 static_cast<FRegister>(wt));
2177}
2178
2179void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2180 CHECK(HasMsa());
2181 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10),
2182 static_cast<FRegister>(wd),
2183 static_cast<FRegister>(ws),
2184 static_cast<FRegister>(wt));
2185}
2186
2187void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2188 CHECK(HasMsa());
2189 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10),
2190 static_cast<FRegister>(wd),
2191 static_cast<FRegister>(ws),
2192 static_cast<FRegister>(wt));
2193}
2194
2195void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2196 CHECK(HasMsa());
2197 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10),
2198 static_cast<FRegister>(wd),
2199 static_cast<FRegister>(ws),
2200 static_cast<FRegister>(wt));
2201}
2202
2203void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2204 CHECK(HasMsa());
2205 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10),
2206 static_cast<FRegister>(wd),
2207 static_cast<FRegister>(ws),
2208 static_cast<FRegister>(wt));
2209}
2210
2211void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2212 CHECK(HasMsa());
2213 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10),
2214 static_cast<FRegister>(wd),
2215 static_cast<FRegister>(ws),
2216 static_cast<FRegister>(wt));
2217}
2218
2219void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2220 CHECK(HasMsa());
2221 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10),
2222 static_cast<FRegister>(wd),
2223 static_cast<FRegister>(ws),
2224 static_cast<FRegister>(wt));
2225}
2226
2227void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2228 CHECK(HasMsa());
2229 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10),
2230 static_cast<FRegister>(wd),
2231 static_cast<FRegister>(ws),
2232 static_cast<FRegister>(wt));
2233}
2234
2235void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2236 CHECK(HasMsa());
2237 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10),
2238 static_cast<FRegister>(wd),
2239 static_cast<FRegister>(ws),
2240 static_cast<FRegister>(wt));
2241}
2242
2243void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2244 CHECK(HasMsa());
2245 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10),
2246 static_cast<FRegister>(wd),
2247 static_cast<FRegister>(ws),
2248 static_cast<FRegister>(wt));
2249}
2250
2251void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2252 CHECK(HasMsa());
2253 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10),
2254 static_cast<FRegister>(wd),
2255 static_cast<FRegister>(ws),
2256 static_cast<FRegister>(wt));
2257}
2258
2259void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2260 CHECK(HasMsa());
2261 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10),
2262 static_cast<FRegister>(wd),
2263 static_cast<FRegister>(ws),
2264 static_cast<FRegister>(wt));
2265}
2266
2267void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2268 CHECK(HasMsa());
2269 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10),
2270 static_cast<FRegister>(wd),
2271 static_cast<FRegister>(ws),
2272 static_cast<FRegister>(wt));
2273}
2274
2275void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2276 CHECK(HasMsa());
2277 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10),
2278 static_cast<FRegister>(wd),
2279 static_cast<FRegister>(ws),
2280 static_cast<FRegister>(wt));
2281}
2282
2283void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2284 CHECK(HasMsa());
2285 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10),
2286 static_cast<FRegister>(wd),
2287 static_cast<FRegister>(ws),
2288 static_cast<FRegister>(wt));
2289}
2290
2291void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2292 CHECK(HasMsa());
2293 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10),
2294 static_cast<FRegister>(wd),
2295 static_cast<FRegister>(ws),
2296 static_cast<FRegister>(wt));
2297}
2298
2299void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2300 CHECK(HasMsa());
2301 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe),
2302 static_cast<FRegister>(wd),
2303 static_cast<FRegister>(ws),
2304 static_cast<FRegister>(wt));
2305}
2306
2307void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2308 CHECK(HasMsa());
2309 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe),
2310 static_cast<FRegister>(wd),
2311 static_cast<FRegister>(ws),
2312 static_cast<FRegister>(wt));
2313}
2314
2315void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2316 CHECK(HasMsa());
2317 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe),
2318 static_cast<FRegister>(wd),
2319 static_cast<FRegister>(ws),
2320 static_cast<FRegister>(wt));
2321}
2322
2323void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2324 CHECK(HasMsa());
2325 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe),
2326 static_cast<FRegister>(wd),
2327 static_cast<FRegister>(ws),
2328 static_cast<FRegister>(wt));
2329}
2330
2331void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2332 CHECK(HasMsa());
2333 DsFsmInstrFff(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe),
2334 static_cast<FRegister>(wd),
2335 static_cast<FRegister>(ws),
2336 static_cast<FRegister>(wt));
2337}
2338
2339void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2340 CHECK(HasMsa());
2341 DsFsmInstrFff(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe),
2342 static_cast<FRegister>(wd),
2343 static_cast<FRegister>(ws),
2344 static_cast<FRegister>(wt));
2345}
2346
2347void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2348 CHECK(HasMsa());
2349 DsFsmInstrFff(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe),
2350 static_cast<FRegister>(wd),
2351 static_cast<FRegister>(ws),
2352 static_cast<FRegister>(wt));
2353}
2354
2355void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2356 CHECK(HasMsa());
2357 DsFsmInstrFff(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe),
2358 static_cast<FRegister>(wd),
2359 static_cast<FRegister>(ws),
2360 static_cast<FRegister>(wt));
2361}
2362
2363void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2364 CHECK(HasMsa());
2365 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe),
2366 static_cast<FRegister>(wd),
2367 static_cast<FRegister>(ws),
2368 static_cast<FRegister>(wt));
2369}
2370
2371void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2372 CHECK(HasMsa());
2373 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe),
2374 static_cast<FRegister>(wd),
2375 static_cast<FRegister>(ws),
2376 static_cast<FRegister>(wt));
2377}
2378
2379void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2380 CHECK(HasMsa());
2381 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe),
2382 static_cast<FRegister>(wd),
2383 static_cast<FRegister>(ws),
2384 static_cast<FRegister>(wt));
2385}
2386
2387void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2388 CHECK(HasMsa());
2389 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe),
2390 static_cast<FRegister>(wd),
2391 static_cast<FRegister>(ws),
2392 static_cast<FRegister>(wt));
2393}
2394
2395void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2396 CHECK(HasMsa());
2397 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe),
2398 static_cast<FRegister>(wd),
2399 static_cast<FRegister>(ws),
2400 static_cast<FRegister>(wt));
2401}
2402
2403void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2404 CHECK(HasMsa());
2405 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe),
2406 static_cast<FRegister>(wd),
2407 static_cast<FRegister>(ws),
2408 static_cast<FRegister>(wt));
2409}
2410
2411void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2412 CHECK(HasMsa());
2413 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe),
2414 static_cast<FRegister>(wd),
2415 static_cast<FRegister>(ws),
2416 static_cast<FRegister>(wt));
2417}
2418
2419void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2420 CHECK(HasMsa());
2421 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe),
2422 static_cast<FRegister>(wd),
2423 static_cast<FRegister>(ws),
2424 static_cast<FRegister>(wt));
2425}
2426
2427void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2428 CHECK(HasMsa());
2429 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b),
2430 static_cast<FRegister>(wd),
2431 static_cast<FRegister>(ws),
2432 static_cast<FRegister>(wt));
2433}
2434
2435void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2436 CHECK(HasMsa());
2437 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b),
2438 static_cast<FRegister>(wd),
2439 static_cast<FRegister>(ws),
2440 static_cast<FRegister>(wt));
2441}
2442
2443void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2444 CHECK(HasMsa());
2445 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b),
2446 static_cast<FRegister>(wd),
2447 static_cast<FRegister>(ws),
2448 static_cast<FRegister>(wt));
2449}
2450
2451void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2452 CHECK(HasMsa());
2453 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b),
2454 static_cast<FRegister>(wd),
2455 static_cast<FRegister>(ws),
2456 static_cast<FRegister>(wt));
2457}
2458
2459void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2460 CHECK(HasMsa());
2461 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b),
2462 static_cast<FRegister>(wd),
2463 static_cast<FRegister>(ws),
2464 static_cast<FRegister>(wt));
2465}
2466
2467void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2468 CHECK(HasMsa());
2469 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b),
2470 static_cast<FRegister>(wd),
2471 static_cast<FRegister>(ws),
2472 static_cast<FRegister>(wt));
2473}
2474
2475void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2476 CHECK(HasMsa());
2477 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b),
2478 static_cast<FRegister>(wd),
2479 static_cast<FRegister>(ws),
2480 static_cast<FRegister>(wt));
2481}
2482
2483void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2484 CHECK(HasMsa());
2485 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b),
2486 static_cast<FRegister>(wd),
2487 static_cast<FRegister>(ws),
2488 static_cast<FRegister>(wt));
2489}
2490
2491void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2492 CHECK(HasMsa());
2493 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b),
2494 static_cast<FRegister>(wd),
2495 static_cast<FRegister>(ws),
2496 static_cast<FRegister>(wt));
2497}
2498
2499void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2500 CHECK(HasMsa());
2501 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b),
2502 static_cast<FRegister>(wd),
2503 static_cast<FRegister>(ws),
2504 static_cast<FRegister>(wt));
2505}
2506
2507void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2508 CHECK(HasMsa());
2509 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b),
2510 static_cast<FRegister>(wd),
2511 static_cast<FRegister>(ws),
2512 static_cast<FRegister>(wt));
2513}
2514
2515void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2516 CHECK(HasMsa());
2517 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b),
2518 static_cast<FRegister>(wd),
2519 static_cast<FRegister>(ws),
2520 static_cast<FRegister>(wt));
2521}
2522
2523void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
2524 CHECK(HasMsa());
2525 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e),
2526 static_cast<FRegister>(wd),
2527 static_cast<FRegister>(ws),
2528 static_cast<FRegister>(ws));
2529}
2530
2531void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
2532 CHECK(HasMsa());
2533 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e),
2534 static_cast<FRegister>(wd),
2535 static_cast<FRegister>(ws),
2536 static_cast<FRegister>(ws));
2537}
2538
2539void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
2540 CHECK(HasMsa());
2541 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e),
2542 static_cast<FRegister>(wd),
2543 static_cast<FRegister>(ws),
2544 static_cast<FRegister>(ws));
2545}
2546
2547void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
2548 CHECK(HasMsa());
2549 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e),
2550 static_cast<FRegister>(wd),
2551 static_cast<FRegister>(ws),
2552 static_cast<FRegister>(ws));
2553}
2554
2555void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2556 CHECK(HasMsa());
2557 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd),
2558 static_cast<FRegister>(wd),
2559 static_cast<FRegister>(ws),
2560 static_cast<FRegister>(wt));
2561}
2562
2563void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2564 CHECK(HasMsa());
2565 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd),
2566 static_cast<FRegister>(wd),
2567 static_cast<FRegister>(ws),
2568 static_cast<FRegister>(wt));
2569}
2570
2571void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2572 CHECK(HasMsa());
2573 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd),
2574 static_cast<FRegister>(wd),
2575 static_cast<FRegister>(ws),
2576 static_cast<FRegister>(wt));
2577}
2578
2579void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2580 CHECK(HasMsa());
2581 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd),
2582 static_cast<FRegister>(wd),
2583 static_cast<FRegister>(ws),
2584 static_cast<FRegister>(wt));
2585}
2586
2587void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2588 CHECK(HasMsa());
2589 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd),
2590 static_cast<FRegister>(wd),
2591 static_cast<FRegister>(ws),
2592 static_cast<FRegister>(wt));
2593}
2594
2595void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2596 CHECK(HasMsa());
2597 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd),
2598 static_cast<FRegister>(wd),
2599 static_cast<FRegister>(ws),
2600 static_cast<FRegister>(wt));
2601}
2602
2603void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2604 CHECK(HasMsa());
2605 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd),
2606 static_cast<FRegister>(wd),
2607 static_cast<FRegister>(ws),
2608 static_cast<FRegister>(wt));
2609}
2610
2611void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2612 CHECK(HasMsa());
2613 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd),
2614 static_cast<FRegister>(wd),
2615 static_cast<FRegister>(ws),
2616 static_cast<FRegister>(wt));
2617}
2618
2619void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2620 CHECK(HasMsa());
2621 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd),
2622 static_cast<FRegister>(wd),
2623 static_cast<FRegister>(ws),
2624 static_cast<FRegister>(wt));
2625}
2626
2627void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2628 CHECK(HasMsa());
2629 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd),
2630 static_cast<FRegister>(wd),
2631 static_cast<FRegister>(ws),
2632 static_cast<FRegister>(wt));
2633}
2634
2635void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2636 CHECK(HasMsa());
2637 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd),
2638 static_cast<FRegister>(wd),
2639 static_cast<FRegister>(ws),
2640 static_cast<FRegister>(wt));
2641}
2642
2643void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2644 CHECK(HasMsa());
2645 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd),
2646 static_cast<FRegister>(wd),
2647 static_cast<FRegister>(ws),
2648 static_cast<FRegister>(wt));
2649}
2650
2651void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2652 CHECK(HasMsa());
2653 CHECK(IsUint<3>(shamt3)) << shamt3;
2654 DsFsmInstrFff(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2655 static_cast<FRegister>(wd),
2656 static_cast<FRegister>(ws),
2657 static_cast<FRegister>(ws));
2658}
2659
2660void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2661 CHECK(HasMsa());
2662 CHECK(IsUint<4>(shamt4)) << shamt4;
2663 DsFsmInstrFff(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2664 static_cast<FRegister>(wd),
2665 static_cast<FRegister>(ws),
2666 static_cast<FRegister>(ws));
2667}
2668
2669void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2670 CHECK(HasMsa());
2671 CHECK(IsUint<5>(shamt5)) << shamt5;
2672 DsFsmInstrFff(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2673 static_cast<FRegister>(wd),
2674 static_cast<FRegister>(ws),
2675 static_cast<FRegister>(ws));
2676}
2677
2678void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2679 CHECK(HasMsa());
2680 CHECK(IsUint<6>(shamt6)) << shamt6;
2681 DsFsmInstrFff(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2682 static_cast<FRegister>(wd),
2683 static_cast<FRegister>(ws),
2684 static_cast<FRegister>(ws));
2685}
2686
2687void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
2688 CHECK(HasMsa());
2689 CHECK(IsUint<3>(shamt3)) << shamt3;
2690 DsFsmInstrFff(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2691 static_cast<FRegister>(wd),
2692 static_cast<FRegister>(ws),
2693 static_cast<FRegister>(ws));
2694}
2695
2696void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
2697 CHECK(HasMsa());
2698 CHECK(IsUint<4>(shamt4)) << shamt4;
2699 DsFsmInstrFff(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2700 static_cast<FRegister>(wd),
2701 static_cast<FRegister>(ws),
2702 static_cast<FRegister>(ws));
2703}
2704
2705void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
2706 CHECK(HasMsa());
2707 CHECK(IsUint<5>(shamt5)) << shamt5;
2708 DsFsmInstrFff(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2709 static_cast<FRegister>(wd),
2710 static_cast<FRegister>(ws),
2711 static_cast<FRegister>(ws));
2712}
2713
2714void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
2715 CHECK(HasMsa());
2716 CHECK(IsUint<6>(shamt6)) << shamt6;
2717 DsFsmInstrFff(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2718 static_cast<FRegister>(wd),
2719 static_cast<FRegister>(ws),
2720 static_cast<FRegister>(ws));
2721}
2722
2723void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2724 CHECK(HasMsa());
2725 CHECK(IsUint<3>(shamt3)) << shamt3;
2726 DsFsmInstrFff(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2727 static_cast<FRegister>(wd),
2728 static_cast<FRegister>(ws),
2729 static_cast<FRegister>(ws));
2730}
2731
2732void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2733 CHECK(HasMsa());
2734 CHECK(IsUint<4>(shamt4)) << shamt4;
2735 DsFsmInstrFff(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2736 static_cast<FRegister>(wd),
2737 static_cast<FRegister>(ws),
2738 static_cast<FRegister>(ws));
2739}
2740
2741void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2742 CHECK(HasMsa());
2743 CHECK(IsUint<5>(shamt5)) << shamt5;
2744 DsFsmInstrFff(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2745 static_cast<FRegister>(wd),
2746 static_cast<FRegister>(ws),
2747 static_cast<FRegister>(ws));
2748}
2749
2750void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2751 CHECK(HasMsa());
2752 CHECK(IsUint<6>(shamt6)) << shamt6;
2753 DsFsmInstrFff(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2754 static_cast<FRegister>(wd),
2755 static_cast<FRegister>(ws),
2756 static_cast<FRegister>(ws));
2757}
2758
2759void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) {
2760 CHECK(HasMsa());
2761 DsFsmInstrFff(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19),
2762 static_cast<FRegister>(wd),
2763 static_cast<FRegister>(ws),
2764 static_cast<FRegister>(ws));
2765}
2766
2767void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
2768 CHECK(HasMsa());
2769 CHECK(IsUint<4>(n4)) << n4;
2770 DsFsmInstrFff(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19),
2771 static_cast<FRegister>(wd),
2772 static_cast<FRegister>(ws),
2773 static_cast<FRegister>(ws));
2774}
2775
2776void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
2777 CHECK(HasMsa());
2778 CHECK(IsUint<3>(n3)) << n3;
2779 DsFsmInstrFff(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19),
2780 static_cast<FRegister>(wd),
2781 static_cast<FRegister>(ws),
2782 static_cast<FRegister>(ws));
2783}
2784
2785void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
2786 CHECK(HasMsa());
2787 CHECK(IsUint<2>(n2)) << n2;
2788 DsFsmInstrFff(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19),
2789 static_cast<FRegister>(wd),
2790 static_cast<FRegister>(ws),
2791 static_cast<FRegister>(ws));
2792}
2793
2794void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
2795 CHECK(HasMsa());
2796 CHECK(IsUint<1>(n1)) << n1;
2797 DsFsmInstrFff(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19),
2798 static_cast<FRegister>(wd),
2799 static_cast<FRegister>(ws),
2800 static_cast<FRegister>(ws));
2801}
2802
Lena Djokic3309c012017-10-13 14:34:32 +02002803void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) {
2804 CHECK(HasMsa());
2805 CHECK(IsUint<4>(n4)) << n4;
2806 DsFsmInstrRf(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
2807 rd,
2808 static_cast<FRegister>(ws));
2809}
2810
2811void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) {
2812 CHECK(HasMsa());
2813 CHECK(IsUint<3>(n3)) << n3;
2814 DsFsmInstrRf(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
2815 rd,
2816 static_cast<FRegister>(ws));
2817}
2818
2819void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) {
2820 CHECK(HasMsa());
2821 CHECK(IsUint<2>(n2)) << n2;
2822 DsFsmInstrRf(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19),
2823 rd,
2824 static_cast<FRegister>(ws));
2825}
2826
2827void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) {
2828 CHECK(HasMsa());
2829 CHECK(IsUint<4>(n4)) << n4;
2830 DsFsmInstrRf(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
2831 rd,
2832 static_cast<FRegister>(ws));
2833}
2834
2835void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) {
2836 CHECK(HasMsa());
2837 CHECK(IsUint<3>(n3)) << n3;
2838 DsFsmInstrRf(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
2839 rd,
2840 static_cast<FRegister>(ws));
2841}
2842
2843void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) {
2844 CHECK(HasMsa());
2845 CHECK(IsUint<4>(n4)) << n4;
2846 DsFsmInstrFffr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19),
2847 static_cast<FRegister>(wd),
2848 static_cast<FRegister>(wd),
2849 rs);
2850}
2851
2852void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) {
2853 CHECK(HasMsa());
2854 CHECK(IsUint<3>(n3)) << n3;
2855 DsFsmInstrFffr(
2856 EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19),
2857 static_cast<FRegister>(wd),
2858 static_cast<FRegister>(wd),
2859 rs);
2860}
2861
2862void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) {
2863 CHECK(HasMsa());
2864 CHECK(IsUint<2>(n2)) << n2;
2865 DsFsmInstrFffr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19),
2866 static_cast<FRegister>(wd),
2867 static_cast<FRegister>(wd),
2868 rs);
2869}
2870
Lena Djokic0758ae72017-05-23 11:06:23 +02002871void MipsAssembler::FillB(VectorRegister wd, Register rs) {
2872 CHECK(HasMsa());
2873 DsFsmInstrFr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e),
2874 static_cast<FRegister>(wd),
2875 rs);
2876}
2877
2878void MipsAssembler::FillH(VectorRegister wd, Register rs) {
2879 CHECK(HasMsa());
2880 DsFsmInstrFr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e),
2881 static_cast<FRegister>(wd),
2882 rs);
2883}
2884
2885void MipsAssembler::FillW(VectorRegister wd, Register rs) {
2886 CHECK(HasMsa());
2887 DsFsmInstrFr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e),
2888 static_cast<FRegister>(wd),
2889 rs);
2890}
2891
2892void MipsAssembler::LdiB(VectorRegister wd, int imm8) {
2893 CHECK(HasMsa());
2894 CHECK(IsInt<8>(imm8)) << imm8;
2895 DsFsmInstrFr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7),
2896 static_cast<FRegister>(wd),
2897 ZERO);
2898}
2899
2900void MipsAssembler::LdiH(VectorRegister wd, int imm10) {
2901 CHECK(HasMsa());
2902 CHECK(IsInt<10>(imm10)) << imm10;
2903 DsFsmInstrFr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7),
2904 static_cast<FRegister>(wd),
2905 ZERO);
2906}
2907
2908void MipsAssembler::LdiW(VectorRegister wd, int imm10) {
2909 CHECK(HasMsa());
2910 CHECK(IsInt<10>(imm10)) << imm10;
2911 DsFsmInstrFr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7),
2912 static_cast<FRegister>(wd),
2913 ZERO);
2914}
2915
2916void MipsAssembler::LdiD(VectorRegister wd, int imm10) {
2917 CHECK(HasMsa());
2918 CHECK(IsInt<10>(imm10)) << imm10;
2919 DsFsmInstrFr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7),
2920 static_cast<FRegister>(wd),
2921 ZERO);
2922}
2923
2924void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) {
2925 CHECK(HasMsa());
2926 CHECK(IsInt<10>(offset)) << offset;
2927 DsFsmInstrFr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0),
2928 static_cast<FRegister>(wd),
2929 rs);
2930}
2931
2932void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) {
2933 CHECK(HasMsa());
2934 CHECK(IsInt<11>(offset)) << offset;
2935 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2936 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1),
2937 static_cast<FRegister>(wd),
2938 rs);
2939}
2940
2941void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) {
2942 CHECK(HasMsa());
2943 CHECK(IsInt<12>(offset)) << offset;
2944 CHECK_ALIGNED(offset, kMipsWordSize);
2945 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2),
2946 static_cast<FRegister>(wd),
2947 rs);
2948}
2949
2950void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) {
2951 CHECK(HasMsa());
2952 CHECK(IsInt<13>(offset)) << offset;
2953 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2954 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3),
2955 static_cast<FRegister>(wd),
2956 rs);
2957}
2958
2959void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) {
2960 CHECK(HasMsa());
2961 CHECK(IsInt<10>(offset)) << offset;
2962 DsFsmInstrFR(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0), static_cast<FRegister>(wd), rs);
2963}
2964
2965void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) {
2966 CHECK(HasMsa());
2967 CHECK(IsInt<11>(offset)) << offset;
2968 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2969 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1),
2970 static_cast<FRegister>(wd),
2971 rs);
2972}
2973
2974void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) {
2975 CHECK(HasMsa());
2976 CHECK(IsInt<12>(offset)) << offset;
2977 CHECK_ALIGNED(offset, kMipsWordSize);
2978 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2),
2979 static_cast<FRegister>(wd),
2980 rs);
2981}
2982
2983void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
2984 CHECK(HasMsa());
2985 CHECK(IsInt<13>(offset)) << offset;
2986 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2987 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3),
2988 static_cast<FRegister>(wd),
2989 rs);
2990}
2991
Lena Djokic3309c012017-10-13 14:34:32 +02002992void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2993 CHECK(HasMsa());
2994 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14),
2995 static_cast<FRegister>(wd),
2996 static_cast<FRegister>(ws),
2997 static_cast<FRegister>(wt));
2998}
2999
3000void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3001 CHECK(HasMsa());
3002 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14),
3003 static_cast<FRegister>(wd),
3004 static_cast<FRegister>(ws),
3005 static_cast<FRegister>(wt));
3006}
3007
3008void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3009 CHECK(HasMsa());
3010 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14),
3011 static_cast<FRegister>(wd),
3012 static_cast<FRegister>(ws),
3013 static_cast<FRegister>(wt));
3014}
3015
3016void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3017 CHECK(HasMsa());
3018 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14),
3019 static_cast<FRegister>(wd),
3020 static_cast<FRegister>(ws),
3021 static_cast<FRegister>(wt));
3022}
3023
Lena Djokic0758ae72017-05-23 11:06:23 +02003024void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3025 CHECK(HasMsa());
3026 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14),
3027 static_cast<FRegister>(wd),
3028 static_cast<FRegister>(ws),
3029 static_cast<FRegister>(wt));
3030}
3031
3032void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3033 CHECK(HasMsa());
3034 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14),
3035 static_cast<FRegister>(wd),
3036 static_cast<FRegister>(ws),
3037 static_cast<FRegister>(wt));
3038}
3039
3040void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3041 CHECK(HasMsa());
3042 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14),
3043 static_cast<FRegister>(wd),
3044 static_cast<FRegister>(ws),
3045 static_cast<FRegister>(wt));
3046}
3047
3048void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3049 CHECK(HasMsa());
3050 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14),
3051 static_cast<FRegister>(wd),
3052 static_cast<FRegister>(ws),
3053 static_cast<FRegister>(wt));
3054}
3055
Lena Djokic3309c012017-10-13 14:34:32 +02003056void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3057 CHECK(HasMsa());
3058 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14),
3059 static_cast<FRegister>(wd),
3060 static_cast<FRegister>(ws),
3061 static_cast<FRegister>(wt));
3062}
3063
3064void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3065 CHECK(HasMsa());
3066 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14),
3067 static_cast<FRegister>(wd),
3068 static_cast<FRegister>(ws),
3069 static_cast<FRegister>(wt));
3070}
3071
3072void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3073 CHECK(HasMsa());
3074 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14),
3075 static_cast<FRegister>(wd),
3076 static_cast<FRegister>(ws),
3077 static_cast<FRegister>(wt));
3078}
3079
3080void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3081 CHECK(HasMsa());
3082 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14),
3083 static_cast<FRegister>(wd),
3084 static_cast<FRegister>(ws),
3085 static_cast<FRegister>(wt));
3086}
3087
3088void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3089 CHECK(HasMsa());
3090 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14),
3091 static_cast<FRegister>(wd),
3092 static_cast<FRegister>(ws),
3093 static_cast<FRegister>(wt));
3094}
3095
3096void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3097 CHECK(HasMsa());
3098 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14),
3099 static_cast<FRegister>(wd),
3100 static_cast<FRegister>(ws),
3101 static_cast<FRegister>(wt));
3102}
3103
3104void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3105 CHECK(HasMsa());
3106 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14),
3107 static_cast<FRegister>(wd),
3108 static_cast<FRegister>(ws),
3109 static_cast<FRegister>(wt));
3110}
3111
3112void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3113 CHECK(HasMsa());
3114 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14),
3115 static_cast<FRegister>(wd),
3116 static_cast<FRegister>(ws),
3117 static_cast<FRegister>(wt));
3118}
3119
Lena Djokicb3d79e42017-07-25 11:20:52 +02003120void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3121 CHECK(HasMsa());
3122 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12),
3123 static_cast<FRegister>(wd),
3124 static_cast<FRegister>(ws),
3125 static_cast<FRegister>(wt));
3126}
3127
3128void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3129 CHECK(HasMsa());
3130 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12),
3131 static_cast<FRegister>(wd),
3132 static_cast<FRegister>(ws),
3133 static_cast<FRegister>(wt));
3134}
3135
3136void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3137 CHECK(HasMsa());
3138 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12),
3139 static_cast<FRegister>(wd),
3140 static_cast<FRegister>(ws),
3141 static_cast<FRegister>(wt));
3142}
3143
3144void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3145 CHECK(HasMsa());
3146 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12),
3147 static_cast<FRegister>(wd),
3148 static_cast<FRegister>(ws),
3149 static_cast<FRegister>(wt));
3150}
3151
3152void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3153 CHECK(HasMsa());
3154 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12),
3155 static_cast<FRegister>(wd),
3156 static_cast<FRegister>(ws),
3157 static_cast<FRegister>(wt));
3158}
3159
3160void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3161 CHECK(HasMsa());
3162 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12),
3163 static_cast<FRegister>(wd),
3164 static_cast<FRegister>(ws),
3165 static_cast<FRegister>(wt));
3166}
3167
3168void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3169 CHECK(HasMsa());
3170 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12),
3171 static_cast<FRegister>(wd),
3172 static_cast<FRegister>(ws),
3173 static_cast<FRegister>(wt));
3174}
3175
3176void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3177 CHECK(HasMsa());
3178 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12),
3179 static_cast<FRegister>(wd),
3180 static_cast<FRegister>(ws),
3181 static_cast<FRegister>(wt));
3182}
3183
Lena Djokic72aba712017-10-30 15:47:20 +01003184void MipsAssembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3185 CHECK(HasMsa());
3186 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11),
3187 static_cast<FRegister>(wd),
3188 static_cast<FRegister>(ws),
3189 static_cast<FRegister>(wt));
3190}
3191
3192void MipsAssembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3193 CHECK(HasMsa());
3194 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11),
3195 static_cast<FRegister>(wd),
3196 static_cast<FRegister>(ws),
3197 static_cast<FRegister>(wt));
3198}
3199
3200void MipsAssembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3201 CHECK(HasMsa());
3202 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11),
3203 static_cast<FRegister>(wd),
3204 static_cast<FRegister>(ws),
3205 static_cast<FRegister>(wt));
3206}
3207
3208void MipsAssembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3209 CHECK(HasMsa());
3210 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11),
3211 static_cast<FRegister>(wd),
3212 static_cast<FRegister>(ws),
3213 static_cast<FRegister>(wt));
3214}
3215
3216void MipsAssembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3217 CHECK(HasMsa());
3218 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11),
3219 static_cast<FRegister>(wd),
3220 static_cast<FRegister>(ws),
3221 static_cast<FRegister>(wt));
3222}
3223
3224void MipsAssembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3225 CHECK(HasMsa());
3226 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11),
3227 static_cast<FRegister>(wd),
3228 static_cast<FRegister>(ws),
3229 static_cast<FRegister>(wt));
3230}
3231
3232void MipsAssembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3233 CHECK(HasMsa());
3234 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11),
3235 static_cast<FRegister>(wd),
3236 static_cast<FRegister>(ws),
3237 static_cast<FRegister>(wt));
3238}
3239
3240void MipsAssembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3241 CHECK(HasMsa());
3242 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11),
3243 static_cast<FRegister>(wd),
3244 static_cast<FRegister>(ws),
3245 static_cast<FRegister>(wt));
3246}
3247
Lena Djokicb3d79e42017-07-25 11:20:52 +02003248void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3249 CHECK(HasMsa());
3250 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b),
3251 static_cast<FRegister>(wd),
3252 static_cast<FRegister>(ws),
3253 static_cast<FRegister>(wt));
3254}
3255
3256void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3257 CHECK(HasMsa());
3258 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b),
3259 static_cast<FRegister>(wd),
3260 static_cast<FRegister>(ws),
3261 static_cast<FRegister>(wt));
3262}
3263
3264void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3265 CHECK(HasMsa());
3266 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b),
3267 static_cast<FRegister>(wd),
3268 static_cast<FRegister>(ws),
3269 static_cast<FRegister>(wt));
3270}
3271
3272void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3273 CHECK(HasMsa());
3274 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b),
3275 static_cast<FRegister>(wd),
3276 static_cast<FRegister>(ws),
3277 static_cast<FRegister>(wt));
3278}
3279
Lena Djokic3309c012017-10-13 14:34:32 +02003280void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3281 CHECK(HasMsa());
3282 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15),
3283 static_cast<FRegister>(wd),
3284 static_cast<FRegister>(ws),
3285 static_cast<FRegister>(wt));
3286}
3287
3288void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3289 CHECK(HasMsa());
3290 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15),
3291 static_cast<FRegister>(wd),
3292 static_cast<FRegister>(ws),
3293 static_cast<FRegister>(wt));
3294}
3295
3296void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3297 CHECK(HasMsa());
3298 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15),
3299 static_cast<FRegister>(wd),
3300 static_cast<FRegister>(ws),
3301 static_cast<FRegister>(wt));
3302}
3303
3304void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3305 CHECK(HasMsa());
3306 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15),
3307 static_cast<FRegister>(wd),
3308 static_cast<FRegister>(ws),
3309 static_cast<FRegister>(wt));
3310}
3311
3312void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3313 CHECK(HasMsa());
3314 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15),
3315 static_cast<FRegister>(wd),
3316 static_cast<FRegister>(ws),
3317 static_cast<FRegister>(wt));
3318}
3319
3320void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3321 CHECK(HasMsa());
3322 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15),
3323 static_cast<FRegister>(wd),
3324 static_cast<FRegister>(ws),
3325 static_cast<FRegister>(wt));
3326}
3327
Lena Djokic51765b02017-06-22 13:49:59 +02003328void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
3329 FRegister src,
3330 bool is_double) {
3331 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
3332 if (is_double) {
3333 SplatiD(dst, static_cast<VectorRegister>(src), 0);
3334 } else {
3335 SplatiW(dst, static_cast<VectorRegister>(src), 0);
3336 }
3337}
3338
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003339void MipsAssembler::LoadConst32(Register rd, int32_t value) {
3340 if (IsUint<16>(value)) {
3341 // Use OR with (unsigned) immediate to encode 16b unsigned int.
3342 Ori(rd, ZERO, value);
3343 } else if (IsInt<16>(value)) {
3344 // Use ADD with (signed) immediate to encode 16b signed int.
3345 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07003346 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003347 Lui(rd, High16Bits(value));
3348 if (value & 0xFFFF)
3349 Ori(rd, rd, Low16Bits(value));
3350 }
3351}
3352
3353void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003354 uint32_t low = Low32Bits(value);
3355 uint32_t high = High32Bits(value);
3356 LoadConst32(reg_lo, low);
3357 if (high != low) {
3358 LoadConst32(reg_hi, high);
3359 } else {
3360 Move(reg_hi, reg_lo);
3361 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003362}
3363
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003364void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003365 if (value == 0) {
3366 temp = ZERO;
3367 } else {
3368 LoadConst32(temp, value);
3369 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003370 Mtc1(temp, r);
3371}
3372
3373void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003374 uint32_t low = Low32Bits(value);
3375 uint32_t high = High32Bits(value);
3376 if (low == 0) {
3377 Mtc1(ZERO, rd);
3378 } else {
3379 LoadConst32(temp, low);
3380 Mtc1(temp, rd);
3381 }
3382 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003383 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003384 } else {
3385 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003386 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003387 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003388}
3389
3390void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003391 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003392 if (IsInt<16>(value)) {
3393 Addiu(rt, rs, value);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003394 } else if (IsR6()) {
3395 int16_t high = High16Bits(value);
3396 int16_t low = Low16Bits(value);
3397 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
3398 if (low != 0) {
3399 Aui(temp, rs, high);
3400 Addiu(rt, temp, low);
3401 } else {
3402 Aui(rt, rs, high);
3403 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003404 } else {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003405 // Do not load the whole 32-bit `value` if it can be represented as
3406 // a sum of two 16-bit signed values. This can save an instruction.
3407 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
3408 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
3409 if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
3410 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
3411 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
3412 } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
3413 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
3414 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
3415 } else {
3416 // Now that all shorter options have been exhausted, load the full 32-bit value.
3417 LoadConst32(temp, value);
3418 Addu(rt, rs, temp);
3419 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003420 }
3421}
3422
3423void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
3424 MipsAssembler::Branch::Type short_type,
3425 MipsAssembler::Branch::Type long_type) {
3426 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
3427}
3428
Alexey Frunze96b66822016-09-10 02:32:44 -07003429void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003430 OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003431 if (is_r6) {
3432 // R6
Alexey Frunze96b66822016-09-10 02:32:44 -07003433 switch (initial_type) {
3434 case kLabel:
3435 CHECK(!IsResolved());
3436 type_ = kR6Label;
3437 break;
3438 case kLiteral:
3439 CHECK(!IsResolved());
3440 type_ = kR6Literal;
3441 break;
3442 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003443 InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07003444 break;
3445 case kCondBranch:
3446 switch (condition_) {
3447 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003448 InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003449 break;
3450 case kCondEQZ:
3451 case kCondNEZ:
3452 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
Alexey Frunze0cab6562017-07-25 15:19:36 -07003453 type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
Alexey Frunze96b66822016-09-10 02:32:44 -07003454 break;
3455 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003456 InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003457 break;
3458 }
3459 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003460 case kBareCall:
3461 type_ = kR6BareCall;
3462 CHECK_LE(offset_size_needed, GetOffsetSize());
3463 break;
3464 case kBareCondBranch:
3465 type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch;
3466 CHECK_LE(offset_size_needed, GetOffsetSize());
3467 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003468 default:
3469 LOG(FATAL) << "Unexpected branch type " << initial_type;
3470 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003471 }
3472 } else {
3473 // R2
Alexey Frunze96b66822016-09-10 02:32:44 -07003474 switch (initial_type) {
3475 case kLabel:
3476 CHECK(!IsResolved());
3477 type_ = kLabel;
3478 break;
3479 case kLiteral:
3480 CHECK(!IsResolved());
3481 type_ = kLiteral;
3482 break;
3483 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003484 InitShortOrLong(offset_size_needed, kCall, kLongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07003485 break;
3486 case kCondBranch:
3487 switch (condition_) {
3488 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003489 InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003490 break;
3491 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003492 InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003493 break;
3494 }
3495 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003496 case kBareCall:
3497 type_ = kBareCall;
3498 CHECK_LE(offset_size_needed, GetOffsetSize());
3499 break;
3500 case kBareCondBranch:
3501 type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
3502 CHECK_LE(offset_size_needed, GetOffsetSize());
3503 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003504 default:
3505 LOG(FATAL) << "Unexpected branch type " << initial_type;
3506 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003507 }
3508 }
3509 old_type_ = type_;
3510}
3511
3512bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
3513 switch (condition) {
3514 case kCondLT:
3515 case kCondGT:
3516 case kCondNE:
3517 case kCondLTU:
3518 return lhs == rhs;
3519 default:
3520 return false;
3521 }
3522}
3523
3524bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
3525 switch (condition) {
3526 case kUncond:
3527 return true;
3528 case kCondGE:
3529 case kCondLE:
3530 case kCondEQ:
3531 case kCondGEU:
3532 return lhs == rhs;
3533 default:
3534 return false;
3535 }
3536}
3537
Alexey Frunze0cab6562017-07-25 15:19:36 -07003538MipsAssembler::Branch::Branch(bool is_r6,
3539 uint32_t location,
3540 uint32_t target,
3541 bool is_call,
3542 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003543 : old_location_(location),
3544 location_(location),
3545 target_(target),
3546 lhs_reg_(0),
3547 rhs_reg_(0),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003548 condition_(kUncond),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003549 delayed_instruction_(kUnfilledDelaySlot),
3550 patcher_label_(nullptr) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003551 InitializeType(
3552 (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
3553 is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003554}
3555
3556MipsAssembler::Branch::Branch(bool is_r6,
3557 uint32_t location,
3558 uint32_t target,
3559 MipsAssembler::BranchCondition condition,
3560 Register lhs_reg,
Alexey Frunze0cab6562017-07-25 15:19:36 -07003561 Register rhs_reg,
3562 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003563 : old_location_(location),
3564 location_(location),
3565 target_(target),
3566 lhs_reg_(lhs_reg),
3567 rhs_reg_(rhs_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003568 condition_(condition),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003569 delayed_instruction_(kUnfilledDelaySlot),
3570 patcher_label_(nullptr) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003571 CHECK_NE(condition, kUncond);
3572 switch (condition) {
3573 case kCondLT:
3574 case kCondGE:
3575 case kCondLE:
3576 case kCondGT:
3577 case kCondLTU:
3578 case kCondGEU:
3579 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3580 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3581 // We leave this up to the caller.
3582 CHECK(is_r6);
3583 FALLTHROUGH_INTENDED;
3584 case kCondEQ:
3585 case kCondNE:
3586 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3587 // To compare with 0, use dedicated kCond*Z conditions.
3588 CHECK_NE(lhs_reg, ZERO);
3589 CHECK_NE(rhs_reg, ZERO);
3590 break;
3591 case kCondLTZ:
3592 case kCondGEZ:
3593 case kCondLEZ:
3594 case kCondGTZ:
3595 case kCondEQZ:
3596 case kCondNEZ:
3597 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3598 CHECK_NE(lhs_reg, ZERO);
3599 CHECK_EQ(rhs_reg, ZERO);
3600 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003601 case kCondF:
3602 case kCondT:
3603 CHECK_EQ(rhs_reg, ZERO);
3604 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003605 case kUncond:
3606 UNREACHABLE();
3607 }
3608 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
3609 if (IsUncond(condition, lhs_reg, rhs_reg)) {
3610 // Branch condition is always true, make the branch unconditional.
3611 condition_ = kUncond;
3612 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07003613 InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003614}
3615
Alexey Frunze96b66822016-09-10 02:32:44 -07003616MipsAssembler::Branch::Branch(bool is_r6,
3617 uint32_t location,
3618 Register dest_reg,
3619 Register base_reg,
3620 Type label_or_literal_type)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003621 : old_location_(location),
3622 location_(location),
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003623 target_(kUnresolved),
3624 lhs_reg_(dest_reg),
3625 rhs_reg_(base_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003626 condition_(kUncond),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003627 delayed_instruction_(kUnfilledDelaySlot),
3628 patcher_label_(nullptr) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003629 CHECK_NE(dest_reg, ZERO);
3630 if (is_r6) {
3631 CHECK_EQ(base_reg, ZERO);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003632 }
Alexey Frunze96b66822016-09-10 02:32:44 -07003633 InitializeType(label_or_literal_type, is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003634}
3635
3636MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
3637 MipsAssembler::BranchCondition cond) {
3638 switch (cond) {
3639 case kCondLT:
3640 return kCondGE;
3641 case kCondGE:
3642 return kCondLT;
3643 case kCondLE:
3644 return kCondGT;
3645 case kCondGT:
3646 return kCondLE;
3647 case kCondLTZ:
3648 return kCondGEZ;
3649 case kCondGEZ:
3650 return kCondLTZ;
3651 case kCondLEZ:
3652 return kCondGTZ;
3653 case kCondGTZ:
3654 return kCondLEZ;
3655 case kCondEQ:
3656 return kCondNE;
3657 case kCondNE:
3658 return kCondEQ;
3659 case kCondEQZ:
3660 return kCondNEZ;
3661 case kCondNEZ:
3662 return kCondEQZ;
3663 case kCondLTU:
3664 return kCondGEU;
3665 case kCondGEU:
3666 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003667 case kCondF:
3668 return kCondT;
3669 case kCondT:
3670 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003671 case kUncond:
3672 LOG(FATAL) << "Unexpected branch condition " << cond;
3673 }
3674 UNREACHABLE();
3675}
3676
3677MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
3678 return type_;
3679}
3680
3681MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
3682 return condition_;
3683}
3684
3685Register MipsAssembler::Branch::GetLeftRegister() const {
3686 return static_cast<Register>(lhs_reg_);
3687}
3688
3689Register MipsAssembler::Branch::GetRightRegister() const {
3690 return static_cast<Register>(rhs_reg_);
3691}
3692
3693uint32_t MipsAssembler::Branch::GetTarget() const {
3694 return target_;
3695}
3696
3697uint32_t MipsAssembler::Branch::GetLocation() const {
3698 return location_;
3699}
3700
3701uint32_t MipsAssembler::Branch::GetOldLocation() const {
3702 return old_location_;
3703}
3704
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003705uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const {
3706 // Short branches with delay slots always consist of two instructions, the branch
3707 // and the delay slot, irrespective of whether the delay slot is filled with a
3708 // useful instruction or not.
3709 // Long composite branches may have a length longer by one instruction than
3710 // specified in branch_info_[].length. This happens when an instruction is taken
3711 // to fill the short branch delay slot, but the branch eventually becomes long
3712 // and formally has no delay slot to fill. This instruction is placed at the
3713 // beginning of the long composite branch and this needs to be accounted for in
3714 // the branch length and the location of the offset encoded in the branch.
3715 switch (type) {
3716 case kLongUncondBranch:
3717 case kLongCondBranch:
3718 case kLongCall:
3719 case kR6LongCondBranch:
3720 return (delayed_instruction_ != kUnfilledDelaySlot &&
3721 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0;
3722 default:
3723 return 0;
3724 }
3725}
3726
3727uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const {
3728 return GetPrecedingInstructionLength(type) * sizeof(uint32_t);
3729}
3730
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003731uint32_t MipsAssembler::Branch::GetLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003732 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003733}
3734
3735uint32_t MipsAssembler::Branch::GetOldLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003736 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003737}
3738
3739uint32_t MipsAssembler::Branch::GetSize() const {
3740 return GetLength() * sizeof(uint32_t);
3741}
3742
3743uint32_t MipsAssembler::Branch::GetOldSize() const {
3744 return GetOldLength() * sizeof(uint32_t);
3745}
3746
3747uint32_t MipsAssembler::Branch::GetEndLocation() const {
3748 return GetLocation() + GetSize();
3749}
3750
3751uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
3752 return GetOldLocation() + GetOldSize();
3753}
3754
Alexey Frunze0cab6562017-07-25 15:19:36 -07003755bool MipsAssembler::Branch::IsBare() const {
3756 switch (type_) {
3757 // R2 short branches (can't be promoted to long), delay slots filled manually.
3758 case kBareUncondBranch:
3759 case kBareCondBranch:
3760 case kBareCall:
3761 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3762 case kR6BareUncondBranch:
3763 case kR6BareCondBranch:
3764 case kR6BareCall:
3765 return true;
3766 default:
3767 return false;
3768 }
3769}
3770
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003771bool MipsAssembler::Branch::IsLong() const {
3772 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003773 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003774 case kUncondBranch:
3775 case kCondBranch:
3776 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003777 // R2 short branches (can't be promoted to long), delay slots filled manually.
3778 case kBareUncondBranch:
3779 case kBareCondBranch:
3780 case kBareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003781 // R2 near label.
3782 case kLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003783 // R2 near literal.
3784 case kLiteral:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003785 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003786 case kR6UncondBranch:
3787 case kR6CondBranch:
3788 case kR6Call:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003789 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3790 case kR6BareUncondBranch:
3791 case kR6BareCondBranch:
3792 case kR6BareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003793 // R6 near label.
3794 case kR6Label:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003795 // R6 near literal.
3796 case kR6Literal:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003797 return false;
3798 // R2 long branches.
3799 case kLongUncondBranch:
3800 case kLongCondBranch:
3801 case kLongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003802 // R2 far label.
3803 case kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003804 // R2 far literal.
3805 case kFarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003806 // R6 long branches.
3807 case kR6LongUncondBranch:
3808 case kR6LongCondBranch:
3809 case kR6LongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003810 // R6 far label.
3811 case kR6FarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003812 // R6 far literal.
3813 case kR6FarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003814 return true;
3815 }
3816 UNREACHABLE();
3817}
3818
3819bool MipsAssembler::Branch::IsResolved() const {
3820 return target_ != kUnresolved;
3821}
3822
3823MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003824 bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003825 OffsetBits offset_size =
Alexey Frunze0cab6562017-07-25 15:19:36 -07003826 (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003827 ? kOffset23
3828 : branch_info_[type_].offset_size;
3829 return offset_size;
3830}
3831
3832MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
3833 uint32_t target) {
3834 // For unresolved targets assume the shortest encoding
3835 // (later it will be made longer if needed).
3836 if (target == kUnresolved)
3837 return kOffset16;
3838 int64_t distance = static_cast<int64_t>(target) - location;
3839 // To simplify calculations in composite branches consisting of multiple instructions
3840 // bump up the distance by a value larger than the max byte size of a composite branch.
3841 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
3842 if (IsInt<kOffset16>(distance))
3843 return kOffset16;
3844 else if (IsInt<kOffset18>(distance))
3845 return kOffset18;
3846 else if (IsInt<kOffset21>(distance))
3847 return kOffset21;
3848 else if (IsInt<kOffset23>(distance))
3849 return kOffset23;
3850 else if (IsInt<kOffset28>(distance))
3851 return kOffset28;
3852 return kOffset32;
3853}
3854
3855void MipsAssembler::Branch::Resolve(uint32_t target) {
3856 target_ = target;
3857}
3858
3859void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
3860 if (location_ > expand_location) {
3861 location_ += delta;
3862 }
3863 if (!IsResolved()) {
3864 return; // Don't know the target yet.
3865 }
3866 if (target_ > expand_location) {
3867 target_ += delta;
3868 }
3869}
3870
3871void MipsAssembler::Branch::PromoteToLong() {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003872 CHECK(!IsBare()); // Bare branches do not promote.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003873 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003874 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003875 case kUncondBranch:
3876 type_ = kLongUncondBranch;
3877 break;
3878 case kCondBranch:
3879 type_ = kLongCondBranch;
3880 break;
3881 case kCall:
3882 type_ = kLongCall;
3883 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003884 // R2 near label.
3885 case kLabel:
3886 type_ = kFarLabel;
3887 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003888 // R2 near literal.
3889 case kLiteral:
3890 type_ = kFarLiteral;
3891 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003892 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003893 case kR6UncondBranch:
3894 type_ = kR6LongUncondBranch;
3895 break;
3896 case kR6CondBranch:
3897 type_ = kR6LongCondBranch;
3898 break;
3899 case kR6Call:
3900 type_ = kR6LongCall;
3901 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003902 // R6 near label.
3903 case kR6Label:
3904 type_ = kR6FarLabel;
3905 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003906 // R6 near literal.
3907 case kR6Literal:
3908 type_ = kR6FarLiteral;
3909 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003910 default:
3911 // Note: 'type_' is already long.
3912 break;
3913 }
3914 CHECK(IsLong());
3915}
3916
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003917uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
3918 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003919 case Branch::kLabel:
3920 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003921 case Branch::kLiteral:
3922 case Branch::kFarLiteral:
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003923 if (branch->GetRightRegister() != ZERO) {
3924 return GetLabelLocation(&pc_rel_base_label_);
3925 }
3926 // For those label/literal loads which come with their own NAL instruction
3927 // and don't depend on `pc_rel_base_label_` we can simply use the location
3928 // of the "branch" (the NAL precedes the "branch" immediately). The location
3929 // is close enough for the user of the returned location, PromoteIfNeeded(),
3930 // to not miss needed promotion to a far load.
3931 // (GetOffsetSizeNeeded() provides a little leeway by means of kMaxBranchSize,
3932 // which is larger than all composite branches and label/literal loads: it's
3933 // OK to promote a bit earlier than strictly necessary, it makes things
3934 // simpler.)
3935 FALLTHROUGH_INTENDED;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003936 default:
3937 return branch->GetLocation();
3938 }
3939}
3940
3941uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003942 // `location` comes from GetBranchLocationOrPcRelBase() and is either the location
3943 // of the PC-relative branch or (for some R2 label and literal loads) the location
3944 // of `pc_rel_base_label_`. The PC-relative offset of the branch/load is relative
3945 // to this location.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003946 // If the branch is still unresolved or already long, nothing to do.
3947 if (IsLong() || !IsResolved()) {
3948 return 0;
3949 }
3950 // Promote the short branch to long if the offset size is too small
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003951 // to hold the distance between location and target_.
3952 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003953 PromoteToLong();
3954 uint32_t old_size = GetOldSize();
3955 uint32_t new_size = GetSize();
3956 CHECK_GT(new_size, old_size);
3957 return new_size - old_size;
3958 }
3959 // The following logic is for debugging/testing purposes.
3960 // Promote some short branches to long when it's not really required.
Alexey Frunze0cab6562017-07-25 15:19:36 -07003961 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003962 int64_t distance = static_cast<int64_t>(target_) - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003963 distance = (distance >= 0) ? distance : -distance;
3964 if (distance >= max_short_distance) {
3965 PromoteToLong();
3966 uint32_t old_size = GetOldSize();
3967 uint32_t new_size = GetSize();
3968 CHECK_GT(new_size, old_size);
3969 return new_size - old_size;
3970 }
3971 }
3972 return 0;
3973}
3974
3975uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003976 return location_ + GetPrecedingInstructionSize(type_) +
3977 branch_info_[type_].instr_offset * sizeof(uint32_t);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003978}
3979
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003980uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
3981 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003982 case Branch::kLabel:
3983 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003984 case Branch::kLiteral:
3985 case Branch::kFarLiteral:
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003986 if (branch->GetRightRegister() == ZERO) {
3987 // These loads don't use `pc_rel_base_label_` and instead rely on their own
3988 // NAL instruction (it immediately precedes the "branch"). Therefore the
3989 // effective PC-relative base register is RA and it corresponds to the 2nd
3990 // instruction after the NAL.
3991 return branch->GetLocation() + sizeof(uint32_t);
3992 } else {
3993 return GetLabelLocation(&pc_rel_base_label_);
3994 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003995 default:
3996 return branch->GetOffsetLocation() +
3997 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
3998 }
3999}
4000
4001uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004002 // `location` comes from GetBranchOrPcRelBaseForEncoding() and is either a location
4003 // within/near the PC-relative branch or (for some R2 label and literal loads) the
4004 // location of `pc_rel_base_label_`. The PC-relative offset of the branch/load is
4005 // relative to this location.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004006 CHECK(IsResolved());
4007 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
4008 // Calculate the byte distance between instructions and also account for
4009 // different PC-relative origins.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004010 uint32_t offset = target_ - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004011 // Prepare the offset for encoding into the instruction(s).
4012 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
4013 return offset;
4014}
4015
4016MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
4017 CHECK_LT(branch_id, branches_.size());
4018 return &branches_[branch_id];
4019}
4020
4021const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
4022 CHECK_LT(branch_id, branches_.size());
4023 return &branches_[branch_id];
4024}
4025
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004026void MipsAssembler::BindRelativeToPrecedingBranch(MipsLabel* label,
4027 uint32_t prev_branch_id_plus_one,
4028 uint32_t position) {
4029 if (prev_branch_id_plus_one != 0) {
4030 const Branch* branch = GetBranch(prev_branch_id_plus_one - 1);
4031 position -= branch->GetEndLocation();
4032 }
4033 label->prev_branch_id_plus_one_ = prev_branch_id_plus_one;
4034 label->BindTo(position);
4035}
4036
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004037void MipsAssembler::Bind(MipsLabel* label) {
4038 CHECK(!label->IsBound());
4039 uint32_t bound_pc = buffer_.Size();
4040
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004041 // Make the delay slot FSM aware of the new label.
4042 DsFsmLabel();
4043
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004044 // Walk the list of branches referring to and preceding this label.
4045 // Store the previously unknown target addresses in them.
4046 while (label->IsLinked()) {
4047 uint32_t branch_id = label->Position();
4048 Branch* branch = GetBranch(branch_id);
4049 branch->Resolve(bound_pc);
4050
4051 uint32_t branch_location = branch->GetLocation();
4052 // Extract the location of the previous branch in the list (walking the list backwards;
4053 // the previous branch ID was stored in the space reserved for this branch).
4054 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
4055
4056 // On to the previous branch in the list...
4057 label->position_ = prev;
4058 }
4059
4060 // Now make the label object contain its own location (relative to the end of the preceding
4061 // branch, if any; it will be used by the branches referring to and following this label).
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004062 BindRelativeToPrecedingBranch(label, branches_.size(), bound_pc);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004063}
4064
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004065uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004066 CHECK(label->IsBound());
4067 uint32_t target = label->Position();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004068 if (label->prev_branch_id_plus_one_ != 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004069 // Get label location based on the branch preceding it.
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004070 const Branch* branch = GetBranch(label->prev_branch_id_plus_one_ - 1);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004071 target += branch->GetEndLocation();
4072 }
4073 return target;
4074}
4075
4076uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
4077 // We can reconstruct the adjustment by going through all the branches from the beginning
4078 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
4079 // with increasing old_position, we can use the data from last AdjustedPosition() to
4080 // continue where we left off and the whole loop should be O(m+n) where m is the number
4081 // of positions to adjust and n is the number of branches.
4082 if (old_position < last_old_position_) {
4083 last_position_adjustment_ = 0;
4084 last_old_position_ = 0;
4085 last_branch_id_ = 0;
4086 }
4087 while (last_branch_id_ != branches_.size()) {
4088 const Branch* branch = GetBranch(last_branch_id_);
4089 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
4090 break;
4091 }
4092 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
4093 ++last_branch_id_;
4094 }
4095 last_old_position_ = old_position;
4096 return old_position + last_position_adjustment_;
4097}
4098
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004099void MipsAssembler::BindPcRelBaseLabel() {
4100 Bind(&pc_rel_base_label_);
4101}
4102
Alexey Frunze06a46c42016-07-19 15:00:40 -07004103uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const {
4104 return GetLabelLocation(&pc_rel_base_label_);
4105}
4106
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004107void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
4108 uint32_t length = branches_.back().GetLength();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004109 // Commit the last branch target label (if any).
4110 DsFsmCommitLabel();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004111 if (!label->IsBound()) {
4112 // Branch forward (to a following label), distance is unknown.
4113 // The first branch forward will contain 0, serving as the terminator of
4114 // the list of forward-reaching branches.
4115 Emit(label->position_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004116 // Nothing for the delay slot (yet).
4117 DsFsmInstrNop(0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004118 length--;
4119 // Now make the label object point to this branch
4120 // (this forms a linked list of branches preceding this label).
4121 uint32_t branch_id = branches_.size() - 1;
4122 label->LinkTo(branch_id);
4123 }
4124 // Reserve space for the branch.
4125 while (length--) {
4126 Nop();
4127 }
4128}
4129
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004130bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const {
4131 if (delay_slot.instruction_ == 0) {
4132 // NOP or no instruction for the delay slot.
4133 return false;
4134 }
4135 switch (type_) {
4136 // R2 unconditional branches.
4137 case kUncondBranch:
4138 case kLongUncondBranch:
4139 // There are no register interdependencies.
4140 return true;
4141
4142 // R2 calls.
4143 case kCall:
4144 case kLongCall:
4145 // Instructions depending on or modifying RA should not be moved into delay slots
4146 // of branches modifying RA.
4147 return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0;
4148
4149 // R2 conditional branches.
4150 case kCondBranch:
4151 case kLongCondBranch:
4152 switch (condition_) {
4153 // Branches with one GPR source.
4154 case kCondLTZ:
4155 case kCondGEZ:
4156 case kCondLEZ:
4157 case kCondGTZ:
4158 case kCondEQZ:
4159 case kCondNEZ:
4160 return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0;
4161
4162 // Branches with two GPR sources.
4163 case kCondEQ:
4164 case kCondNE:
4165 return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
4166
4167 // Branches with one FPU condition code source.
4168 case kCondF:
4169 case kCondT:
4170 return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0;
4171
4172 default:
4173 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
4174 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
4175 LOG(FATAL) << "Unexpected branch condition " << condition_;
4176 UNREACHABLE();
4177 }
4178
4179 // R6 unconditional branches.
4180 case kR6UncondBranch:
4181 case kR6LongUncondBranch:
4182 // R6 calls.
4183 case kR6Call:
4184 case kR6LongCall:
4185 // There are no delay slots.
4186 return false;
4187
4188 // R6 conditional branches.
4189 case kR6CondBranch:
4190 case kR6LongCondBranch:
4191 switch (condition_) {
4192 // Branches with one FPU register source.
4193 case kCondF:
4194 case kCondT:
4195 return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0;
4196 // Others have a forbidden slot instead of a delay slot.
4197 default:
4198 return false;
4199 }
4200
4201 // Literals.
4202 default:
4203 LOG(FATAL) << "Unexpected branch type " << type_;
4204 UNREACHABLE();
4205 }
4206}
4207
4208uint32_t MipsAssembler::Branch::GetDelayedInstruction() const {
4209 return delayed_instruction_;
4210}
4211
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004212MipsLabel* MipsAssembler::Branch::GetPatcherLabel() const {
4213 return patcher_label_;
4214}
4215
4216void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction, MipsLabel* patcher_label) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004217 CHECK_NE(instruction, kUnfilledDelaySlot);
4218 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot);
4219 delayed_instruction_ = instruction;
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004220 patcher_label_ = patcher_label;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004221}
4222
4223void MipsAssembler::Branch::DecrementLocations() {
4224 // We first create a branch object, which gets its type and locations initialized,
4225 // and then we check if the branch can actually have the preceding instruction moved
4226 // into its delay slot. If it can, the branch locations need to be decremented.
4227 //
4228 // We could make the check before creating the branch object and avoid the location
4229 // adjustment, but the check is cleaner when performed on an initialized branch
4230 // object.
4231 //
4232 // If the branch is backwards (to a previously bound label), reducing the locations
4233 // cannot cause a short branch to exceed its offset range because the offset reduces.
4234 // And this is not at all a problem for a long branch backwards.
4235 //
4236 // If the branch is forward (not linked to any label yet), reducing the locations
4237 // is harmless. The branch will be promoted to long if needed when the target is known.
4238 CHECK_EQ(location_, old_location_);
4239 CHECK_GE(old_location_, sizeof(uint32_t));
4240 old_location_ -= sizeof(uint32_t);
4241 location_ = old_location_;
4242}
4243
4244void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004245 if (branch.IsBare()) {
4246 // Delay slots are filled manually in bare branches.
4247 return;
4248 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004249 if (branch.CanHaveDelayedInstruction(delay_slot_)) {
4250 // The last instruction cannot be used in a different delay slot,
4251 // do not commit the label before it (if any).
4252 DsFsmDropLabel();
4253 // Remove the last emitted instruction.
4254 size_t size = buffer_.Size();
4255 CHECK_GE(size, sizeof(uint32_t));
4256 size -= sizeof(uint32_t);
4257 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_);
4258 buffer_.Resize(size);
4259 // Attach it to the branch and adjust the branch locations.
4260 branch.DecrementLocations();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004261 branch.SetDelayedInstruction(delay_slot_.instruction_, delay_slot_.patcher_label_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004262 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) {
4263 // If reordefing is disabled, prevent absorption of the target instruction.
4264 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot);
4265 }
4266}
4267
Alexey Frunze0cab6562017-07-25 15:19:36 -07004268void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004269 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004270 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ false, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004271 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004272 FinalizeLabeledBranch(label);
4273}
4274
Alexey Frunze0cab6562017-07-25 15:19:36 -07004275void MipsAssembler::Bcond(MipsLabel* label,
4276 bool is_r6,
4277 bool is_bare,
4278 BranchCondition condition,
4279 Register lhs,
4280 Register rhs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004281 // If lhs = rhs, this can be a NOP.
4282 if (Branch::IsNop(condition, lhs, rhs)) {
4283 return;
4284 }
4285 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004286 branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004287 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004288 FinalizeLabeledBranch(label);
4289}
4290
Alexey Frunze0cab6562017-07-25 15:19:36 -07004291void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004292 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004293 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ true, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004294 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004295 FinalizeLabeledBranch(label);
4296}
4297
Alexey Frunze96b66822016-09-10 02:32:44 -07004298void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
4299 // Label address loads are treated as pseudo branches since they require very similar handling.
4300 DCHECK(!label->IsBound());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004301 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
4302 // may generate an individual NAL instruction to simulate PC-relative addressing on R2
4303 // by specifying `base_reg` of `ZERO`. Check for it.
4304 if (base_reg == ZERO && !IsR6()) {
4305 Nal();
4306 }
Alexey Frunze96b66822016-09-10 02:32:44 -07004307 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
4308 FinalizeLabeledBranch(label);
4309}
4310
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004311Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
4312 DCHECK(size == 4u || size == 8u) << size;
4313 literals_.emplace_back(size, data);
4314 return &literals_.back();
4315}
4316
4317void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) {
4318 // Literal loads are treated as pseudo branches since they require very similar handling.
4319 DCHECK_EQ(literal->GetSize(), 4u);
4320 MipsLabel* label = literal->GetLabel();
4321 DCHECK(!label->IsBound());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004322 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
4323 // may generate an individual NAL instruction to simulate PC-relative addressing on R2
4324 // by specifying `base_reg` of `ZERO`. Check for it.
4325 if (base_reg == ZERO && !IsR6()) {
4326 Nal();
4327 }
Alexey Frunze96b66822016-09-10 02:32:44 -07004328 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004329 FinalizeLabeledBranch(label);
4330}
4331
Alexey Frunze96b66822016-09-10 02:32:44 -07004332JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
4333 jump_tables_.emplace_back(std::move(labels));
4334 JumpTable* table = &jump_tables_.back();
4335 DCHECK(!table->GetLabel()->IsBound());
4336 return table;
4337}
4338
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004339void MipsAssembler::EmitLiterals() {
4340 if (!literals_.empty()) {
4341 // We don't support byte and half-word literals.
4342 // TODO: proper alignment for 64-bit literals when they're implemented.
4343 for (Literal& literal : literals_) {
4344 MipsLabel* label = literal.GetLabel();
4345 Bind(label);
4346 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
4347 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
4348 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
4349 buffer_.Emit<uint8_t>(literal.GetData()[i]);
4350 }
4351 }
4352 }
4353}
4354
Alexey Frunze96b66822016-09-10 02:32:44 -07004355void MipsAssembler::ReserveJumpTableSpace() {
4356 if (!jump_tables_.empty()) {
4357 for (JumpTable& table : jump_tables_) {
4358 MipsLabel* label = table.GetLabel();
4359 Bind(label);
4360
4361 // Bulk ensure capacity, as this may be large.
4362 size_t orig_size = buffer_.Size();
4363 size_t required_capacity = orig_size + table.GetSize();
4364 if (required_capacity > buffer_.Capacity()) {
4365 buffer_.ExtendCapacity(required_capacity);
4366 }
4367#ifndef NDEBUG
4368 buffer_.has_ensured_capacity_ = true;
4369#endif
4370
4371 // Fill the space with dummy data as the data is not final
4372 // until the branches have been promoted. And we shouldn't
4373 // be moving uninitialized data during branch promotion.
4374 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
4375 buffer_.Emit<uint32_t>(0x1abe1234u);
4376 }
4377
4378#ifndef NDEBUG
4379 buffer_.has_ensured_capacity_ = false;
4380#endif
4381 }
4382 }
4383}
4384
4385void MipsAssembler::EmitJumpTables() {
4386 if (!jump_tables_.empty()) {
4387 CHECK(!overwriting_);
4388 // Switch from appending instructions at the end of the buffer to overwriting
4389 // existing instructions (here, jump tables) in the buffer.
4390 overwriting_ = true;
4391
4392 for (JumpTable& table : jump_tables_) {
4393 MipsLabel* table_label = table.GetLabel();
4394 uint32_t start = GetLabelLocation(table_label);
4395 overwrite_location_ = start;
4396
4397 for (MipsLabel* target : table.GetData()) {
4398 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
4399 // The table will contain target addresses relative to the table start.
4400 uint32_t offset = GetLabelLocation(target) - start;
4401 Emit(offset);
4402 }
4403 }
4404
4405 overwriting_ = false;
4406 }
4407}
4408
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004409void MipsAssembler::PromoteBranches() {
4410 // Promote short branches to long as necessary.
4411 bool changed;
4412 do {
4413 changed = false;
4414 for (auto& branch : branches_) {
4415 CHECK(branch.IsResolved());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004416 uint32_t base = GetBranchLocationOrPcRelBase(&branch);
4417 uint32_t delta = branch.PromoteIfNeeded(base);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004418 // If this branch has been promoted and needs to expand in size,
4419 // relocate all branches by the expansion size.
4420 if (delta) {
4421 changed = true;
4422 uint32_t expand_location = branch.GetLocation();
4423 for (auto& branch2 : branches_) {
4424 branch2.Relocate(expand_location, delta);
4425 }
4426 }
4427 }
4428 } while (changed);
4429
4430 // Account for branch expansion by resizing the code buffer
4431 // and moving the code in it to its final location.
4432 size_t branch_count = branches_.size();
4433 if (branch_count > 0) {
4434 // Resize.
4435 Branch& last_branch = branches_[branch_count - 1];
4436 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
4437 uint32_t old_size = buffer_.Size();
4438 buffer_.Resize(old_size + size_delta);
4439 // Move the code residing between branch placeholders.
4440 uint32_t end = old_size;
4441 for (size_t i = branch_count; i > 0; ) {
4442 Branch& branch = branches_[--i];
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004443 CHECK_GE(end, branch.GetOldEndLocation());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004444 uint32_t size = end - branch.GetOldEndLocation();
4445 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
4446 end = branch.GetOldLocation();
4447 }
4448 }
4449}
4450
4451// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
4452const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004453 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004454 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
4455 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004456 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall
Alexey Frunze0cab6562017-07-25 15:19:36 -07004457 // R2 short branches (can't be promoted to long), delay slots filled manually.
4458 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch
4459 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch
4460 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004461 // R2 near label.
4462 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004463 // R2 near literal.
4464 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004465 // R2 long branches.
4466 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
4467 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
4468 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004469 // R2 far label.
4470 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004471 // R2 far literal.
4472 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral
Alexey Frunze0cab6562017-07-25 15:19:36 -07004473 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004474 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
4475 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
4476 // Exception: kOffset23 for beqzc/bnezc.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004477 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call
Alexey Frunze0cab6562017-07-25 15:19:36 -07004478 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
4479 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch
4480 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch
4481 // Exception: kOffset23 for beqzc/bnezc.
4482 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004483 // R6 near label.
4484 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004485 // R6 near literal.
4486 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004487 // R6 long branches.
4488 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
4489 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004490 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004491 // R6 far label.
4492 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004493 // R6 far literal.
4494 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004495};
4496
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004497static inline bool IsAbsorbableInstruction(uint32_t instruction) {
4498 // The relative patcher patches addiu, lw and sw with an immediate operand of 0x5678.
4499 // We want to make sure that these instructions do not get absorbed into delay slots
4500 // of unconditional branches on R2. Absorption would otherwise make copies of
4501 // unpatched instructions.
4502 if ((instruction & 0xFFFF) != 0x5678) {
4503 return true;
4504 }
4505 switch (instruction >> kOpcodeShift) {
4506 case 0x09: // Addiu.
4507 case 0x23: // Lw.
4508 case 0x2B: // Sw.
4509 return false;
4510 default:
4511 return true;
4512 }
4513}
4514
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004515static inline Register GetR2PcRelBaseRegister(Register reg) {
4516 // LoadLabelAddress() and LoadLiteral() generate individual NAL
4517 // instructions on R2 when the specified base register is ZERO
4518 // and so the effective PC-relative base register is RA, not ZERO.
4519 return (reg == ZERO) ? RA : reg;
4520}
4521
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004522// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004523void MipsAssembler::EmitBranch(uint32_t branch_id) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004524 CHECK_EQ(overwriting_, true);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004525 Branch* branch = GetBranch(branch_id);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004526 overwrite_location_ = branch->GetLocation();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004527 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004528 BranchCondition condition = branch->GetCondition();
4529 Register lhs = branch->GetLeftRegister();
4530 Register rhs = branch->GetRightRegister();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004531 uint32_t delayed_instruction = branch->GetDelayedInstruction();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004532 MipsLabel* patcher_label = branch->GetPatcherLabel();
4533 if (patcher_label != nullptr) {
4534 // Update the patcher label location to account for branch promotion and
4535 // delay slot filling.
4536 CHECK(patcher_label->IsBound());
4537 uint32_t bound_pc = branch->GetLocation();
4538 if (!branch->IsLong()) {
4539 // Short branches precede delay slots.
4540 // Long branches follow "delay slots".
4541 bound_pc += sizeof(uint32_t);
4542 }
4543 // Rebind the label.
4544 patcher_label->Reinitialize();
4545 BindRelativeToPrecedingBranch(patcher_label, branch_id, bound_pc);
4546 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004547 switch (branch->GetType()) {
4548 // R2 short branches.
4549 case Branch::kUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004550 if (delayed_instruction == Branch::kUnfillableDelaySlot) {
4551 // The branch was created when reordering was disabled, do not absorb the target
4552 // instruction.
4553 delayed_instruction = 0; // NOP.
4554 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4555 // Try to absorb the target instruction into the delay slot.
4556 delayed_instruction = 0; // NOP.
4557 // Incrementing the signed 16-bit offset past the target instruction must not
4558 // cause overflow into the negative subrange, check for the max offset.
4559 if (offset != 0x7FFF) {
4560 uint32_t target = branch->GetTarget();
4561 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004562 uint32_t target_instruction = buffer_.Load<uint32_t>(target);
4563 if (IsAbsorbableInstruction(target_instruction)) {
4564 delayed_instruction = target_instruction;
4565 offset++;
4566 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004567 }
4568 }
4569 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004570 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4571 B(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004572 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004573 break;
4574 case Branch::kCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004575 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4576 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4577 delayed_instruction = 0; // NOP.
4578 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004579 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004580 EmitBcondR2(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004581 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004582 break;
4583 case Branch::kCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004584 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4585 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4586 delayed_instruction = 0; // NOP.
4587 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004588 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004589 Bal(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004590 Emit(delayed_instruction);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004591 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004592 case Branch::kBareUncondBranch:
4593 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4594 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4595 B(offset);
4596 break;
4597 case Branch::kBareCondBranch:
4598 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4599 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4600 EmitBcondR2(condition, lhs, rhs, offset);
4601 break;
4602 case Branch::kBareCall:
4603 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4604 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4605 Bal(offset);
4606 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004607
Alexey Frunze96b66822016-09-10 02:32:44 -07004608 // R2 near label.
4609 case Branch::kLabel:
4610 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4611 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004612 Addiu(lhs, GetR2PcRelBaseRegister(rhs), offset);
Alexey Frunze96b66822016-09-10 02:32:44 -07004613 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004614 // R2 near literal.
4615 case Branch::kLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004616 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004617 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004618 Lw(lhs, GetR2PcRelBaseRegister(rhs), offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004619 break;
4620
4621 // R2 long branches.
4622 case Branch::kLongUncondBranch:
4623 // To get the value of the PC register we need to use the NAL instruction.
4624 // NAL clobbers the RA register. However, RA must be preserved if the
4625 // method is compiled without the entry/exit sequences that would take care
4626 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
4627 // So, we need to preserve RA in some temporary storage ourselves. The AT
4628 // register can't be used for this because we need it to load a constant
4629 // which will be added to the value that NAL stores in RA. And we can't
4630 // use T9 for this in the context of the JNI compiler, which uses it
4631 // as a scratch register (see InterproceduralScratchRegister()).
4632 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
4633 // we'd also need to use the ROTR instruction, which requires no less than
4634 // MIPSR2.
4635 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
4636 // (LO or HI) or even a floating-point register, but that doesn't seem
4637 // like a nice solution. We may want this to work on both R6 and pre-R6.
4638 // For now simply use the stack for RA. This should be OK since for the
4639 // vast majority of code a short PC-relative branch is sufficient.
4640 // TODO: can this be improved?
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004641 // TODO: consider generation of a shorter sequence when we know that RA
4642 // is explicitly preserved by the method entry/exit code.
4643 if (delayed_instruction != Branch::kUnfilledDelaySlot &&
4644 delayed_instruction != Branch::kUnfillableDelaySlot) {
4645 Emit(delayed_instruction);
4646 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004647 Push(RA);
4648 Nal();
4649 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4650 Lui(AT, High16Bits(offset));
4651 Ori(AT, AT, Low16Bits(offset));
4652 Addu(AT, AT, RA);
4653 Lw(RA, SP, 0);
4654 Jr(AT);
Chris Larsen715f43e2017-10-23 11:00:32 -07004655 DecreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004656 break;
4657 case Branch::kLongCondBranch:
4658 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004659 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4660 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4661 Emit(delayed_instruction);
4662 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004663 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
4664 // number of instructions skipped:
4665 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004666 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004667 Push(RA);
4668 Nal();
4669 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4670 Lui(AT, High16Bits(offset));
4671 Ori(AT, AT, Low16Bits(offset));
4672 Addu(AT, AT, RA);
4673 Lw(RA, SP, 0);
4674 Jr(AT);
Chris Larsen715f43e2017-10-23 11:00:32 -07004675 DecreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004676 break;
4677 case Branch::kLongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004678 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4679 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4680 Emit(delayed_instruction);
4681 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004682 Nal();
4683 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4684 Lui(AT, High16Bits(offset));
4685 Ori(AT, AT, Low16Bits(offset));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004686 Addu(AT, AT, RA);
4687 Jalr(AT);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004688 Nop();
4689 break;
4690
Alexey Frunze96b66822016-09-10 02:32:44 -07004691 // R2 far label.
4692 case Branch::kFarLabel:
4693 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4694 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4695 Lui(AT, High16Bits(offset));
4696 Ori(AT, AT, Low16Bits(offset));
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004697 Addu(lhs, AT, GetR2PcRelBaseRegister(rhs));
Alexey Frunze96b66822016-09-10 02:32:44 -07004698 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004699 // R2 far literal.
4700 case Branch::kFarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004701 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004702 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4703 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4704 Lui(AT, High16Bits(offset));
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004705 Addu(AT, AT, GetR2PcRelBaseRegister(rhs));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004706 Lw(lhs, AT, Low16Bits(offset));
4707 break;
4708
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004709 // R6 short branches.
4710 case Branch::kR6UncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004711 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004712 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4713 Bc(offset);
4714 break;
4715 case Branch::kR6CondBranch:
4716 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004717 EmitBcondR6(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004718 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4719 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4720 Emit(delayed_instruction);
4721 } else {
4722 // TODO: improve by filling the forbidden slot (IFF this is
4723 // a forbidden and not a delay slot).
4724 Nop();
4725 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004726 break;
4727 case Branch::kR6Call:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004728 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004729 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004730 Balc(offset);
4731 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004732 case Branch::kR6BareUncondBranch:
4733 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4734 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4735 Bc(offset);
4736 break;
4737 case Branch::kR6BareCondBranch:
4738 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4739 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4740 EmitBcondR6(condition, lhs, rhs, offset);
4741 break;
4742 case Branch::kR6BareCall:
4743 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4744 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4745 Balc(offset);
4746 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004747
Alexey Frunze96b66822016-09-10 02:32:44 -07004748 // R6 near label.
4749 case Branch::kR6Label:
4750 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4751 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4752 Addiupc(lhs, offset);
4753 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004754 // R6 near literal.
4755 case Branch::kR6Literal:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004756 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004757 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4758 Lwpc(lhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004759 break;
4760
4761 // R6 long branches.
4762 case Branch::kR6LongUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004763 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004764 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4765 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4766 Auipc(AT, High16Bits(offset));
4767 Jic(AT, Low16Bits(offset));
4768 break;
4769 case Branch::kR6LongCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004770 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4771 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4772 Emit(delayed_instruction);
4773 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004774 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004775 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4776 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4777 Auipc(AT, High16Bits(offset));
4778 Jic(AT, Low16Bits(offset));
4779 break;
4780 case Branch::kR6LongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004781 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004782 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004783 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004784 Auipc(AT, High16Bits(offset));
4785 Jialc(AT, Low16Bits(offset));
4786 break;
4787
Alexey Frunze96b66822016-09-10 02:32:44 -07004788 // R6 far label.
4789 case Branch::kR6FarLabel:
4790 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4791 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
4792 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4793 Auipc(AT, High16Bits(offset));
4794 Addiu(lhs, AT, Low16Bits(offset));
4795 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004796 // R6 far literal.
4797 case Branch::kR6FarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004798 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004799 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4800 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4801 Auipc(AT, High16Bits(offset));
4802 Lw(lhs, AT, Low16Bits(offset));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004803 break;
4804 }
4805 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
4806 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004807 if (patcher_label != nullptr) {
4808 // The patched instruction should look like one.
4809 uint32_t patched_instruction = buffer_.Load<uint32_t>(GetLabelLocation(patcher_label));
4810 CHECK(!IsAbsorbableInstruction(patched_instruction));
4811 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004812}
4813
Alexey Frunze0cab6562017-07-25 15:19:36 -07004814void MipsAssembler::B(MipsLabel* label, bool is_bare) {
4815 Buncond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004816}
4817
Alexey Frunze0cab6562017-07-25 15:19:36 -07004818void MipsAssembler::Bal(MipsLabel* label, bool is_bare) {
4819 Call(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004820}
4821
Alexey Frunze0cab6562017-07-25 15:19:36 -07004822void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4823 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004824}
4825
Alexey Frunze0cab6562017-07-25 15:19:36 -07004826void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4827 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004828}
4829
Alexey Frunze0cab6562017-07-25 15:19:36 -07004830void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) {
4831 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004832}
4833
Alexey Frunze0cab6562017-07-25 15:19:36 -07004834void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) {
4835 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004836}
4837
Alexey Frunze0cab6562017-07-25 15:19:36 -07004838void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) {
4839 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004840}
4841
Alexey Frunze0cab6562017-07-25 15:19:36 -07004842void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) {
4843 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004844}
4845
Alexey Frunze0cab6562017-07-25 15:19:36 -07004846void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) {
4847 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004848}
4849
Alexey Frunze0cab6562017-07-25 15:19:36 -07004850void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) {
4851 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004852}
4853
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004854bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
4855 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u]
4856 // instruction because either slt[u] depends on `rs` or `rt` or the following
4857 // conditional branch depends on AT set by slt[u].
4858 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
4859 // because slt[u] changes AT.
4860 return (delay_slot_.instruction_ != 0 &&
4861 (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
4862 (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0);
4863}
4864
4865void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
4866 // Exchange the last two instructions in the assembler buffer.
4867 size_t size = buffer_.Size();
4868 CHECK_GE(size, 2 * sizeof(uint32_t));
4869 size_t pos1 = size - 2 * sizeof(uint32_t);
4870 size_t pos2 = size - sizeof(uint32_t);
4871 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
4872 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
4873 CHECK_EQ(instr1, forwarded_slot.instruction_);
4874 CHECK_EQ(instr2, delay_slot_.instruction_);
4875 buffer_.Store<uint32_t>(pos1, instr2);
4876 buffer_.Store<uint32_t>(pos2, instr1);
4877 // Set the current delay slot information to that of the last instruction
4878 // in the buffer.
4879 delay_slot_ = forwarded_slot;
4880}
4881
4882void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) {
4883 // If possible, exchange the slt[u] instruction with the preceding instruction,
4884 // so it can fill the delay slot.
4885 DelaySlot forwarded_slot = delay_slot_;
4886 bool exchange = CanExchangeWithSlt(rs, rt);
4887 if (exchange) {
4888 // The last instruction cannot be used in a different delay slot,
4889 // do not commit the label before it (if any).
4890 DsFsmDropLabel();
4891 }
4892 if (unsigned_slt) {
4893 Sltu(AT, rs, rt);
4894 } else {
4895 Slt(AT, rs, rt);
4896 }
4897 if (exchange) {
4898 ExchangeWithSlt(forwarded_slot);
4899 }
4900}
4901
Alexey Frunze0cab6562017-07-25 15:19:36 -07004902void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4903 if (IsR6() && !is_bare) {
4904 Bcond(label, IsR6(), is_bare, kCondLT, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004905 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
4906 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004907 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004908 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004909 }
4910}
4911
Alexey Frunze0cab6562017-07-25 15:19:36 -07004912void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4913 if (IsR6() && !is_bare) {
4914 Bcond(label, IsR6(), is_bare, kCondGE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004915 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004916 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004917 } else {
4918 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004919 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004920 Beqz(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004921 }
4922}
4923
Alexey Frunze0cab6562017-07-25 15:19:36 -07004924void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4925 if (IsR6() && !is_bare) {
4926 Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004927 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
4928 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004929 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004930 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004931 }
4932}
4933
Alexey Frunze0cab6562017-07-25 15:19:36 -07004934void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4935 if (IsR6() && !is_bare) {
4936 Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004937 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004938 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004939 } else {
4940 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004941 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004942 Beqz(AT, label, is_bare);
jeffhao7fbee072012-08-24 17:56:54 -07004943 }
4944}
4945
Alexey Frunze0cab6562017-07-25 15:19:36 -07004946void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) {
4947 Bc1f(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004948}
4949
Alexey Frunze0cab6562017-07-25 15:19:36 -07004950void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004951 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004952 Bcond(label, /* is_r6 */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004953}
4954
Alexey Frunze0cab6562017-07-25 15:19:36 -07004955void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) {
4956 Bc1t(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004957}
4958
Alexey Frunze0cab6562017-07-25 15:19:36 -07004959void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004960 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004961 Bcond(label, /* is_r6 */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004962}
4963
Alexey Frunze0cab6562017-07-25 15:19:36 -07004964void MipsAssembler::Bc(MipsLabel* label, bool is_bare) {
4965 Buncond(label, /* is_r6 */ true, is_bare);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004966}
4967
Alexey Frunze0cab6562017-07-25 15:19:36 -07004968void MipsAssembler::Balc(MipsLabel* label, bool is_bare) {
4969 Call(label, /* is_r6 */ true, is_bare);
4970}
4971
4972void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4973 Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt);
4974}
4975
4976void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4977 Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt);
4978}
4979
4980void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) {
4981 Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rt);
4982}
4983
4984void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) {
4985 Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rt);
4986}
4987
4988void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) {
4989 Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt);
4990}
4991
4992void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) {
4993 Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt);
4994}
4995
4996void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) {
4997 Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt);
4998}
4999
5000void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) {
5001 Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt);
5002}
5003
5004void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
5005 Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt);
5006}
5007
5008void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
5009 Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt);
5010}
5011
5012void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
5013 Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt);
5014}
5015
5016void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
5017 Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt);
5018}
5019
5020void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) {
5021 Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO);
5022}
5023
5024void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) {
5025 Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005026}
5027
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07005028void MipsAssembler::AdjustBaseAndOffset(Register& base,
5029 int32_t& offset,
5030 bool is_doubleword,
5031 bool is_float) {
5032 // This method is used to adjust the base register and offset pair
5033 // for a load/store when the offset doesn't fit into int16_t.
5034 // It is assumed that `base + offset` is sufficiently aligned for memory
5035 // operands that are machine word in size or smaller. For doubleword-sized
5036 // operands it's assumed that `base` is a multiple of 8, while `offset`
5037 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
5038 // and spilled variables on the stack accessed relative to the stack
5039 // pointer register).
5040 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
5041 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
5042
5043 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
5044 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
5045
5046 // IsInt<16> must be passed a signed value, hence the static cast below.
5047 if (IsInt<16>(offset) &&
5048 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
5049 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
5050 return;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005051 }
5052
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07005053 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
5054 uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
5055
5056 // Do not load the whole 32-bit `offset` if it can be represented as
5057 // a sum of two 16-bit signed offsets. This can save an instruction or two.
5058 // To simplify matters, only do this for a symmetric range of offsets from
5059 // about -64KB to about +64KB, allowing further addition of 4 when accessing
5060 // 64-bit variables with two 32-bit accesses.
5061 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
5062 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
5063 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
5064 Addiu(AT, base, kMinOffsetForSimpleAdjustment);
5065 offset -= kMinOffsetForSimpleAdjustment;
5066 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
5067 Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
5068 offset += kMinOffsetForSimpleAdjustment;
5069 } else if (IsR6()) {
5070 // On R6 take advantage of the aui instruction, e.g.:
5071 // aui AT, base, offset_high
5072 // lw reg_lo, offset_low(AT)
5073 // lw reg_hi, (offset_low+4)(AT)
5074 // or when offset_low+4 overflows int16_t:
5075 // aui AT, base, offset_high
5076 // addiu AT, AT, 8
5077 // lw reg_lo, (offset_low-8)(AT)
5078 // lw reg_hi, (offset_low-4)(AT)
5079 int16_t offset_high = High16Bits(offset);
5080 int16_t offset_low = Low16Bits(offset);
5081 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store.
5082 Aui(AT, base, offset_high);
5083 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
5084 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
5085 Addiu(AT, AT, kMipsDoublewordSize);
5086 offset_low -= kMipsDoublewordSize;
5087 }
5088 offset = offset_low;
5089 } else {
5090 // Do not load the whole 32-bit `offset` if it can be represented as
5091 // a sum of three 16-bit signed offsets. This can save an instruction.
5092 // To simplify matters, only do this for a symmetric range of offsets from
5093 // about -96KB to about +96KB, allowing further addition of 4 when accessing
5094 // 64-bit variables with two 32-bit accesses.
5095 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
5096 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
5097 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
5098 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
5099 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
5100 offset -= kMinOffsetForMediumAdjustment;
5101 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
5102 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
5103 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
5104 offset += kMinOffsetForMediumAdjustment;
5105 } else {
5106 // Now that all shorter options have been exhausted, load the full 32-bit offset.
5107 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
5108 LoadConst32(AT, loaded_offset);
5109 Addu(AT, AT, base);
5110 offset -= loaded_offset;
5111 }
5112 }
5113 base = AT;
5114
5115 CHECK(IsInt<16>(offset));
5116 if (two_accesses) {
5117 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
5118 }
5119 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
5120}
5121
Lena Djokic2e0a7e52017-07-06 11:55:24 +02005122void MipsAssembler::AdjustBaseOffsetAndElementSizeShift(Register& base,
5123 int32_t& offset,
5124 int& element_size_shift) {
5125 // This method is used to adjust the base register, offset and element_size_shift
5126 // for a vector load/store when the offset doesn't fit into allowed number of bits.
5127 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
5128 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
5129 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
5130 // If element_size_shift is non-negative at entry, it won't be changed, but offset
5131 // will be checked for appropriate alignment. If negative at entry, it will be
5132 // adjusted based on offset for maximum fit.
5133 // It's assumed that `base` is a multiple of 8.
5134 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
5135
5136 if (element_size_shift >= 0) {
5137 CHECK_LE(element_size_shift, TIMES_8);
5138 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
5139 } else if (IsAligned<kMipsDoublewordSize>(offset)) {
5140 element_size_shift = TIMES_8;
5141 } else if (IsAligned<kMipsWordSize>(offset)) {
5142 element_size_shift = TIMES_4;
5143 } else if (IsAligned<kMipsHalfwordSize>(offset)) {
5144 element_size_shift = TIMES_2;
5145 } else {
5146 element_size_shift = TIMES_1;
5147 }
5148
5149 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
5150 // will take.
5151 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
5152 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
5153 if (low == offset) {
5154 return; // `offset` fits into ld.df/st.df.
5155 }
5156
5157 // First, see if `offset` can be represented as a sum of two or three signed offsets.
5158 // This can save an instruction or two.
5159
5160 // Max int16_t that's a multiple of element size.
5161 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
5162 // Max ld.df/st.df offset that's a multiple of element size.
5163 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
5164 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
5165 const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment;
5166 const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset;
5167
5168 if (IsInt<16>(offset)) {
5169 Addiu(AT, base, offset);
5170 offset = 0;
5171 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
5172 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
5173 offset -= kMaxDeltaForSimpleAdjustment;
5174 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
5175 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
5176 offset += kMaxDeltaForSimpleAdjustment;
5177 } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
5178 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
5179 if (offset <= kMinOffsetForMediumAdjustment) {
5180 Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment);
5181 offset = 0;
5182 } else {
5183 Addiu(AT, AT, kMaxDeltaForSimpleAdjustment);
5184 offset -= kMinOffsetForMediumAdjustment;
5185 }
5186 } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
5187 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
5188 if (-kMinOffsetForMediumAdjustment <= offset) {
5189 Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment);
5190 offset = 0;
5191 } else {
5192 Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment);
5193 offset += kMinOffsetForMediumAdjustment;
5194 }
5195 } else {
5196 // 16-bit or smaller parts of `offset`:
5197 // |31 hi 16|15 mid 13-10|12-9 low 0|
5198 //
5199 // Instructions that supply each part as a signed integer addend:
5200 // |aui |addiu |ld.df/st.df |
5201 uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset`
5202 // (accounts for sign of `low`).
5203 tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu.
5204 int16_t mid = Low16Bits(tmp);
5205 int16_t hi = High16Bits(tmp);
5206 if (IsR6()) {
5207 Aui(AT, base, hi);
5208 } else {
5209 Lui(AT, hi);
5210 Addu(AT, AT, base);
5211 }
5212 if (mid != 0) {
5213 Addiu(AT, AT, mid);
5214 }
5215 offset = low;
5216 }
5217 base = AT;
5218 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
5219 CHECK(IsInt<10>(offset >> element_size_shift));
5220}
5221
Alexey Frunze2923db72016-08-20 01:55:47 -07005222void MipsAssembler::LoadFromOffset(LoadOperandType type,
5223 Register reg,
5224 Register base,
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07005225 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005226 LoadFromOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07005227}
5228
5229void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005230 LoadSFromOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07005231}
5232
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005233void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005234 LoadDFromOffset<>(reg, base, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005235}
5236
Lena Djokic2e0a7e52017-07-06 11:55:24 +02005237void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) {
5238 LoadQFromOffset<>(reg, base, offset);
5239}
5240
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005241void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
5242 size_t size) {
5243 MipsManagedRegister dst = m_dst.AsMips();
5244 if (dst.IsNoRegister()) {
5245 CHECK_EQ(0u, size) << dst;
5246 } else if (dst.IsCoreRegister()) {
5247 CHECK_EQ(kMipsWordSize, size) << dst;
5248 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
5249 } else if (dst.IsRegisterPair()) {
5250 CHECK_EQ(kMipsDoublewordSize, size) << dst;
5251 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
5252 } else if (dst.IsFRegister()) {
5253 if (size == kMipsWordSize) {
5254 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
5255 } else {
5256 CHECK_EQ(kMipsDoublewordSize, size) << dst;
5257 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
5258 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08005259 } else if (dst.IsDRegister()) {
5260 CHECK_EQ(kMipsDoublewordSize, size) << dst;
5261 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005262 }
jeffhao7fbee072012-08-24 17:56:54 -07005263}
5264
Alexey Frunze2923db72016-08-20 01:55:47 -07005265void MipsAssembler::StoreToOffset(StoreOperandType type,
5266 Register reg,
5267 Register base,
jeffhao7fbee072012-08-24 17:56:54 -07005268 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005269 StoreToOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07005270}
5271
Goran Jakovljevicff734982015-08-24 12:58:55 +00005272void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005273 StoreSToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07005274}
5275
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005276void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005277 StoreDToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07005278}
5279
Lena Djokic2e0a7e52017-07-06 11:55:24 +02005280void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) {
5281 StoreQToOffset<>(reg, base, offset);
5282}
5283
David Srbeckydd973932015-04-07 20:29:48 +01005284static dwarf::Reg DWARFReg(Register reg) {
5285 return dwarf::Reg::MipsCore(static_cast<int>(reg));
5286}
5287
Ian Rogers790a6b72014-04-01 10:36:00 -07005288constexpr size_t kFramePointerSize = 4;
5289
Vladimir Marko32248382016-05-19 10:37:24 +01005290void MipsAssembler::BuildFrame(size_t frame_size,
5291 ManagedRegister method_reg,
5292 ArrayRef<const ManagedRegister> callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07005293 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07005294 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01005295 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07005296
5297 // Increase frame to required size.
5298 IncreaseFrameSize(frame_size);
5299
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005300 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07005301 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07005302 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01005303 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07005304 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07005305 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01005306 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07005307 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01005308 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07005309 }
5310
5311 // Write out Method*.
5312 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
5313
5314 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00005315 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07005316 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00005317 MipsManagedRegister reg = entry_spills.at(i).AsMips();
5318 if (reg.IsNoRegister()) {
5319 ManagedRegisterSpill spill = entry_spills.at(i);
5320 offset += spill.getSize();
5321 } else if (reg.IsCoreRegister()) {
5322 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005323 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00005324 } else if (reg.IsFRegister()) {
5325 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005326 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00005327 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005328 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
5329 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00005330 }
jeffhao7fbee072012-08-24 17:56:54 -07005331 }
5332}
5333
5334void MipsAssembler::RemoveFrame(size_t frame_size,
Roland Levillain0d127e12017-07-05 17:01:11 +01005335 ArrayRef<const ManagedRegister> callee_save_regs,
5336 bool may_suspend ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07005337 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01005338 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01005339 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07005340
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005341 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07005342 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07005343 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01005344 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07005345 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01005346 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07005347 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07005348 }
5349 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01005350 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07005351
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005352 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
5353 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
5354 bool reordering = SetReorder(false);
5355 if (exchange) {
5356 // Jump to the return address.
5357 Jr(RA);
5358 // Decrease frame to required size.
5359 DecreaseFrameSize(frame_size); // Single instruction in delay slot.
5360 } else {
5361 // Decrease frame to required size.
5362 DecreaseFrameSize(frame_size);
5363 // Jump to the return address.
5364 Jr(RA);
5365 Nop(); // In delay slot.
5366 }
5367 SetReorder(reordering);
David Srbeckydd973932015-04-07 20:29:48 +01005368
5369 // The CFI should be restored for any code that follows the exit block.
5370 cfi_.RestoreState();
5371 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07005372}
5373
5374void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005375 CHECK_ALIGNED(adjust, kFramePointerSize);
5376 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01005377 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01005378 if (overwriting_) {
5379 cfi_.OverrideDelayedPC(overwrite_location_);
5380 }
jeffhao7fbee072012-08-24 17:56:54 -07005381}
5382
5383void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005384 CHECK_ALIGNED(adjust, kFramePointerSize);
5385 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01005386 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01005387 if (overwriting_) {
5388 cfi_.OverrideDelayedPC(overwrite_location_);
5389 }
jeffhao7fbee072012-08-24 17:56:54 -07005390}
5391
5392void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
5393 MipsManagedRegister src = msrc.AsMips();
5394 if (src.IsNoRegister()) {
5395 CHECK_EQ(0u, size);
5396 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005397 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07005398 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5399 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005400 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07005401 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
5402 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005403 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005404 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005405 if (size == kMipsWordSize) {
5406 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
5407 } else {
5408 CHECK_EQ(kMipsDoublewordSize, size);
5409 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
5410 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08005411 } else if (src.IsDRegister()) {
5412 CHECK_EQ(kMipsDoublewordSize, size);
5413 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005414 }
5415}
5416
5417void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
5418 MipsManagedRegister src = msrc.AsMips();
5419 CHECK(src.IsCoreRegister());
5420 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5421}
5422
5423void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
5424 MipsManagedRegister src = msrc.AsMips();
5425 CHECK(src.IsCoreRegister());
5426 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5427}
5428
5429void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
5430 ManagedRegister mscratch) {
5431 MipsManagedRegister scratch = mscratch.AsMips();
5432 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005433 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07005434 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
5435}
5436
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005437void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
5438 FrameOffset fr_offs,
jeffhao7fbee072012-08-24 17:56:54 -07005439 ManagedRegister mscratch) {
5440 MipsManagedRegister scratch = mscratch.AsMips();
5441 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005442 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005443 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5444 S1, thr_offs.Int32Value());
5445}
5446
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005447void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005448 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
5449}
5450
5451void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
5452 FrameOffset in_off, ManagedRegister mscratch) {
5453 MipsManagedRegister src = msrc.AsMips();
5454 MipsManagedRegister scratch = mscratch.AsMips();
5455 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5456 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005457 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005458}
5459
5460void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
5461 return EmitLoad(mdest, SP, src.Int32Value(), size);
5462}
5463
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005464void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005465 return EmitLoad(mdest, S1, src.Int32Value(), size);
5466}
5467
5468void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
5469 MipsManagedRegister dest = mdest.AsMips();
5470 CHECK(dest.IsCoreRegister());
5471 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
5472}
5473
Mathieu Chartiere401d142015-04-22 13:56:20 -07005474void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01005475 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07005476 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005477 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07005478 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
5479 base.AsMips().AsCoreRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08005480 if (unpoison_reference) {
5481 MaybeUnpoisonHeapReference(dest.AsCoreRegister());
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08005482 }
jeffhao7fbee072012-08-24 17:56:54 -07005483}
5484
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005485void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005486 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005487 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07005488 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
5489 base.AsMips().AsCoreRegister(), offs.Int32Value());
5490}
5491
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005492void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005493 MipsManagedRegister dest = mdest.AsMips();
5494 CHECK(dest.IsCoreRegister());
5495 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
5496}
5497
5498void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
5499 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
5500}
5501
5502void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
5503 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
5504}
5505
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005506void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005507 MipsManagedRegister dest = mdest.AsMips();
5508 MipsManagedRegister src = msrc.AsMips();
5509 if (!dest.Equals(src)) {
5510 if (dest.IsCoreRegister()) {
5511 CHECK(src.IsCoreRegister()) << src;
5512 Move(dest.AsCoreRegister(), src.AsCoreRegister());
5513 } else if (dest.IsFRegister()) {
5514 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005515 if (size == kMipsWordSize) {
5516 MovS(dest.AsFRegister(), src.AsFRegister());
5517 } else {
5518 CHECK_EQ(kMipsDoublewordSize, size);
5519 MovD(dest.AsFRegister(), src.AsFRegister());
5520 }
jeffhao7fbee072012-08-24 17:56:54 -07005521 } else if (dest.IsDRegister()) {
5522 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005523 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07005524 } else {
5525 CHECK(dest.IsRegisterPair()) << dest;
5526 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005527 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07005528 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
5529 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
5530 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
5531 } else {
5532 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
5533 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
5534 }
5535 }
5536 }
5537}
5538
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005539void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005540 MipsManagedRegister scratch = mscratch.AsMips();
5541 CHECK(scratch.IsCoreRegister()) << scratch;
5542 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5543 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
5544}
5545
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005546void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
5547 ThreadOffset32 thr_offs,
5548 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005549 MipsManagedRegister scratch = mscratch.AsMips();
5550 CHECK(scratch.IsCoreRegister()) << scratch;
5551 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5552 S1, thr_offs.Int32Value());
5553 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5554 SP, fr_offs.Int32Value());
5555}
5556
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005557void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
5558 FrameOffset fr_offs,
5559 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005560 MipsManagedRegister scratch = mscratch.AsMips();
5561 CHECK(scratch.IsCoreRegister()) << scratch;
5562 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5563 SP, fr_offs.Int32Value());
5564 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5565 S1, thr_offs.Int32Value());
5566}
5567
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005568void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005569 MipsManagedRegister scratch = mscratch.AsMips();
5570 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005571 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
5572 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005573 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5574 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005575 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005576 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5577 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005578 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
5579 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005580 }
5581}
5582
5583void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
5584 ManagedRegister mscratch, size_t size) {
5585 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005586 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005587 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
5588 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
5589}
5590
5591void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
5592 ManagedRegister mscratch, size_t size) {
5593 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005594 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005595 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
5596 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5597}
5598
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005599void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5600 FrameOffset src_base ATTRIBUTE_UNUSED,
5601 Offset src_offset ATTRIBUTE_UNUSED,
5602 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5603 size_t size ATTRIBUTE_UNUSED) {
5604 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005605}
5606
5607void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
5608 ManagedRegister src, Offset src_offset,
5609 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005610 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005611 Register scratch = mscratch.AsMips().AsCoreRegister();
5612 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
5613 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5614}
5615
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005616void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5617 Offset dest_offset ATTRIBUTE_UNUSED,
5618 FrameOffset src ATTRIBUTE_UNUSED,
5619 Offset src_offset ATTRIBUTE_UNUSED,
5620 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5621 size_t size ATTRIBUTE_UNUSED) {
5622 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005623}
5624
5625void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005626 // TODO: sync?
5627 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005628}
5629
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005630void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005631 FrameOffset handle_scope_offset,
5632 ManagedRegister min_reg,
5633 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005634 MipsManagedRegister out_reg = mout_reg.AsMips();
5635 MipsManagedRegister in_reg = min_reg.AsMips();
5636 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
5637 CHECK(out_reg.IsCoreRegister()) << out_reg;
5638 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005639 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005640 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5641 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005642 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07005643 if (in_reg.IsNoRegister()) {
5644 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005645 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005646 in_reg = out_reg;
5647 }
5648 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005649 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005650 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005651 Beqz(in_reg.AsCoreRegister(), &null_arg);
5652 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5653 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005654 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005655 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005656 }
5657}
5658
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005659void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005660 FrameOffset handle_scope_offset,
5661 ManagedRegister mscratch,
5662 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005663 MipsManagedRegister scratch = mscratch.AsMips();
5664 CHECK(scratch.IsCoreRegister()) << scratch;
5665 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005666 MipsLabel null_arg;
5667 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005668 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5669 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005670 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
5671 Beqz(scratch.AsCoreRegister(), &null_arg);
5672 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5673 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005674 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005675 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005676 }
5677 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
5678}
5679
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005680// Given a handle scope entry, load the associated reference.
5681void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005682 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07005683 MipsManagedRegister out_reg = mout_reg.AsMips();
5684 MipsManagedRegister in_reg = min_reg.AsMips();
5685 CHECK(out_reg.IsCoreRegister()) << out_reg;
5686 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005687 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07005688 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005689 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005690 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005691 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005692 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
5693 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005694 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005695}
5696
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005697void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
5698 bool could_be_null ATTRIBUTE_UNUSED) {
5699 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005700}
5701
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005702void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
5703 bool could_be_null ATTRIBUTE_UNUSED) {
5704 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005705}
5706
5707void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
5708 MipsManagedRegister base = mbase.AsMips();
5709 MipsManagedRegister scratch = mscratch.AsMips();
5710 CHECK(base.IsCoreRegister()) << base;
5711 CHECK(scratch.IsCoreRegister()) << scratch;
5712 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5713 base.AsCoreRegister(), offset.Int32Value());
5714 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005715 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005716 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005717}
5718
5719void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
5720 MipsManagedRegister scratch = mscratch.AsMips();
5721 CHECK(scratch.IsCoreRegister()) << scratch;
5722 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005723 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005724 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5725 scratch.AsCoreRegister(), offset.Int32Value());
5726 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005727 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005728 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005729}
5730
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005731void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
5732 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07005733 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005734}
5735
5736void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
5737 Move(tr.AsMips().AsCoreRegister(), S1);
5738}
5739
5740void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005741 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07005742 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
5743}
5744
jeffhao7fbee072012-08-24 17:56:54 -07005745void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
5746 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005747 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07005748 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Andreas Gampe542451c2016-07-26 09:02:02 -07005749 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005750 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07005751}
5752
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005753void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
5754 Bind(exception->Entry());
5755 if (exception->stack_adjust_ != 0) { // Fix up the frame.
5756 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07005757 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005758 // Pass exception object as argument.
5759 // Don't care about preserving A0 as this call won't return.
5760 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5761 Move(A0, exception->scratch_.AsCoreRegister());
5762 // Set up call to Thread::Current()->pDeliverException.
5763 LoadFromOffset(kLoadWord, T9, S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07005764 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005765 Jr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005766 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005767
5768 // Call never returns.
5769 Break();
jeffhao7fbee072012-08-24 17:56:54 -07005770}
5771
5772} // namespace mips
5773} // namespace art