blob: 18099d8e131030e447bd46cedfde3ff8602101ab [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),
50 cc_ins_mask_(0) {}
51
52void MipsAssembler::DsFsmInstr(uint32_t instruction,
53 uint32_t gpr_outs_mask,
54 uint32_t gpr_ins_mask,
55 uint32_t fpr_outs_mask,
56 uint32_t fpr_ins_mask,
57 uint32_t cc_outs_mask,
58 uint32_t cc_ins_mask) {
59 if (!reordering_) {
60 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
61 CHECK_EQ(delay_slot_.instruction_, 0u);
62 return;
63 }
64 switch (ds_fsm_state_) {
65 case kExpectingLabel:
66 break;
67 case kExpectingInstruction:
68 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
69 // If the last instruction is not suitable for delay slots, drop
70 // the PC of the label preceding it so that no unconditional branch
71 // uses this instruction to fill its delay slot.
72 if (instruction == 0) {
73 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
74 } else {
75 // Otherwise wait for another instruction or label before we can
76 // commit the label PC. The label PC will be dropped if instead
77 // of another instruction or label there's a call from the code
78 // generator to CodePosition() to record the buffer size.
79 // Instructions after which the buffer size is recorded cannot
80 // be moved into delay slots or anywhere else because they may
81 // trigger signals and the signal handlers expect these signals
82 // to be coming from the instructions immediately preceding the
83 // recorded buffer locations.
84 ds_fsm_state_ = kExpectingCommit;
85 }
86 break;
87 case kExpectingCommit:
88 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size());
89 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
90 break;
91 }
92 delay_slot_.instruction_ = instruction;
93 delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u; // Ignore register ZERO.
94 delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u; // Ignore register ZERO.
95 delay_slot_.fpr_outs_mask_ = fpr_outs_mask;
96 delay_slot_.fpr_ins_mask_ = fpr_ins_mask;
97 delay_slot_.cc_outs_mask_ = cc_outs_mask;
98 delay_slot_.cc_ins_mask_ = cc_ins_mask;
99}
100
101void MipsAssembler::DsFsmLabel() {
102 if (!reordering_) {
103 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
104 CHECK_EQ(delay_slot_.instruction_, 0u);
105 return;
106 }
107 switch (ds_fsm_state_) {
108 case kExpectingLabel:
109 ds_fsm_target_pc_ = buffer_.Size();
110 ds_fsm_state_ = kExpectingInstruction;
111 break;
112 case kExpectingInstruction:
113 // Allow consecutive labels.
114 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size());
115 break;
116 case kExpectingCommit:
117 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
118 DsFsmCommitLabel();
119 ds_fsm_target_pc_ = buffer_.Size();
120 ds_fsm_state_ = kExpectingInstruction;
121 break;
122 }
123 // We cannot move instructions into delay slots across labels.
124 delay_slot_.instruction_ = 0;
125}
126
127void MipsAssembler::DsFsmCommitLabel() {
128 if (ds_fsm_state_ == kExpectingCommit) {
129 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_);
130 }
131 ds_fsm_state_ = kExpectingLabel;
132}
133
134void MipsAssembler::DsFsmDropLabel() {
135 ds_fsm_state_ = kExpectingLabel;
136}
137
138bool MipsAssembler::SetReorder(bool enable) {
139 bool last_state = reordering_;
140 if (last_state != enable) {
141 DsFsmCommitLabel();
142 DsFsmInstrNop(0);
143 }
144 reordering_ = enable;
145 return last_state;
146}
147
148size_t MipsAssembler::CodePosition() {
149 // The last instruction cannot be used in a delay slot, do not commit
150 // the label before it (if any) and clear the delay slot.
151 DsFsmDropLabel();
152 DsFsmInstrNop(0);
153 size_t size = buffer_.Size();
154 // In theory we can get the following sequence:
155 // label1:
156 // instr
157 // label2: # label1 gets committed when label2 is seen
158 // CodePosition() call
159 // and we need to uncommit label1.
160 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) {
161 ds_fsm_target_pcs_.pop_back();
162 }
163 return size;
164}
165
166void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
167 DsFsmInstr(0, 0, 0, 0, 0, 0, 0);
168}
169
170void MipsAssembler::DsFsmInstrRrr(uint32_t instruction, Register out, Register in1, Register in2) {
171 DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0);
172}
173
174void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction,
175 Register in1_out,
176 Register in2,
177 Register in3) {
178 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0);
179}
180
181void MipsAssembler::DsFsmInstrFff(uint32_t instruction,
182 FRegister out,
183 FRegister in1,
184 FRegister in2) {
185 DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0);
186}
187
188void MipsAssembler::DsFsmInstrFfff(uint32_t instruction,
189 FRegister in1_out,
190 FRegister in2,
191 FRegister in3) {
192 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0);
193}
194
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700195void MipsAssembler::DsFsmInstrFffr(uint32_t instruction,
196 FRegister in1_out,
197 FRegister in2,
198 Register in3) {
199 DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0);
200}
201
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700202void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) {
203 DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0);
204}
205
206void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) {
207 DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0);
208}
209
210void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) {
211 DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0);
212}
213
214void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) {
215 DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0);
216}
217
218void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction,
219 Register in1_out,
220 Register in2,
221 int cc_in) {
222 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in));
223}
224
225void MipsAssembler::DsFsmInstrFffc(uint32_t instruction,
226 FRegister in1_out,
227 FRegister in2,
228 int cc_in) {
229 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in));
230}
231
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200232void MipsAssembler::FinalizeCode() {
233 for (auto& exception_block : exception_blocks_) {
234 EmitExceptionPoll(&exception_block);
235 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700236 // Commit the last branch target label (if any) and disable instruction reordering.
237 DsFsmCommitLabel();
238 SetReorder(false);
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700239 EmitLiterals();
Alexey Frunze96b66822016-09-10 02:32:44 -0700240 ReserveJumpTableSpace();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200241 PromoteBranches();
242}
243
244void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
Vladimir Marko10ef6942015-10-22 15:25:54 +0100245 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200246 EmitBranches();
Alexey Frunze96b66822016-09-10 02:32:44 -0700247 EmitJumpTables();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200248 Assembler::FinalizeInstructions(region);
Vladimir Marko10ef6942015-10-22 15:25:54 +0100249 PatchCFI(number_of_delayed_adjust_pcs);
250}
251
252void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
253 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
254 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
255 return;
256 }
257
258 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
259 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
260 const std::vector<uint8_t>& old_stream = data.first;
261 const std::vector<DelayedAdvancePC>& advances = data.second;
262
263 // PCs recorded before EmitBranches() need to be adjusted.
264 // PCs recorded during EmitBranches() are already adjusted.
265 // Both ranges are separately sorted but they may overlap.
266 if (kIsDebugBuild) {
267 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
268 return lhs.pc < rhs.pc;
269 };
270 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
271 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
272 }
273
274 // Append initial CFI data if any.
275 size_t size = advances.size();
276 DCHECK_NE(size, 0u);
277 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
278 // Emit PC adjustments interleaved with the old CFI stream.
279 size_t adjust_pos = 0u;
280 size_t late_emit_pos = number_of_delayed_adjust_pcs;
281 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
282 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
283 ? GetAdjustedPosition(advances[adjust_pos].pc)
284 : static_cast<size_t>(-1);
285 size_t late_emit_pc = (late_emit_pos != size)
286 ? advances[late_emit_pos].pc
287 : static_cast<size_t>(-1);
288 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
289 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
290 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
291 if (adjusted_pc <= late_emit_pc) {
292 ++adjust_pos;
293 } else {
294 ++late_emit_pos;
295 }
296 cfi().AdvancePC(advance_pc);
297 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
298 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
299 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200300}
301
302void MipsAssembler::EmitBranches() {
303 CHECK(!overwriting_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700304 CHECK(!reordering_);
305 // Now that everything has its final position in the buffer (the branches have
306 // been promoted), adjust the target label PCs.
307 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) {
308 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]);
309 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200310 // Switch from appending instructions at the end of the buffer to overwriting
311 // existing instructions (branch placeholders) in the buffer.
312 overwriting_ = true;
313 for (auto& branch : branches_) {
314 EmitBranch(&branch);
315 }
316 overwriting_ = false;
317}
318
319void MipsAssembler::Emit(uint32_t value) {
320 if (overwriting_) {
321 // Branches to labels are emitted into their placeholders here.
322 buffer_.Store<uint32_t>(overwrite_location_, value);
323 overwrite_location_ += sizeof(uint32_t);
324 } else {
325 // Other instructions are simply appended at the end here.
326 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
327 buffer_.Emit<uint32_t>(value);
328 }
jeffhao7fbee072012-08-24 17:56:54 -0700329}
330
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700331uint32_t MipsAssembler::EmitR(int opcode,
332 Register rs,
333 Register rt,
334 Register rd,
335 int shamt,
336 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700337 CHECK_NE(rs, kNoRegister);
338 CHECK_NE(rt, kNoRegister);
339 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200340 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
341 static_cast<uint32_t>(rs) << kRsShift |
342 static_cast<uint32_t>(rt) << kRtShift |
343 static_cast<uint32_t>(rd) << kRdShift |
344 shamt << kShamtShift |
345 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700346 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700347 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700348}
349
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700350uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
jeffhao7fbee072012-08-24 17:56:54 -0700351 CHECK_NE(rs, kNoRegister);
352 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200353 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
354 static_cast<uint32_t>(rs) << kRsShift |
355 static_cast<uint32_t>(rt) << kRtShift |
356 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700357 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700358 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700359}
360
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700361uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200362 CHECK_NE(rs, kNoRegister);
363 CHECK(IsUint<21>(imm21)) << imm21;
364 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
365 static_cast<uint32_t>(rs) << kRsShift |
366 imm21;
jeffhao7fbee072012-08-24 17:56:54 -0700367 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700368 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700369}
370
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700371uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372 CHECK(IsUint<26>(imm26)) << imm26;
373 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
374 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700375 return encoding;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200376}
377
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700378uint32_t MipsAssembler::EmitFR(int opcode,
379 int fmt,
380 FRegister ft,
381 FRegister fs,
382 FRegister fd,
383 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700384 CHECK_NE(ft, kNoFRegister);
385 CHECK_NE(fs, kNoFRegister);
386 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200387 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
388 fmt << kFmtShift |
389 static_cast<uint32_t>(ft) << kFtShift |
390 static_cast<uint32_t>(fs) << kFsShift |
391 static_cast<uint32_t>(fd) << kFdShift |
392 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700393 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700394 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700395}
396
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700397uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200398 CHECK_NE(ft, kNoFRegister);
399 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
400 fmt << kFmtShift |
401 static_cast<uint32_t>(ft) << kFtShift |
402 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700403 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700404 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700405}
406
Lena Djokic0758ae72017-05-23 11:06:23 +0200407uint32_t MipsAssembler::EmitMsa3R(int operation,
408 int df,
409 VectorRegister wt,
410 VectorRegister ws,
411 VectorRegister wd,
412 int minor_opcode) {
413 CHECK_NE(wt, kNoVectorRegister);
414 CHECK_NE(ws, kNoVectorRegister);
415 CHECK_NE(wd, kNoVectorRegister);
416 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
417 operation << kMsaOperationShift |
418 df << kDfShift |
419 static_cast<uint32_t>(wt) << kWtShift |
420 static_cast<uint32_t>(ws) << kWsShift |
421 static_cast<uint32_t>(wd) << kWdShift |
422 minor_opcode;
423 Emit(encoding);
424 return encoding;
425}
426
427uint32_t MipsAssembler::EmitMsaBIT(int operation,
428 int df_m,
429 VectorRegister ws,
430 VectorRegister wd,
431 int minor_opcode) {
432 CHECK_NE(ws, kNoVectorRegister);
433 CHECK_NE(wd, kNoVectorRegister);
434 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
435 operation << kMsaOperationShift |
436 df_m << kDfMShift |
437 static_cast<uint32_t>(ws) << kWsShift |
438 static_cast<uint32_t>(wd) << kWdShift |
439 minor_opcode;
440 Emit(encoding);
441 return encoding;
442}
443
444uint32_t MipsAssembler::EmitMsaELM(int operation,
445 int df_n,
446 VectorRegister ws,
447 VectorRegister wd,
448 int minor_opcode) {
449 CHECK_NE(ws, kNoVectorRegister);
450 CHECK_NE(wd, kNoVectorRegister);
451 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
452 operation << kMsaELMOperationShift |
453 df_n << kDfNShift |
454 static_cast<uint32_t>(ws) << kWsShift |
455 static_cast<uint32_t>(wd) << kWdShift |
456 minor_opcode;
457 Emit(encoding);
458 return encoding;
459}
460
461uint32_t MipsAssembler::EmitMsaMI10(int s10,
462 Register rs,
463 VectorRegister wd,
464 int minor_opcode,
465 int df) {
466 CHECK_NE(rs, kNoRegister);
467 CHECK_NE(wd, kNoVectorRegister);
468 CHECK(IsUint<10>(s10)) << s10;
469 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
470 s10 << kS10Shift |
471 static_cast<uint32_t>(rs) << kWsShift |
472 static_cast<uint32_t>(wd) << kWdShift |
473 minor_opcode << kS10MinorShift |
474 df;
475 Emit(encoding);
476 return encoding;
477}
478
479uint32_t MipsAssembler::EmitMsaI10(int operation,
480 int df,
481 int i10,
482 VectorRegister wd,
483 int minor_opcode) {
484 CHECK_NE(wd, kNoVectorRegister);
485 CHECK(IsUint<10>(i10)) << i10;
486 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
487 operation << kMsaOperationShift |
488 df << kDfShift |
489 i10 << kI10Shift |
490 static_cast<uint32_t>(wd) << kWdShift |
491 minor_opcode;
492 Emit(encoding);
493 return encoding;
494}
495
496uint32_t MipsAssembler::EmitMsa2R(int operation,
497 int df,
498 VectorRegister ws,
499 VectorRegister wd,
500 int minor_opcode) {
501 CHECK_NE(ws, kNoVectorRegister);
502 CHECK_NE(wd, kNoVectorRegister);
503 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
504 operation << kMsa2ROperationShift |
505 df << kDf2RShift |
506 static_cast<uint32_t>(ws) << kWsShift |
507 static_cast<uint32_t>(wd) << kWdShift |
508 minor_opcode;
509 Emit(encoding);
510 return encoding;
511}
512
513uint32_t MipsAssembler::EmitMsa2RF(int operation,
514 int df,
515 VectorRegister ws,
516 VectorRegister wd,
517 int minor_opcode) {
518 CHECK_NE(ws, kNoVectorRegister);
519 CHECK_NE(wd, kNoVectorRegister);
520 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
521 operation << kMsa2RFOperationShift |
522 df << kDf2RShift |
523 static_cast<uint32_t>(ws) << kWsShift |
524 static_cast<uint32_t>(wd) << kWdShift |
525 minor_opcode;
526 Emit(encoding);
527 return encoding;
528}
529
jeffhao7fbee072012-08-24 17:56:54 -0700530void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700531 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700532}
533
jeffhao7fbee072012-08-24 17:56:54 -0700534void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700535 DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700536}
537
jeffhao7fbee072012-08-24 17:56:54 -0700538void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700539 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700540}
541
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200542void MipsAssembler::MultR2(Register rs, Register rt) {
543 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700544 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700545}
546
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200547void MipsAssembler::MultuR2(Register rs, Register rt) {
548 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700549 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700550}
551
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200552void MipsAssembler::DivR2(Register rs, Register rt) {
553 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700554 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700555}
556
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200557void MipsAssembler::DivuR2(Register rs, Register rt) {
558 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700559 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700560}
561
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200562void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
563 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700564 DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200565}
566
567void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
568 CHECK(!IsR6());
569 DivR2(rs, rt);
570 Mflo(rd);
571}
572
573void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
574 CHECK(!IsR6());
575 DivR2(rs, rt);
576 Mfhi(rd);
577}
578
579void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
580 CHECK(!IsR6());
581 DivuR2(rs, rt);
582 Mflo(rd);
583}
584
585void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
586 CHECK(!IsR6());
587 DivuR2(rs, rt);
588 Mfhi(rd);
589}
590
591void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
592 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700593 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200594}
595
Alexey Frunze7e99e052015-11-24 19:28:01 -0800596void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
597 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700598 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt);
Alexey Frunze7e99e052015-11-24 19:28:01 -0800599}
600
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200601void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
602 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700603 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200604}
605
606void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
607 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700608 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200609}
610
611void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
612 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700613 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200614}
615
616void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
617 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700618 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200619}
620
621void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
622 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700623 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200624}
625
jeffhao7fbee072012-08-24 17:56:54 -0700626void MipsAssembler::And(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700627 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700628}
629
630void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700631 DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700632}
633
634void MipsAssembler::Or(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700635 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700636}
637
638void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700639 DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700640}
641
642void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700643 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700644}
645
646void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700647 DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700648}
649
650void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700651 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700652}
653
Chris Larsene3845472015-11-18 12:27:15 -0800654void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
655 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700656 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800657}
658
659void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
660 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700661 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800662}
663
664void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
665 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700666 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800667}
668
669void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
670 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700671 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800672}
673
674void MipsAssembler::ClzR6(Register rd, Register rs) {
675 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700676 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800677}
678
679void MipsAssembler::ClzR2(Register rd, Register rs) {
680 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700681 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800682}
683
684void MipsAssembler::CloR6(Register rd, Register rs) {
685 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700686 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800687}
688
689void MipsAssembler::CloR2(Register rd, Register rs) {
690 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700691 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs);
Chris Larsene3845472015-11-18 12:27:15 -0800692}
693
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200694void MipsAssembler::Seb(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700695 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700696}
697
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200698void MipsAssembler::Seh(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700699 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700700}
701
Chris Larsen3f8bf652015-10-28 10:08:56 -0700702void MipsAssembler::Wsbh(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700703 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700704}
705
Chris Larsen70014c82015-11-18 12:26:08 -0800706void MipsAssembler::Bitswap(Register rd, Register rt) {
707 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700708 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt);
Chris Larsen70014c82015-11-18 12:26:08 -0800709}
710
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200711void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700712 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700713 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700714}
715
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200716void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700717 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700718 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200719}
720
Chris Larsen3f8bf652015-10-28 10:08:56 -0700721void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
722 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700723 DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700724}
725
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200726void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700727 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700728 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200729}
730
731void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700732 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700733}
734
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200735void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700736 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700737}
738
Chris Larsene16ce5a2015-11-18 12:30:20 -0800739void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700740 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt);
Chris Larsene16ce5a2015-11-18 12:30:20 -0800741}
742
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200743void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700744 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700745}
746
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800747void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
748 CHECK(IsUint<5>(pos)) << pos;
749 CHECK(0 < size && size <= 32) << size;
750 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700751 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800752}
753
754void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
755 CHECK(IsUint<5>(pos)) << pos;
756 CHECK(0 < size && size <= 32) << size;
757 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700758 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800759}
760
Chris Larsen692235e2016-11-21 16:04:53 -0800761void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
Lena Djokic0758ae72017-05-23 11:06:23 +0200762 CHECK(IsR6() || HasMsa());
Chris Larsen692235e2016-11-21 16:04:53 -0800763 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
764 int sa = saPlusOne - 1;
765 DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
766}
767
Chris Larsencd0295d2017-03-31 15:26:54 -0700768void MipsAssembler::ShiftAndAdd(Register dst,
769 Register src_idx,
770 Register src_base,
771 int shamt,
772 Register tmp) {
773 CHECK(0 <= shamt && shamt <= 4) << shamt;
774 CHECK_NE(src_base, tmp);
775 if (shamt == TIMES_1) {
776 // Catch the special case where the shift amount is zero (0).
777 Addu(dst, src_base, src_idx);
Lena Djokic0758ae72017-05-23 11:06:23 +0200778 } else if (IsR6() || HasMsa()) {
Chris Larsencd0295d2017-03-31 15:26:54 -0700779 Lsa(dst, src_idx, src_base, shamt);
780 } else {
781 Sll(tmp, src_idx, shamt);
782 Addu(dst, src_base, tmp);
783 }
784}
785
jeffhao7fbee072012-08-24 17:56:54 -0700786void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700787 DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700788}
789
790void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700791 DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700792}
793
794void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700795 DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700796}
797
Chris Larsen3acee732015-11-18 13:31:08 -0800798void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
799 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700800 DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800801}
802
803void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
804 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700805 DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800806}
807
jeffhao7fbee072012-08-24 17:56:54 -0700808void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700809 DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700810}
811
812void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700813 DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700814}
815
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700816void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
817 CHECK(IsR6());
818 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700819 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700820}
821
jeffhao7fbee072012-08-24 17:56:54 -0700822void MipsAssembler::Lui(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700823 DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700824}
825
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700826void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
827 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700828 DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700829}
830
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700831void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) {
832 bool increment = (rs == rt);
833 if (increment) {
834 CHECK_NE(rs, tmp);
835 }
836 if (IsR6()) {
837 Aui(rt, rs, imm16);
838 } else if (increment) {
839 Lui(tmp, imm16);
840 Addu(rt, rs, tmp);
841 } else {
842 Lui(rt, imm16);
843 Addu(rt, rs, rt);
844 }
845}
846
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200847void MipsAssembler::Sync(uint32_t stype) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700848 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200849}
850
jeffhao7fbee072012-08-24 17:56:54 -0700851void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200852 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700853 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700854}
855
856void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200857 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700858 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -0700859}
860
861void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700862 DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700863}
864
865void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700866 DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700867}
868
869void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700870 DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700871}
872
Chris Larsen3acee732015-11-18 13:31:08 -0800873void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
874 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700875 DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800876}
877
878void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
879 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700880 DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800881}
882
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700883void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
884 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700885 DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700886}
887
888void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
889 CHECK(!IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700890 DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700891}
892
893void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
894 CHECK(IsR6());
895 CHECK(IsInt<9>(imm9));
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700896 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700897}
898
899void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
900 CHECK(IsR6());
901 CHECK(IsInt<9>(imm9));
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700902 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700903}
904
jeffhao7fbee072012-08-24 17:56:54 -0700905void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700906 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700907}
908
909void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700910 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700911}
912
913void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700914 DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700915}
916
917void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700918 DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700919}
920
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200921void MipsAssembler::B(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700922 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200923}
924
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700925void MipsAssembler::Bal(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700926 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700927}
928
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200929void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700930 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700931}
932
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200933void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700934 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700935}
936
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200937void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700938 Beq(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700939}
940
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200941void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700942 Bne(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700943}
944
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200945void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700946 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200947}
948
949void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700950 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200951}
952
953void MipsAssembler::Blez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700954 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200955}
956
957void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700958 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200959}
960
Chris Larsenb74353a2015-11-20 09:07:09 -0800961void MipsAssembler::Bc1f(uint16_t imm16) {
962 Bc1f(0, imm16);
963}
964
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800965void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
966 CHECK(!IsR6());
967 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700968 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800969}
970
Chris Larsenb74353a2015-11-20 09:07:09 -0800971void MipsAssembler::Bc1t(uint16_t imm16) {
972 Bc1t(0, imm16);
973}
974
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800975void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
976 CHECK(!IsR6());
977 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700978 DsFsmInstrNop(EmitI(0x11,
979 static_cast<Register>(0x8),
980 static_cast<Register>((cc << 2) | 1),
981 imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800982}
983
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200984void MipsAssembler::J(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700985 DsFsmInstrNop(EmitI26(0x2, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200986}
987
988void MipsAssembler::Jal(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700989 DsFsmInstrNop(EmitI26(0x3, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200990}
991
992void MipsAssembler::Jalr(Register rd, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700993 uint32_t last_instruction = delay_slot_.instruction_;
994 bool exchange = (last_instruction != 0 &&
995 (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 &&
996 ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0);
997 if (exchange) {
998 // The last instruction cannot be used in a different delay slot,
999 // do not commit the label before it (if any).
1000 DsFsmDropLabel();
1001 }
1002 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09));
1003 if (exchange) {
1004 // Exchange the last two instructions in the assembler buffer.
1005 size_t size = buffer_.Size();
1006 CHECK_GE(size, 2 * sizeof(uint32_t));
1007 size_t pos1 = size - 2 * sizeof(uint32_t);
1008 size_t pos2 = size - sizeof(uint32_t);
1009 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
1010 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
1011 CHECK_EQ(instr1, last_instruction);
1012 buffer_.Store<uint32_t>(pos1, instr2);
1013 buffer_.Store<uint32_t>(pos2, instr1);
1014 } else if (reordering_) {
1015 Nop();
1016 }
jeffhao7fbee072012-08-24 17:56:54 -07001017}
1018
1019void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001020 Jalr(RA, rs);
1021}
1022
1023void MipsAssembler::Jr(Register rs) {
1024 Jalr(ZERO, rs);
1025}
1026
1027void MipsAssembler::Nal() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001028 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001029}
1030
1031void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
1032 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001033 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001034}
1035
1036void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
1037 CHECK(IsR6());
1038 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001039 DsFsmInstrNop(EmitI21(0x3B, rs, imm19));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001040}
1041
1042void MipsAssembler::Bc(uint32_t imm26) {
1043 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001044 DsFsmInstrNop(EmitI26(0x32, imm26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001045}
1046
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001047void MipsAssembler::Balc(uint32_t imm26) {
1048 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001049 DsFsmInstrNop(EmitI26(0x3A, imm26));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001050}
1051
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001052void MipsAssembler::Jic(Register rt, uint16_t imm16) {
1053 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001054 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001055}
1056
1057void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
1058 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001059 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001060}
1061
1062void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
1063 CHECK(IsR6());
1064 CHECK_NE(rs, ZERO);
1065 CHECK_NE(rt, ZERO);
1066 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001067 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001068}
1069
1070void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
1071 CHECK(IsR6());
1072 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001073 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001074}
1075
1076void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
1077 CHECK(IsR6());
1078 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001079 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001080}
1081
1082void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
1083 CHECK(IsR6());
1084 CHECK_NE(rs, ZERO);
1085 CHECK_NE(rt, ZERO);
1086 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001087 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001088}
1089
1090void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
1091 CHECK(IsR6());
1092 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001093 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001094}
1095
1096void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
1097 CHECK(IsR6());
1098 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001099 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001100}
1101
1102void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
1103 CHECK(IsR6());
1104 CHECK_NE(rs, ZERO);
1105 CHECK_NE(rt, ZERO);
1106 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001107 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001108}
1109
1110void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
1111 CHECK(IsR6());
1112 CHECK_NE(rs, ZERO);
1113 CHECK_NE(rt, ZERO);
1114 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001115 DsFsmInstrNop(EmitI(0x6, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001116}
1117
1118void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
1119 CHECK(IsR6());
1120 CHECK_NE(rs, ZERO);
1121 CHECK_NE(rt, ZERO);
1122 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001123 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001124}
1125
1126void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
1127 CHECK(IsR6());
1128 CHECK_NE(rs, ZERO);
1129 CHECK_NE(rt, ZERO);
1130 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001131 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001132}
1133
1134void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
1135 CHECK(IsR6());
1136 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001137 DsFsmInstrNop(EmitI21(0x36, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001138}
1139
1140void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
1141 CHECK(IsR6());
1142 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001143 DsFsmInstrNop(EmitI21(0x3E, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001144}
1145
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001146void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
1147 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001148 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001149}
1150
1151void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
1152 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001153 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001154}
1155
1156void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001157 switch (cond) {
1158 case kCondLTZ:
1159 CHECK_EQ(rt, ZERO);
1160 Bltz(rs, imm16);
1161 break;
1162 case kCondGEZ:
1163 CHECK_EQ(rt, ZERO);
1164 Bgez(rs, imm16);
1165 break;
1166 case kCondLEZ:
1167 CHECK_EQ(rt, ZERO);
1168 Blez(rs, imm16);
1169 break;
1170 case kCondGTZ:
1171 CHECK_EQ(rt, ZERO);
1172 Bgtz(rs, imm16);
1173 break;
1174 case kCondEQ:
1175 Beq(rs, rt, imm16);
1176 break;
1177 case kCondNE:
1178 Bne(rs, rt, imm16);
1179 break;
1180 case kCondEQZ:
1181 CHECK_EQ(rt, ZERO);
1182 Beqz(rs, imm16);
1183 break;
1184 case kCondNEZ:
1185 CHECK_EQ(rt, ZERO);
1186 Bnez(rs, imm16);
1187 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001188 case kCondF:
1189 CHECK_EQ(rt, ZERO);
1190 Bc1f(static_cast<int>(rs), imm16);
1191 break;
1192 case kCondT:
1193 CHECK_EQ(rt, ZERO);
1194 Bc1t(static_cast<int>(rs), imm16);
1195 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001196 case kCondLT:
1197 case kCondGE:
1198 case kCondLE:
1199 case kCondGT:
1200 case kCondLTU:
1201 case kCondGEU:
1202 case kUncond:
1203 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1204 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1205 LOG(FATAL) << "Unexpected branch condition " << cond;
1206 UNREACHABLE();
1207 }
1208}
1209
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001210void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001211 switch (cond) {
1212 case kCondLT:
1213 Bltc(rs, rt, imm16_21);
1214 break;
1215 case kCondGE:
1216 Bgec(rs, rt, imm16_21);
1217 break;
1218 case kCondLE:
1219 Bgec(rt, rs, imm16_21);
1220 break;
1221 case kCondGT:
1222 Bltc(rt, rs, imm16_21);
1223 break;
1224 case kCondLTZ:
1225 CHECK_EQ(rt, ZERO);
1226 Bltzc(rs, imm16_21);
1227 break;
1228 case kCondGEZ:
1229 CHECK_EQ(rt, ZERO);
1230 Bgezc(rs, imm16_21);
1231 break;
1232 case kCondLEZ:
1233 CHECK_EQ(rt, ZERO);
1234 Blezc(rs, imm16_21);
1235 break;
1236 case kCondGTZ:
1237 CHECK_EQ(rt, ZERO);
1238 Bgtzc(rs, imm16_21);
1239 break;
1240 case kCondEQ:
1241 Beqc(rs, rt, imm16_21);
1242 break;
1243 case kCondNE:
1244 Bnec(rs, rt, imm16_21);
1245 break;
1246 case kCondEQZ:
1247 CHECK_EQ(rt, ZERO);
1248 Beqzc(rs, imm16_21);
1249 break;
1250 case kCondNEZ:
1251 CHECK_EQ(rt, ZERO);
1252 Bnezc(rs, imm16_21);
1253 break;
1254 case kCondLTU:
1255 Bltuc(rs, rt, imm16_21);
1256 break;
1257 case kCondGEU:
1258 Bgeuc(rs, rt, imm16_21);
1259 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001260 case kCondF:
1261 CHECK_EQ(rt, ZERO);
1262 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
1263 break;
1264 case kCondT:
1265 CHECK_EQ(rt, ZERO);
1266 Bc1nez(static_cast<FRegister>(rs), imm16_21);
1267 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001268 case kUncond:
1269 LOG(FATAL) << "Unexpected branch condition " << cond;
1270 UNREACHABLE();
1271 }
jeffhao7fbee072012-08-24 17:56:54 -07001272}
1273
1274void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001275 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001276}
1277
1278void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001279 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001280}
1281
1282void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001283 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001284}
1285
1286void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001287 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001288}
1289
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001290void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001291 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001292}
1293
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001294void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001295 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001296}
1297
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001298void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001299 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001300}
1301
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001302void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001303 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001304}
1305
Chris Larsenb74353a2015-11-20 09:07:09 -08001306void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001307 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001308}
1309
1310void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001311 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001312}
1313
1314void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001315 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001316}
1317
1318void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001319 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001320}
1321
jeffhao7fbee072012-08-24 17:56:54 -07001322void MipsAssembler::MovS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001323 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
jeffhao7fbee072012-08-24 17:56:54 -07001324}
1325
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001326void MipsAssembler::MovD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001327 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001328}
1329
1330void MipsAssembler::NegS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001331 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001332}
1333
1334void MipsAssembler::NegD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001335 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001336}
1337
Chris Larsenb74353a2015-11-20 09:07:09 -08001338void MipsAssembler::CunS(FRegister fs, FRegister ft) {
1339 CunS(0, fs, ft);
1340}
1341
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001342void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
1343 CHECK(!IsR6());
1344 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001345 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001346}
1347
Chris Larsenb74353a2015-11-20 09:07:09 -08001348void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
1349 CeqS(0, fs, ft);
1350}
1351
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001352void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
1353 CHECK(!IsR6());
1354 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001355 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001356}
1357
Chris Larsenb74353a2015-11-20 09:07:09 -08001358void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
1359 CueqS(0, fs, ft);
1360}
1361
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001362void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
1363 CHECK(!IsR6());
1364 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001365 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001366}
1367
Chris Larsenb74353a2015-11-20 09:07:09 -08001368void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
1369 ColtS(0, fs, ft);
1370}
1371
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001372void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
1373 CHECK(!IsR6());
1374 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001375 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001376}
1377
Chris Larsenb74353a2015-11-20 09:07:09 -08001378void MipsAssembler::CultS(FRegister fs, FRegister ft) {
1379 CultS(0, fs, ft);
1380}
1381
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001382void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
1383 CHECK(!IsR6());
1384 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001385 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001386}
1387
Chris Larsenb74353a2015-11-20 09:07:09 -08001388void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
1389 ColeS(0, fs, ft);
1390}
1391
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001392void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
1393 CHECK(!IsR6());
1394 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001395 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001396}
1397
Chris Larsenb74353a2015-11-20 09:07:09 -08001398void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
1399 CuleS(0, fs, ft);
1400}
1401
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001402void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
1403 CHECK(!IsR6());
1404 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001405 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001406}
1407
Chris Larsenb74353a2015-11-20 09:07:09 -08001408void MipsAssembler::CunD(FRegister fs, FRegister ft) {
1409 CunD(0, fs, ft);
1410}
1411
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001412void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
1413 CHECK(!IsR6());
1414 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001415 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001416}
1417
Chris Larsenb74353a2015-11-20 09:07:09 -08001418void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
1419 CeqD(0, fs, ft);
1420}
1421
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001422void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
1423 CHECK(!IsR6());
1424 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001425 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001426}
1427
Chris Larsenb74353a2015-11-20 09:07:09 -08001428void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
1429 CueqD(0, fs, ft);
1430}
1431
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001432void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1433 CHECK(!IsR6());
1434 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001435 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001436}
1437
Chris Larsenb74353a2015-11-20 09:07:09 -08001438void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1439 ColtD(0, fs, ft);
1440}
1441
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001442void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1443 CHECK(!IsR6());
1444 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001445 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001446}
1447
Chris Larsenb74353a2015-11-20 09:07:09 -08001448void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1449 CultD(0, fs, ft);
1450}
1451
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001452void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1453 CHECK(!IsR6());
1454 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001455 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001456}
1457
Chris Larsenb74353a2015-11-20 09:07:09 -08001458void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1459 ColeD(0, fs, ft);
1460}
1461
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001462void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1463 CHECK(!IsR6());
1464 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001465 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001466}
1467
Chris Larsenb74353a2015-11-20 09:07:09 -08001468void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1469 CuleD(0, fs, ft);
1470}
1471
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001472void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1473 CHECK(!IsR6());
1474 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001475 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001476}
1477
1478void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1479 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001480 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001481}
1482
1483void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1484 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001485 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001486}
1487
1488void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1489 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001490 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001491}
1492
1493void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1494 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001495 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001496}
1497
1498void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1499 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001500 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001501}
1502
1503void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1504 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001505 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001506}
1507
1508void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1509 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001510 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001511}
1512
1513void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1514 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001515 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001516}
1517
1518void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1519 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001520 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001521}
1522
1523void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1524 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001525 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001526}
1527
1528void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1529 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001530 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001531}
1532
1533void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1534 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001535 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001536}
1537
1538void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1539 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001540 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001541}
1542
1543void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1544 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001545 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001546}
1547
1548void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1549 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001550 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001551}
1552
1553void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1554 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001555 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001556}
1557
1558void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1559 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001560 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001561}
1562
1563void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1564 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001565 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001566}
1567
1568void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1569 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001570 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001571}
1572
1573void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1574 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001575 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001576}
1577
1578void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1579 CHECK(!IsR6());
1580 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001581 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001582}
1583
1584void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1585 CHECK(!IsR6());
1586 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001587 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001588}
1589
Chris Larsenb74353a2015-11-20 09:07:09 -08001590void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1591 CHECK(!IsR6());
1592 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001593 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001594}
1595
1596void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1597 CHECK(!IsR6());
1598 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001599 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001600}
1601
1602void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1603 CHECK(!IsR6());
1604 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001605 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1606 fd,
1607 fs,
1608 cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001609}
1610
1611void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1612 CHECK(!IsR6());
1613 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001614 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1615 fd,
1616 fs,
1617 cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001618}
1619
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001620void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
1621 CHECK(!IsR6());
1622 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1623}
1624
1625void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
1626 CHECK(!IsR6());
1627 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1628}
1629
1630void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
1631 CHECK(!IsR6());
1632 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1633}
1634
1635void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
1636 CHECK(!IsR6());
1637 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1638}
1639
Chris Larsenb74353a2015-11-20 09:07:09 -08001640void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1641 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001642 DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001643}
1644
1645void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1646 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001647 DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001648}
1649
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001650void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
1651 CHECK(IsR6());
1652 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft);
1653}
1654
1655void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
1656 CHECK(IsR6());
1657 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft);
1658}
1659
1660void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
1661 CHECK(IsR6());
1662 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft);
1663}
1664
1665void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
1666 CHECK(IsR6());
1667 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft);
1668}
1669
Chris Larsenb74353a2015-11-20 09:07:09 -08001670void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1671 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001672 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001673}
1674
1675void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1676 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001677 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001678}
1679
1680void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1681 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001682 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001683}
1684
1685void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1686 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001687 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001688}
1689
1690void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1691 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001692 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001693}
1694
1695void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1696 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001697 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001698}
1699
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001700void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001701 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001702}
1703
1704void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001705 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001706}
1707
1708void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001709 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001710}
1711
1712void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001713 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001714}
1715
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001716void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001717 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001718}
1719
1720void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001721 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001722}
1723
1724void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001725 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001726}
1727
1728void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001729 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
jeffhao7fbee072012-08-24 17:56:54 -07001730}
1731
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001732void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001733 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001734}
1735
1736void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001737 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001738}
1739
Chris Larsenb74353a2015-11-20 09:07:09 -08001740void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001741 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001742}
1743
1744void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001745 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001746}
1747
jeffhao7fbee072012-08-24 17:56:54 -07001748void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001749 DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1750 rt,
1751 fs);
jeffhao7fbee072012-08-24 17:56:54 -07001752}
1753
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001754void MipsAssembler::Mtc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001755 DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1756 fs,
1757 rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001758}
1759
1760void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001761 DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1762 rt,
1763 fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001764}
1765
1766void MipsAssembler::Mthc1(Register rt, FRegister fs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001767 DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1768 fs,
1769 rt);
jeffhao7fbee072012-08-24 17:56:54 -07001770}
1771
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001772void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1773 if (Is32BitFPU()) {
1774 CHECK_EQ(fs % 2, 0) << fs;
1775 Mfc1(rt, static_cast<FRegister>(fs + 1));
1776 } else {
1777 Mfhc1(rt, fs);
1778 }
1779}
1780
1781void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1782 if (Is32BitFPU()) {
1783 CHECK_EQ(fs % 2, 0) << fs;
1784 Mtc1(rt, static_cast<FRegister>(fs + 1));
1785 } else {
1786 Mthc1(rt, fs);
1787 }
1788}
1789
jeffhao7fbee072012-08-24 17:56:54 -07001790void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001791 DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001792}
1793
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001794void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001795 DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001796}
1797
1798void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001799 DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001800}
1801
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001802void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001803 DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs);
jeffhao7fbee072012-08-24 17:56:54 -07001804}
1805
1806void MipsAssembler::Break() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001807 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD));
jeffhao7fbee072012-08-24 17:56:54 -07001808}
1809
jeffhao07030602012-09-26 14:33:14 -07001810void MipsAssembler::Nop() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001811 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0));
1812}
1813
1814void MipsAssembler::NopIfNoReordering() {
1815 if (!reordering_) {
1816 Nop();
1817 }
jeffhao07030602012-09-26 14:33:14 -07001818}
1819
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001820void MipsAssembler::Move(Register rd, Register rs) {
1821 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001822}
1823
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001824void MipsAssembler::Clear(Register rd) {
1825 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001826}
1827
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001828void MipsAssembler::Not(Register rd, Register rs) {
1829 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001830}
1831
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001832void MipsAssembler::Push(Register rs) {
1833 IncreaseFrameSize(kMipsWordSize);
1834 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001835}
1836
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001837void MipsAssembler::Pop(Register rd) {
1838 Lw(rd, SP, 0);
1839 DecreaseFrameSize(kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07001840}
1841
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001842void MipsAssembler::PopAndReturn(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001843 bool reordering = SetReorder(false);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001844 Lw(rd, SP, 0);
1845 Jr(rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001846 DecreaseFrameSize(kMipsWordSize); // Single instruction in delay slot.
1847 SetReorder(reordering);
jeffhao7fbee072012-08-24 17:56:54 -07001848}
1849
Lena Djokic0758ae72017-05-23 11:06:23 +02001850void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1851 CHECK(HasMsa());
1852 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e),
1853 static_cast<FRegister>(wd),
1854 static_cast<FRegister>(ws),
1855 static_cast<FRegister>(wt));
1856}
1857
1858void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1859 CHECK(HasMsa());
1860 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e),
1861 static_cast<FRegister>(wd),
1862 static_cast<FRegister>(ws),
1863 static_cast<FRegister>(wt));
1864}
1865
1866void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1867 CHECK(HasMsa());
1868 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e),
1869 static_cast<FRegister>(wd),
1870 static_cast<FRegister>(ws),
1871 static_cast<FRegister>(wt));
1872}
1873
1874void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1875 CHECK(HasMsa());
1876 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e),
1877 static_cast<FRegister>(wd),
1878 static_cast<FRegister>(ws),
1879 static_cast<FRegister>(wt));
1880}
1881
1882void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1883 CHECK(HasMsa());
1884 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe),
1885 static_cast<FRegister>(wd),
1886 static_cast<FRegister>(ws),
1887 static_cast<FRegister>(wt));
1888}
1889
1890void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1891 CHECK(HasMsa());
1892 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe),
1893 static_cast<FRegister>(wd),
1894 static_cast<FRegister>(ws),
1895 static_cast<FRegister>(wt));
1896}
1897
1898void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1899 CHECK(HasMsa());
1900 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe),
1901 static_cast<FRegister>(wd),
1902 static_cast<FRegister>(ws),
1903 static_cast<FRegister>(wt));
1904}
1905
1906void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1907 CHECK(HasMsa());
1908 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe),
1909 static_cast<FRegister>(wd),
1910 static_cast<FRegister>(ws),
1911 static_cast<FRegister>(wt));
1912}
1913
1914void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1915 CHECK(HasMsa());
1916 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe),
1917 static_cast<FRegister>(wd),
1918 static_cast<FRegister>(ws),
1919 static_cast<FRegister>(wt));
1920}
1921
1922void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1923 CHECK(HasMsa());
1924 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe),
1925 static_cast<FRegister>(wd),
1926 static_cast<FRegister>(ws),
1927 static_cast<FRegister>(wt));
1928}
1929
1930void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1931 CHECK(HasMsa());
1932 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe),
1933 static_cast<FRegister>(wd),
1934 static_cast<FRegister>(ws),
1935 static_cast<FRegister>(wt));
1936}
1937
1938void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1939 CHECK(HasMsa());
1940 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe),
1941 static_cast<FRegister>(wd),
1942 static_cast<FRegister>(ws),
1943 static_cast<FRegister>(wt));
1944}
1945
1946void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1947 CHECK(HasMsa());
1948 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12),
1949 static_cast<FRegister>(wd),
1950 static_cast<FRegister>(ws),
1951 static_cast<FRegister>(wt));
1952}
1953
1954void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1955 CHECK(HasMsa());
1956 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12),
1957 static_cast<FRegister>(wd),
1958 static_cast<FRegister>(ws),
1959 static_cast<FRegister>(wt));
1960}
1961
1962void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1963 CHECK(HasMsa());
1964 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12),
1965 static_cast<FRegister>(wd),
1966 static_cast<FRegister>(ws),
1967 static_cast<FRegister>(wt));
1968}
1969
1970void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1971 CHECK(HasMsa());
1972 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12),
1973 static_cast<FRegister>(wd),
1974 static_cast<FRegister>(ws),
1975 static_cast<FRegister>(wt));
1976}
1977
1978void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1979 CHECK(HasMsa());
1980 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12),
1981 static_cast<FRegister>(wd),
1982 static_cast<FRegister>(ws),
1983 static_cast<FRegister>(wt));
1984}
1985
1986void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1987 CHECK(HasMsa());
1988 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12),
1989 static_cast<FRegister>(wd),
1990 static_cast<FRegister>(ws),
1991 static_cast<FRegister>(wt));
1992}
1993
1994void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1995 CHECK(HasMsa());
1996 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12),
1997 static_cast<FRegister>(wd),
1998 static_cast<FRegister>(ws),
1999 static_cast<FRegister>(wt));
2000}
2001
2002void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2003 CHECK(HasMsa());
2004 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12),
2005 static_cast<FRegister>(wd),
2006 static_cast<FRegister>(ws),
2007 static_cast<FRegister>(wt));
2008}
2009
2010void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2011 CHECK(HasMsa());
2012 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12),
2013 static_cast<FRegister>(wd),
2014 static_cast<FRegister>(ws),
2015 static_cast<FRegister>(wt));
2016}
2017
2018void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2019 CHECK(HasMsa());
2020 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12),
2021 static_cast<FRegister>(wd),
2022 static_cast<FRegister>(ws),
2023 static_cast<FRegister>(wt));
2024}
2025
2026void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2027 CHECK(HasMsa());
2028 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12),
2029 static_cast<FRegister>(wd),
2030 static_cast<FRegister>(ws),
2031 static_cast<FRegister>(wt));
2032}
2033
2034void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2035 CHECK(HasMsa());
2036 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12),
2037 static_cast<FRegister>(wd),
2038 static_cast<FRegister>(ws),
2039 static_cast<FRegister>(wt));
2040}
2041
2042void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2043 CHECK(HasMsa());
2044 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12),
2045 static_cast<FRegister>(wd),
2046 static_cast<FRegister>(ws),
2047 static_cast<FRegister>(wt));
2048}
2049
2050void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2051 CHECK(HasMsa());
2052 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12),
2053 static_cast<FRegister>(wd),
2054 static_cast<FRegister>(ws),
2055 static_cast<FRegister>(wt));
2056}
2057
2058void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2059 CHECK(HasMsa());
2060 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12),
2061 static_cast<FRegister>(wd),
2062 static_cast<FRegister>(ws),
2063 static_cast<FRegister>(wt));
2064}
2065
2066void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2067 CHECK(HasMsa());
2068 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12),
2069 static_cast<FRegister>(wd),
2070 static_cast<FRegister>(ws),
2071 static_cast<FRegister>(wt));
2072}
2073
2074void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2075 CHECK(HasMsa());
2076 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12),
2077 static_cast<FRegister>(wd),
2078 static_cast<FRegister>(ws),
2079 static_cast<FRegister>(wt));
2080}
2081
2082void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2083 CHECK(HasMsa());
2084 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12),
2085 static_cast<FRegister>(wd),
2086 static_cast<FRegister>(ws),
2087 static_cast<FRegister>(wt));
2088}
2089
2090void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2091 CHECK(HasMsa());
2092 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12),
2093 static_cast<FRegister>(wd),
2094 static_cast<FRegister>(ws),
2095 static_cast<FRegister>(wt));
2096}
2097
2098void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2099 CHECK(HasMsa());
2100 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12),
2101 static_cast<FRegister>(wd),
2102 static_cast<FRegister>(ws),
2103 static_cast<FRegister>(wt));
2104}
2105
2106void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2107 CHECK(HasMsa());
2108 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10),
2109 static_cast<FRegister>(wd),
2110 static_cast<FRegister>(ws),
2111 static_cast<FRegister>(wt));
2112}
2113
2114void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2115 CHECK(HasMsa());
2116 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10),
2117 static_cast<FRegister>(wd),
2118 static_cast<FRegister>(ws),
2119 static_cast<FRegister>(wt));
2120}
2121
2122void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2123 CHECK(HasMsa());
2124 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10),
2125 static_cast<FRegister>(wd),
2126 static_cast<FRegister>(ws),
2127 static_cast<FRegister>(wt));
2128}
2129
2130void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2131 CHECK(HasMsa());
2132 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10),
2133 static_cast<FRegister>(wd),
2134 static_cast<FRegister>(ws),
2135 static_cast<FRegister>(wt));
2136}
2137
2138void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2139 CHECK(HasMsa());
2140 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10),
2141 static_cast<FRegister>(wd),
2142 static_cast<FRegister>(ws),
2143 static_cast<FRegister>(wt));
2144}
2145
2146void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2147 CHECK(HasMsa());
2148 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10),
2149 static_cast<FRegister>(wd),
2150 static_cast<FRegister>(ws),
2151 static_cast<FRegister>(wt));
2152}
2153
2154void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2155 CHECK(HasMsa());
2156 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10),
2157 static_cast<FRegister>(wd),
2158 static_cast<FRegister>(ws),
2159 static_cast<FRegister>(wt));
2160}
2161
2162void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2163 CHECK(HasMsa());
2164 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10),
2165 static_cast<FRegister>(wd),
2166 static_cast<FRegister>(ws),
2167 static_cast<FRegister>(wt));
2168}
2169
2170void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2171 CHECK(HasMsa());
2172 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10),
2173 static_cast<FRegister>(wd),
2174 static_cast<FRegister>(ws),
2175 static_cast<FRegister>(wt));
2176}
2177
2178void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2179 CHECK(HasMsa());
2180 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10),
2181 static_cast<FRegister>(wd),
2182 static_cast<FRegister>(ws),
2183 static_cast<FRegister>(wt));
2184}
2185
2186void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2187 CHECK(HasMsa());
2188 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10),
2189 static_cast<FRegister>(wd),
2190 static_cast<FRegister>(ws),
2191 static_cast<FRegister>(wt));
2192}
2193
2194void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2195 CHECK(HasMsa());
2196 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10),
2197 static_cast<FRegister>(wd),
2198 static_cast<FRegister>(ws),
2199 static_cast<FRegister>(wt));
2200}
2201
2202void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2203 CHECK(HasMsa());
2204 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10),
2205 static_cast<FRegister>(wd),
2206 static_cast<FRegister>(ws),
2207 static_cast<FRegister>(wt));
2208}
2209
2210void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2211 CHECK(HasMsa());
2212 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10),
2213 static_cast<FRegister>(wd),
2214 static_cast<FRegister>(ws),
2215 static_cast<FRegister>(wt));
2216}
2217
2218void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2219 CHECK(HasMsa());
2220 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10),
2221 static_cast<FRegister>(wd),
2222 static_cast<FRegister>(ws),
2223 static_cast<FRegister>(wt));
2224}
2225
2226void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2227 CHECK(HasMsa());
2228 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10),
2229 static_cast<FRegister>(wd),
2230 static_cast<FRegister>(ws),
2231 static_cast<FRegister>(wt));
2232}
2233
2234void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2235 CHECK(HasMsa());
2236 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10),
2237 static_cast<FRegister>(wd),
2238 static_cast<FRegister>(ws),
2239 static_cast<FRegister>(wt));
2240}
2241
2242void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2243 CHECK(HasMsa());
2244 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10),
2245 static_cast<FRegister>(wd),
2246 static_cast<FRegister>(ws),
2247 static_cast<FRegister>(wt));
2248}
2249
2250void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2251 CHECK(HasMsa());
2252 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10),
2253 static_cast<FRegister>(wd),
2254 static_cast<FRegister>(ws),
2255 static_cast<FRegister>(wt));
2256}
2257
2258void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2259 CHECK(HasMsa());
2260 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10),
2261 static_cast<FRegister>(wd),
2262 static_cast<FRegister>(ws),
2263 static_cast<FRegister>(wt));
2264}
2265
2266void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2267 CHECK(HasMsa());
2268 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe),
2269 static_cast<FRegister>(wd),
2270 static_cast<FRegister>(ws),
2271 static_cast<FRegister>(wt));
2272}
2273
2274void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2275 CHECK(HasMsa());
2276 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe),
2277 static_cast<FRegister>(wd),
2278 static_cast<FRegister>(ws),
2279 static_cast<FRegister>(wt));
2280}
2281
2282void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2283 CHECK(HasMsa());
2284 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe),
2285 static_cast<FRegister>(wd),
2286 static_cast<FRegister>(ws),
2287 static_cast<FRegister>(wt));
2288}
2289
2290void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2291 CHECK(HasMsa());
2292 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe),
2293 static_cast<FRegister>(wd),
2294 static_cast<FRegister>(ws),
2295 static_cast<FRegister>(wt));
2296}
2297
2298void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2299 CHECK(HasMsa());
2300 DsFsmInstrFff(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe),
2301 static_cast<FRegister>(wd),
2302 static_cast<FRegister>(ws),
2303 static_cast<FRegister>(wt));
2304}
2305
2306void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2307 CHECK(HasMsa());
2308 DsFsmInstrFff(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe),
2309 static_cast<FRegister>(wd),
2310 static_cast<FRegister>(ws),
2311 static_cast<FRegister>(wt));
2312}
2313
2314void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2315 CHECK(HasMsa());
2316 DsFsmInstrFff(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe),
2317 static_cast<FRegister>(wd),
2318 static_cast<FRegister>(ws),
2319 static_cast<FRegister>(wt));
2320}
2321
2322void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2323 CHECK(HasMsa());
2324 DsFsmInstrFff(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe),
2325 static_cast<FRegister>(wd),
2326 static_cast<FRegister>(ws),
2327 static_cast<FRegister>(wt));
2328}
2329
2330void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2331 CHECK(HasMsa());
2332 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe),
2333 static_cast<FRegister>(wd),
2334 static_cast<FRegister>(ws),
2335 static_cast<FRegister>(wt));
2336}
2337
2338void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2339 CHECK(HasMsa());
2340 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe),
2341 static_cast<FRegister>(wd),
2342 static_cast<FRegister>(ws),
2343 static_cast<FRegister>(wt));
2344}
2345
2346void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2347 CHECK(HasMsa());
2348 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe),
2349 static_cast<FRegister>(wd),
2350 static_cast<FRegister>(ws),
2351 static_cast<FRegister>(wt));
2352}
2353
2354void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2355 CHECK(HasMsa());
2356 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe),
2357 static_cast<FRegister>(wd),
2358 static_cast<FRegister>(ws),
2359 static_cast<FRegister>(wt));
2360}
2361
2362void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2363 CHECK(HasMsa());
2364 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe),
2365 static_cast<FRegister>(wd),
2366 static_cast<FRegister>(ws),
2367 static_cast<FRegister>(wt));
2368}
2369
2370void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2371 CHECK(HasMsa());
2372 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe),
2373 static_cast<FRegister>(wd),
2374 static_cast<FRegister>(ws),
2375 static_cast<FRegister>(wt));
2376}
2377
2378void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2379 CHECK(HasMsa());
2380 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe),
2381 static_cast<FRegister>(wd),
2382 static_cast<FRegister>(ws),
2383 static_cast<FRegister>(wt));
2384}
2385
2386void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2387 CHECK(HasMsa());
2388 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe),
2389 static_cast<FRegister>(wd),
2390 static_cast<FRegister>(ws),
2391 static_cast<FRegister>(wt));
2392}
2393
2394void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2395 CHECK(HasMsa());
2396 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b),
2397 static_cast<FRegister>(wd),
2398 static_cast<FRegister>(ws),
2399 static_cast<FRegister>(wt));
2400}
2401
2402void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2403 CHECK(HasMsa());
2404 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b),
2405 static_cast<FRegister>(wd),
2406 static_cast<FRegister>(ws),
2407 static_cast<FRegister>(wt));
2408}
2409
2410void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2411 CHECK(HasMsa());
2412 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b),
2413 static_cast<FRegister>(wd),
2414 static_cast<FRegister>(ws),
2415 static_cast<FRegister>(wt));
2416}
2417
2418void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2419 CHECK(HasMsa());
2420 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b),
2421 static_cast<FRegister>(wd),
2422 static_cast<FRegister>(ws),
2423 static_cast<FRegister>(wt));
2424}
2425
2426void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2427 CHECK(HasMsa());
2428 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b),
2429 static_cast<FRegister>(wd),
2430 static_cast<FRegister>(ws),
2431 static_cast<FRegister>(wt));
2432}
2433
2434void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2435 CHECK(HasMsa());
2436 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b),
2437 static_cast<FRegister>(wd),
2438 static_cast<FRegister>(ws),
2439 static_cast<FRegister>(wt));
2440}
2441
2442void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2443 CHECK(HasMsa());
2444 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b),
2445 static_cast<FRegister>(wd),
2446 static_cast<FRegister>(ws),
2447 static_cast<FRegister>(wt));
2448}
2449
2450void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2451 CHECK(HasMsa());
2452 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b),
2453 static_cast<FRegister>(wd),
2454 static_cast<FRegister>(ws),
2455 static_cast<FRegister>(wt));
2456}
2457
2458void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2459 CHECK(HasMsa());
2460 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b),
2461 static_cast<FRegister>(wd),
2462 static_cast<FRegister>(ws),
2463 static_cast<FRegister>(wt));
2464}
2465
2466void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2467 CHECK(HasMsa());
2468 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b),
2469 static_cast<FRegister>(wd),
2470 static_cast<FRegister>(ws),
2471 static_cast<FRegister>(wt));
2472}
2473
2474void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2475 CHECK(HasMsa());
2476 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b),
2477 static_cast<FRegister>(wd),
2478 static_cast<FRegister>(ws),
2479 static_cast<FRegister>(wt));
2480}
2481
2482void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2483 CHECK(HasMsa());
2484 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b),
2485 static_cast<FRegister>(wd),
2486 static_cast<FRegister>(ws),
2487 static_cast<FRegister>(wt));
2488}
2489
2490void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
2491 CHECK(HasMsa());
2492 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e),
2493 static_cast<FRegister>(wd),
2494 static_cast<FRegister>(ws),
2495 static_cast<FRegister>(ws));
2496}
2497
2498void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
2499 CHECK(HasMsa());
2500 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e),
2501 static_cast<FRegister>(wd),
2502 static_cast<FRegister>(ws),
2503 static_cast<FRegister>(ws));
2504}
2505
2506void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
2507 CHECK(HasMsa());
2508 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e),
2509 static_cast<FRegister>(wd),
2510 static_cast<FRegister>(ws),
2511 static_cast<FRegister>(ws));
2512}
2513
2514void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
2515 CHECK(HasMsa());
2516 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e),
2517 static_cast<FRegister>(wd),
2518 static_cast<FRegister>(ws),
2519 static_cast<FRegister>(ws));
2520}
2521
2522void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2523 CHECK(HasMsa());
2524 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd),
2525 static_cast<FRegister>(wd),
2526 static_cast<FRegister>(ws),
2527 static_cast<FRegister>(wt));
2528}
2529
2530void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2531 CHECK(HasMsa());
2532 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd),
2533 static_cast<FRegister>(wd),
2534 static_cast<FRegister>(ws),
2535 static_cast<FRegister>(wt));
2536}
2537
2538void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2539 CHECK(HasMsa());
2540 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd),
2541 static_cast<FRegister>(wd),
2542 static_cast<FRegister>(ws),
2543 static_cast<FRegister>(wt));
2544}
2545
2546void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2547 CHECK(HasMsa());
2548 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd),
2549 static_cast<FRegister>(wd),
2550 static_cast<FRegister>(ws),
2551 static_cast<FRegister>(wt));
2552}
2553
2554void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2555 CHECK(HasMsa());
2556 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd),
2557 static_cast<FRegister>(wd),
2558 static_cast<FRegister>(ws),
2559 static_cast<FRegister>(wt));
2560}
2561
2562void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2563 CHECK(HasMsa());
2564 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd),
2565 static_cast<FRegister>(wd),
2566 static_cast<FRegister>(ws),
2567 static_cast<FRegister>(wt));
2568}
2569
2570void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2571 CHECK(HasMsa());
2572 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd),
2573 static_cast<FRegister>(wd),
2574 static_cast<FRegister>(ws),
2575 static_cast<FRegister>(wt));
2576}
2577
2578void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2579 CHECK(HasMsa());
2580 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd),
2581 static_cast<FRegister>(wd),
2582 static_cast<FRegister>(ws),
2583 static_cast<FRegister>(wt));
2584}
2585
2586void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2587 CHECK(HasMsa());
2588 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd),
2589 static_cast<FRegister>(wd),
2590 static_cast<FRegister>(ws),
2591 static_cast<FRegister>(wt));
2592}
2593
2594void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2595 CHECK(HasMsa());
2596 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd),
2597 static_cast<FRegister>(wd),
2598 static_cast<FRegister>(ws),
2599 static_cast<FRegister>(wt));
2600}
2601
2602void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2603 CHECK(HasMsa());
2604 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd),
2605 static_cast<FRegister>(wd),
2606 static_cast<FRegister>(ws),
2607 static_cast<FRegister>(wt));
2608}
2609
2610void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2611 CHECK(HasMsa());
2612 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd),
2613 static_cast<FRegister>(wd),
2614 static_cast<FRegister>(ws),
2615 static_cast<FRegister>(wt));
2616}
2617
2618void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2619 CHECK(HasMsa());
2620 CHECK(IsUint<3>(shamt3)) << shamt3;
2621 DsFsmInstrFff(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2622 static_cast<FRegister>(wd),
2623 static_cast<FRegister>(ws),
2624 static_cast<FRegister>(ws));
2625}
2626
2627void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2628 CHECK(HasMsa());
2629 CHECK(IsUint<4>(shamt4)) << shamt4;
2630 DsFsmInstrFff(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2631 static_cast<FRegister>(wd),
2632 static_cast<FRegister>(ws),
2633 static_cast<FRegister>(ws));
2634}
2635
2636void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2637 CHECK(HasMsa());
2638 CHECK(IsUint<5>(shamt5)) << shamt5;
2639 DsFsmInstrFff(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2640 static_cast<FRegister>(wd),
2641 static_cast<FRegister>(ws),
2642 static_cast<FRegister>(ws));
2643}
2644
2645void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2646 CHECK(HasMsa());
2647 CHECK(IsUint<6>(shamt6)) << shamt6;
2648 DsFsmInstrFff(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2649 static_cast<FRegister>(wd),
2650 static_cast<FRegister>(ws),
2651 static_cast<FRegister>(ws));
2652}
2653
2654void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
2655 CHECK(HasMsa());
2656 CHECK(IsUint<3>(shamt3)) << shamt3;
2657 DsFsmInstrFff(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2658 static_cast<FRegister>(wd),
2659 static_cast<FRegister>(ws),
2660 static_cast<FRegister>(ws));
2661}
2662
2663void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
2664 CHECK(HasMsa());
2665 CHECK(IsUint<4>(shamt4)) << shamt4;
2666 DsFsmInstrFff(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2667 static_cast<FRegister>(wd),
2668 static_cast<FRegister>(ws),
2669 static_cast<FRegister>(ws));
2670}
2671
2672void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
2673 CHECK(HasMsa());
2674 CHECK(IsUint<5>(shamt5)) << shamt5;
2675 DsFsmInstrFff(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2676 static_cast<FRegister>(wd),
2677 static_cast<FRegister>(ws),
2678 static_cast<FRegister>(ws));
2679}
2680
2681void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
2682 CHECK(HasMsa());
2683 CHECK(IsUint<6>(shamt6)) << shamt6;
2684 DsFsmInstrFff(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2685 static_cast<FRegister>(wd),
2686 static_cast<FRegister>(ws),
2687 static_cast<FRegister>(ws));
2688}
2689
2690void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2691 CHECK(HasMsa());
2692 CHECK(IsUint<3>(shamt3)) << shamt3;
2693 DsFsmInstrFff(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2694 static_cast<FRegister>(wd),
2695 static_cast<FRegister>(ws),
2696 static_cast<FRegister>(ws));
2697}
2698
2699void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2700 CHECK(HasMsa());
2701 CHECK(IsUint<4>(shamt4)) << shamt4;
2702 DsFsmInstrFff(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2703 static_cast<FRegister>(wd),
2704 static_cast<FRegister>(ws),
2705 static_cast<FRegister>(ws));
2706}
2707
2708void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2709 CHECK(HasMsa());
2710 CHECK(IsUint<5>(shamt5)) << shamt5;
2711 DsFsmInstrFff(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2712 static_cast<FRegister>(wd),
2713 static_cast<FRegister>(ws),
2714 static_cast<FRegister>(ws));
2715}
2716
2717void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2718 CHECK(HasMsa());
2719 CHECK(IsUint<6>(shamt6)) << shamt6;
2720 DsFsmInstrFff(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2721 static_cast<FRegister>(wd),
2722 static_cast<FRegister>(ws),
2723 static_cast<FRegister>(ws));
2724}
2725
2726void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) {
2727 CHECK(HasMsa());
2728 DsFsmInstrFff(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19),
2729 static_cast<FRegister>(wd),
2730 static_cast<FRegister>(ws),
2731 static_cast<FRegister>(ws));
2732}
2733
2734void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
2735 CHECK(HasMsa());
2736 CHECK(IsUint<4>(n4)) << n4;
2737 DsFsmInstrFff(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19),
2738 static_cast<FRegister>(wd),
2739 static_cast<FRegister>(ws),
2740 static_cast<FRegister>(ws));
2741}
2742
2743void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
2744 CHECK(HasMsa());
2745 CHECK(IsUint<3>(n3)) << n3;
2746 DsFsmInstrFff(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19),
2747 static_cast<FRegister>(wd),
2748 static_cast<FRegister>(ws),
2749 static_cast<FRegister>(ws));
2750}
2751
2752void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
2753 CHECK(HasMsa());
2754 CHECK(IsUint<2>(n2)) << n2;
2755 DsFsmInstrFff(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19),
2756 static_cast<FRegister>(wd),
2757 static_cast<FRegister>(ws),
2758 static_cast<FRegister>(ws));
2759}
2760
2761void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
2762 CHECK(HasMsa());
2763 CHECK(IsUint<1>(n1)) << n1;
2764 DsFsmInstrFff(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19),
2765 static_cast<FRegister>(wd),
2766 static_cast<FRegister>(ws),
2767 static_cast<FRegister>(ws));
2768}
2769
2770void MipsAssembler::FillB(VectorRegister wd, Register rs) {
2771 CHECK(HasMsa());
2772 DsFsmInstrFr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e),
2773 static_cast<FRegister>(wd),
2774 rs);
2775}
2776
2777void MipsAssembler::FillH(VectorRegister wd, Register rs) {
2778 CHECK(HasMsa());
2779 DsFsmInstrFr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e),
2780 static_cast<FRegister>(wd),
2781 rs);
2782}
2783
2784void MipsAssembler::FillW(VectorRegister wd, Register rs) {
2785 CHECK(HasMsa());
2786 DsFsmInstrFr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e),
2787 static_cast<FRegister>(wd),
2788 rs);
2789}
2790
2791void MipsAssembler::LdiB(VectorRegister wd, int imm8) {
2792 CHECK(HasMsa());
2793 CHECK(IsInt<8>(imm8)) << imm8;
2794 DsFsmInstrFr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7),
2795 static_cast<FRegister>(wd),
2796 ZERO);
2797}
2798
2799void MipsAssembler::LdiH(VectorRegister wd, int imm10) {
2800 CHECK(HasMsa());
2801 CHECK(IsInt<10>(imm10)) << imm10;
2802 DsFsmInstrFr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7),
2803 static_cast<FRegister>(wd),
2804 ZERO);
2805}
2806
2807void MipsAssembler::LdiW(VectorRegister wd, int imm10) {
2808 CHECK(HasMsa());
2809 CHECK(IsInt<10>(imm10)) << imm10;
2810 DsFsmInstrFr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7),
2811 static_cast<FRegister>(wd),
2812 ZERO);
2813}
2814
2815void MipsAssembler::LdiD(VectorRegister wd, int imm10) {
2816 CHECK(HasMsa());
2817 CHECK(IsInt<10>(imm10)) << imm10;
2818 DsFsmInstrFr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7),
2819 static_cast<FRegister>(wd),
2820 ZERO);
2821}
2822
2823void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) {
2824 CHECK(HasMsa());
2825 CHECK(IsInt<10>(offset)) << offset;
2826 DsFsmInstrFr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0),
2827 static_cast<FRegister>(wd),
2828 rs);
2829}
2830
2831void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) {
2832 CHECK(HasMsa());
2833 CHECK(IsInt<11>(offset)) << offset;
2834 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2835 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1),
2836 static_cast<FRegister>(wd),
2837 rs);
2838}
2839
2840void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) {
2841 CHECK(HasMsa());
2842 CHECK(IsInt<12>(offset)) << offset;
2843 CHECK_ALIGNED(offset, kMipsWordSize);
2844 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2),
2845 static_cast<FRegister>(wd),
2846 rs);
2847}
2848
2849void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) {
2850 CHECK(HasMsa());
2851 CHECK(IsInt<13>(offset)) << offset;
2852 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2853 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3),
2854 static_cast<FRegister>(wd),
2855 rs);
2856}
2857
2858void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) {
2859 CHECK(HasMsa());
2860 CHECK(IsInt<10>(offset)) << offset;
2861 DsFsmInstrFR(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0), static_cast<FRegister>(wd), rs);
2862}
2863
2864void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) {
2865 CHECK(HasMsa());
2866 CHECK(IsInt<11>(offset)) << offset;
2867 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2868 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1),
2869 static_cast<FRegister>(wd),
2870 rs);
2871}
2872
2873void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) {
2874 CHECK(HasMsa());
2875 CHECK(IsInt<12>(offset)) << offset;
2876 CHECK_ALIGNED(offset, kMipsWordSize);
2877 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2),
2878 static_cast<FRegister>(wd),
2879 rs);
2880}
2881
2882void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
2883 CHECK(HasMsa());
2884 CHECK(IsInt<13>(offset)) << offset;
2885 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2886 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3),
2887 static_cast<FRegister>(wd),
2888 rs);
2889}
2890
2891void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2892 CHECK(HasMsa());
2893 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14),
2894 static_cast<FRegister>(wd),
2895 static_cast<FRegister>(ws),
2896 static_cast<FRegister>(wt));
2897}
2898
2899void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2900 CHECK(HasMsa());
2901 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14),
2902 static_cast<FRegister>(wd),
2903 static_cast<FRegister>(ws),
2904 static_cast<FRegister>(wt));
2905}
2906
2907void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2908 CHECK(HasMsa());
2909 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14),
2910 static_cast<FRegister>(wd),
2911 static_cast<FRegister>(ws),
2912 static_cast<FRegister>(wt));
2913}
2914
2915void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2916 CHECK(HasMsa());
2917 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14),
2918 static_cast<FRegister>(wd),
2919 static_cast<FRegister>(ws),
2920 static_cast<FRegister>(wt));
2921}
2922
Lena Djokicb3d79e42017-07-25 11:20:52 +02002923void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2924 CHECK(HasMsa());
2925 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12),
2926 static_cast<FRegister>(wd),
2927 static_cast<FRegister>(ws),
2928 static_cast<FRegister>(wt));
2929}
2930
2931void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2932 CHECK(HasMsa());
2933 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12),
2934 static_cast<FRegister>(wd),
2935 static_cast<FRegister>(ws),
2936 static_cast<FRegister>(wt));
2937}
2938
2939void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2940 CHECK(HasMsa());
2941 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12),
2942 static_cast<FRegister>(wd),
2943 static_cast<FRegister>(ws),
2944 static_cast<FRegister>(wt));
2945}
2946
2947void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2948 CHECK(HasMsa());
2949 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12),
2950 static_cast<FRegister>(wd),
2951 static_cast<FRegister>(ws),
2952 static_cast<FRegister>(wt));
2953}
2954
2955void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2956 CHECK(HasMsa());
2957 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12),
2958 static_cast<FRegister>(wd),
2959 static_cast<FRegister>(ws),
2960 static_cast<FRegister>(wt));
2961}
2962
2963void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2964 CHECK(HasMsa());
2965 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12),
2966 static_cast<FRegister>(wd),
2967 static_cast<FRegister>(ws),
2968 static_cast<FRegister>(wt));
2969}
2970
2971void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2972 CHECK(HasMsa());
2973 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12),
2974 static_cast<FRegister>(wd),
2975 static_cast<FRegister>(ws),
2976 static_cast<FRegister>(wt));
2977}
2978
2979void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2980 CHECK(HasMsa());
2981 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12),
2982 static_cast<FRegister>(wd),
2983 static_cast<FRegister>(ws),
2984 static_cast<FRegister>(wt));
2985}
2986
2987void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2988 CHECK(HasMsa());
2989 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b),
2990 static_cast<FRegister>(wd),
2991 static_cast<FRegister>(ws),
2992 static_cast<FRegister>(wt));
2993}
2994
2995void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2996 CHECK(HasMsa());
2997 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b),
2998 static_cast<FRegister>(wd),
2999 static_cast<FRegister>(ws),
3000 static_cast<FRegister>(wt));
3001}
3002
3003void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3004 CHECK(HasMsa());
3005 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b),
3006 static_cast<FRegister>(wd),
3007 static_cast<FRegister>(ws),
3008 static_cast<FRegister>(wt));
3009}
3010
3011void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
3012 CHECK(HasMsa());
3013 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b),
3014 static_cast<FRegister>(wd),
3015 static_cast<FRegister>(ws),
3016 static_cast<FRegister>(wt));
3017}
3018
Lena Djokic51765b02017-06-22 13:49:59 +02003019void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
3020 FRegister src,
3021 bool is_double) {
3022 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
3023 if (is_double) {
3024 SplatiD(dst, static_cast<VectorRegister>(src), 0);
3025 } else {
3026 SplatiW(dst, static_cast<VectorRegister>(src), 0);
3027 }
3028}
3029
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003030void MipsAssembler::LoadConst32(Register rd, int32_t value) {
3031 if (IsUint<16>(value)) {
3032 // Use OR with (unsigned) immediate to encode 16b unsigned int.
3033 Ori(rd, ZERO, value);
3034 } else if (IsInt<16>(value)) {
3035 // Use ADD with (signed) immediate to encode 16b signed int.
3036 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07003037 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003038 Lui(rd, High16Bits(value));
3039 if (value & 0xFFFF)
3040 Ori(rd, rd, Low16Bits(value));
3041 }
3042}
3043
3044void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003045 uint32_t low = Low32Bits(value);
3046 uint32_t high = High32Bits(value);
3047 LoadConst32(reg_lo, low);
3048 if (high != low) {
3049 LoadConst32(reg_hi, high);
3050 } else {
3051 Move(reg_hi, reg_lo);
3052 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003053}
3054
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003055void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003056 if (value == 0) {
3057 temp = ZERO;
3058 } else {
3059 LoadConst32(temp, value);
3060 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003061 Mtc1(temp, r);
3062}
3063
3064void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003065 uint32_t low = Low32Bits(value);
3066 uint32_t high = High32Bits(value);
3067 if (low == 0) {
3068 Mtc1(ZERO, rd);
3069 } else {
3070 LoadConst32(temp, low);
3071 Mtc1(temp, rd);
3072 }
3073 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003074 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003075 } else {
3076 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003077 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08003078 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003079}
3080
3081void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003082 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003083 if (IsInt<16>(value)) {
3084 Addiu(rt, rs, value);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003085 } else if (IsR6()) {
3086 int16_t high = High16Bits(value);
3087 int16_t low = Low16Bits(value);
3088 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
3089 if (low != 0) {
3090 Aui(temp, rs, high);
3091 Addiu(rt, temp, low);
3092 } else {
3093 Aui(rt, rs, high);
3094 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003095 } else {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07003096 // Do not load the whole 32-bit `value` if it can be represented as
3097 // a sum of two 16-bit signed values. This can save an instruction.
3098 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
3099 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
3100 if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
3101 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
3102 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
3103 } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
3104 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
3105 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
3106 } else {
3107 // Now that all shorter options have been exhausted, load the full 32-bit value.
3108 LoadConst32(temp, value);
3109 Addu(rt, rs, temp);
3110 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003111 }
3112}
3113
3114void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
3115 MipsAssembler::Branch::Type short_type,
3116 MipsAssembler::Branch::Type long_type) {
3117 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
3118}
3119
Alexey Frunze96b66822016-09-10 02:32:44 -07003120void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003121 OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003122 if (is_r6) {
3123 // R6
Alexey Frunze96b66822016-09-10 02:32:44 -07003124 switch (initial_type) {
3125 case kLabel:
3126 CHECK(!IsResolved());
3127 type_ = kR6Label;
3128 break;
3129 case kLiteral:
3130 CHECK(!IsResolved());
3131 type_ = kR6Literal;
3132 break;
3133 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003134 InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07003135 break;
3136 case kCondBranch:
3137 switch (condition_) {
3138 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003139 InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003140 break;
3141 case kCondEQZ:
3142 case kCondNEZ:
3143 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
Alexey Frunze0cab6562017-07-25 15:19:36 -07003144 type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
Alexey Frunze96b66822016-09-10 02:32:44 -07003145 break;
3146 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003147 InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003148 break;
3149 }
3150 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003151 case kBareCall:
3152 type_ = kR6BareCall;
3153 CHECK_LE(offset_size_needed, GetOffsetSize());
3154 break;
3155 case kBareCondBranch:
3156 type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch;
3157 CHECK_LE(offset_size_needed, GetOffsetSize());
3158 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003159 default:
3160 LOG(FATAL) << "Unexpected branch type " << initial_type;
3161 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003162 }
3163 } else {
3164 // R2
Alexey Frunze96b66822016-09-10 02:32:44 -07003165 switch (initial_type) {
3166 case kLabel:
3167 CHECK(!IsResolved());
3168 type_ = kLabel;
3169 break;
3170 case kLiteral:
3171 CHECK(!IsResolved());
3172 type_ = kLiteral;
3173 break;
3174 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003175 InitShortOrLong(offset_size_needed, kCall, kLongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07003176 break;
3177 case kCondBranch:
3178 switch (condition_) {
3179 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003180 InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003181 break;
3182 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003183 InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07003184 break;
3185 }
3186 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003187 case kBareCall:
3188 type_ = kBareCall;
3189 CHECK_LE(offset_size_needed, GetOffsetSize());
3190 break;
3191 case kBareCondBranch:
3192 type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
3193 CHECK_LE(offset_size_needed, GetOffsetSize());
3194 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003195 default:
3196 LOG(FATAL) << "Unexpected branch type " << initial_type;
3197 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003198 }
3199 }
3200 old_type_ = type_;
3201}
3202
3203bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
3204 switch (condition) {
3205 case kCondLT:
3206 case kCondGT:
3207 case kCondNE:
3208 case kCondLTU:
3209 return lhs == rhs;
3210 default:
3211 return false;
3212 }
3213}
3214
3215bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
3216 switch (condition) {
3217 case kUncond:
3218 return true;
3219 case kCondGE:
3220 case kCondLE:
3221 case kCondEQ:
3222 case kCondGEU:
3223 return lhs == rhs;
3224 default:
3225 return false;
3226 }
3227}
3228
Alexey Frunze0cab6562017-07-25 15:19:36 -07003229MipsAssembler::Branch::Branch(bool is_r6,
3230 uint32_t location,
3231 uint32_t target,
3232 bool is_call,
3233 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003234 : old_location_(location),
3235 location_(location),
3236 target_(target),
3237 lhs_reg_(0),
3238 rhs_reg_(0),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003239 condition_(kUncond),
3240 delayed_instruction_(kUnfilledDelaySlot) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003241 InitializeType(
3242 (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
3243 is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003244}
3245
3246MipsAssembler::Branch::Branch(bool is_r6,
3247 uint32_t location,
3248 uint32_t target,
3249 MipsAssembler::BranchCondition condition,
3250 Register lhs_reg,
Alexey Frunze0cab6562017-07-25 15:19:36 -07003251 Register rhs_reg,
3252 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003253 : old_location_(location),
3254 location_(location),
3255 target_(target),
3256 lhs_reg_(lhs_reg),
3257 rhs_reg_(rhs_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003258 condition_(condition),
3259 delayed_instruction_(kUnfilledDelaySlot) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003260 CHECK_NE(condition, kUncond);
3261 switch (condition) {
3262 case kCondLT:
3263 case kCondGE:
3264 case kCondLE:
3265 case kCondGT:
3266 case kCondLTU:
3267 case kCondGEU:
3268 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3269 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3270 // We leave this up to the caller.
3271 CHECK(is_r6);
3272 FALLTHROUGH_INTENDED;
3273 case kCondEQ:
3274 case kCondNE:
3275 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3276 // To compare with 0, use dedicated kCond*Z conditions.
3277 CHECK_NE(lhs_reg, ZERO);
3278 CHECK_NE(rhs_reg, ZERO);
3279 break;
3280 case kCondLTZ:
3281 case kCondGEZ:
3282 case kCondLEZ:
3283 case kCondGTZ:
3284 case kCondEQZ:
3285 case kCondNEZ:
3286 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3287 CHECK_NE(lhs_reg, ZERO);
3288 CHECK_EQ(rhs_reg, ZERO);
3289 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003290 case kCondF:
3291 case kCondT:
3292 CHECK_EQ(rhs_reg, ZERO);
3293 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003294 case kUncond:
3295 UNREACHABLE();
3296 }
3297 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
3298 if (IsUncond(condition, lhs_reg, rhs_reg)) {
3299 // Branch condition is always true, make the branch unconditional.
3300 condition_ = kUncond;
3301 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07003302 InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003303}
3304
Alexey Frunze96b66822016-09-10 02:32:44 -07003305MipsAssembler::Branch::Branch(bool is_r6,
3306 uint32_t location,
3307 Register dest_reg,
3308 Register base_reg,
3309 Type label_or_literal_type)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003310 : old_location_(location),
3311 location_(location),
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003312 target_(kUnresolved),
3313 lhs_reg_(dest_reg),
3314 rhs_reg_(base_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003315 condition_(kUncond),
3316 delayed_instruction_(kUnfilledDelaySlot) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003317 CHECK_NE(dest_reg, ZERO);
3318 if (is_r6) {
3319 CHECK_EQ(base_reg, ZERO);
3320 } else {
3321 CHECK_NE(base_reg, ZERO);
3322 }
Alexey Frunze96b66822016-09-10 02:32:44 -07003323 InitializeType(label_or_literal_type, is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003324}
3325
3326MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
3327 MipsAssembler::BranchCondition cond) {
3328 switch (cond) {
3329 case kCondLT:
3330 return kCondGE;
3331 case kCondGE:
3332 return kCondLT;
3333 case kCondLE:
3334 return kCondGT;
3335 case kCondGT:
3336 return kCondLE;
3337 case kCondLTZ:
3338 return kCondGEZ;
3339 case kCondGEZ:
3340 return kCondLTZ;
3341 case kCondLEZ:
3342 return kCondGTZ;
3343 case kCondGTZ:
3344 return kCondLEZ;
3345 case kCondEQ:
3346 return kCondNE;
3347 case kCondNE:
3348 return kCondEQ;
3349 case kCondEQZ:
3350 return kCondNEZ;
3351 case kCondNEZ:
3352 return kCondEQZ;
3353 case kCondLTU:
3354 return kCondGEU;
3355 case kCondGEU:
3356 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003357 case kCondF:
3358 return kCondT;
3359 case kCondT:
3360 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003361 case kUncond:
3362 LOG(FATAL) << "Unexpected branch condition " << cond;
3363 }
3364 UNREACHABLE();
3365}
3366
3367MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
3368 return type_;
3369}
3370
3371MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
3372 return condition_;
3373}
3374
3375Register MipsAssembler::Branch::GetLeftRegister() const {
3376 return static_cast<Register>(lhs_reg_);
3377}
3378
3379Register MipsAssembler::Branch::GetRightRegister() const {
3380 return static_cast<Register>(rhs_reg_);
3381}
3382
3383uint32_t MipsAssembler::Branch::GetTarget() const {
3384 return target_;
3385}
3386
3387uint32_t MipsAssembler::Branch::GetLocation() const {
3388 return location_;
3389}
3390
3391uint32_t MipsAssembler::Branch::GetOldLocation() const {
3392 return old_location_;
3393}
3394
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003395uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const {
3396 // Short branches with delay slots always consist of two instructions, the branch
3397 // and the delay slot, irrespective of whether the delay slot is filled with a
3398 // useful instruction or not.
3399 // Long composite branches may have a length longer by one instruction than
3400 // specified in branch_info_[].length. This happens when an instruction is taken
3401 // to fill the short branch delay slot, but the branch eventually becomes long
3402 // and formally has no delay slot to fill. This instruction is placed at the
3403 // beginning of the long composite branch and this needs to be accounted for in
3404 // the branch length and the location of the offset encoded in the branch.
3405 switch (type) {
3406 case kLongUncondBranch:
3407 case kLongCondBranch:
3408 case kLongCall:
3409 case kR6LongCondBranch:
3410 return (delayed_instruction_ != kUnfilledDelaySlot &&
3411 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0;
3412 default:
3413 return 0;
3414 }
3415}
3416
3417uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const {
3418 return GetPrecedingInstructionLength(type) * sizeof(uint32_t);
3419}
3420
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003421uint32_t MipsAssembler::Branch::GetLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003422 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003423}
3424
3425uint32_t MipsAssembler::Branch::GetOldLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003426 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003427}
3428
3429uint32_t MipsAssembler::Branch::GetSize() const {
3430 return GetLength() * sizeof(uint32_t);
3431}
3432
3433uint32_t MipsAssembler::Branch::GetOldSize() const {
3434 return GetOldLength() * sizeof(uint32_t);
3435}
3436
3437uint32_t MipsAssembler::Branch::GetEndLocation() const {
3438 return GetLocation() + GetSize();
3439}
3440
3441uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
3442 return GetOldLocation() + GetOldSize();
3443}
3444
Alexey Frunze0cab6562017-07-25 15:19:36 -07003445bool MipsAssembler::Branch::IsBare() const {
3446 switch (type_) {
3447 // R2 short branches (can't be promoted to long), delay slots filled manually.
3448 case kBareUncondBranch:
3449 case kBareCondBranch:
3450 case kBareCall:
3451 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3452 case kR6BareUncondBranch:
3453 case kR6BareCondBranch:
3454 case kR6BareCall:
3455 return true;
3456 default:
3457 return false;
3458 }
3459}
3460
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003461bool MipsAssembler::Branch::IsLong() const {
3462 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003463 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003464 case kUncondBranch:
3465 case kCondBranch:
3466 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003467 // R2 short branches (can't be promoted to long), delay slots filled manually.
3468 case kBareUncondBranch:
3469 case kBareCondBranch:
3470 case kBareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003471 // R2 near label.
3472 case kLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003473 // R2 near literal.
3474 case kLiteral:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003475 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003476 case kR6UncondBranch:
3477 case kR6CondBranch:
3478 case kR6Call:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003479 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3480 case kR6BareUncondBranch:
3481 case kR6BareCondBranch:
3482 case kR6BareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003483 // R6 near label.
3484 case kR6Label:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003485 // R6 near literal.
3486 case kR6Literal:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003487 return false;
3488 // R2 long branches.
3489 case kLongUncondBranch:
3490 case kLongCondBranch:
3491 case kLongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003492 // R2 far label.
3493 case kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003494 // R2 far literal.
3495 case kFarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003496 // R6 long branches.
3497 case kR6LongUncondBranch:
3498 case kR6LongCondBranch:
3499 case kR6LongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003500 // R6 far label.
3501 case kR6FarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003502 // R6 far literal.
3503 case kR6FarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003504 return true;
3505 }
3506 UNREACHABLE();
3507}
3508
3509bool MipsAssembler::Branch::IsResolved() const {
3510 return target_ != kUnresolved;
3511}
3512
3513MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003514 bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003515 OffsetBits offset_size =
Alexey Frunze0cab6562017-07-25 15:19:36 -07003516 (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003517 ? kOffset23
3518 : branch_info_[type_].offset_size;
3519 return offset_size;
3520}
3521
3522MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
3523 uint32_t target) {
3524 // For unresolved targets assume the shortest encoding
3525 // (later it will be made longer if needed).
3526 if (target == kUnresolved)
3527 return kOffset16;
3528 int64_t distance = static_cast<int64_t>(target) - location;
3529 // To simplify calculations in composite branches consisting of multiple instructions
3530 // bump up the distance by a value larger than the max byte size of a composite branch.
3531 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
3532 if (IsInt<kOffset16>(distance))
3533 return kOffset16;
3534 else if (IsInt<kOffset18>(distance))
3535 return kOffset18;
3536 else if (IsInt<kOffset21>(distance))
3537 return kOffset21;
3538 else if (IsInt<kOffset23>(distance))
3539 return kOffset23;
3540 else if (IsInt<kOffset28>(distance))
3541 return kOffset28;
3542 return kOffset32;
3543}
3544
3545void MipsAssembler::Branch::Resolve(uint32_t target) {
3546 target_ = target;
3547}
3548
3549void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
3550 if (location_ > expand_location) {
3551 location_ += delta;
3552 }
3553 if (!IsResolved()) {
3554 return; // Don't know the target yet.
3555 }
3556 if (target_ > expand_location) {
3557 target_ += delta;
3558 }
3559}
3560
3561void MipsAssembler::Branch::PromoteToLong() {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003562 CHECK(!IsBare()); // Bare branches do not promote.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003563 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003564 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003565 case kUncondBranch:
3566 type_ = kLongUncondBranch;
3567 break;
3568 case kCondBranch:
3569 type_ = kLongCondBranch;
3570 break;
3571 case kCall:
3572 type_ = kLongCall;
3573 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003574 // R2 near label.
3575 case kLabel:
3576 type_ = kFarLabel;
3577 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003578 // R2 near literal.
3579 case kLiteral:
3580 type_ = kFarLiteral;
3581 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003582 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003583 case kR6UncondBranch:
3584 type_ = kR6LongUncondBranch;
3585 break;
3586 case kR6CondBranch:
3587 type_ = kR6LongCondBranch;
3588 break;
3589 case kR6Call:
3590 type_ = kR6LongCall;
3591 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003592 // R6 near label.
3593 case kR6Label:
3594 type_ = kR6FarLabel;
3595 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003596 // R6 near literal.
3597 case kR6Literal:
3598 type_ = kR6FarLiteral;
3599 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003600 default:
3601 // Note: 'type_' is already long.
3602 break;
3603 }
3604 CHECK(IsLong());
3605}
3606
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003607uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
3608 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003609 case Branch::kLabel:
3610 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003611 case Branch::kLiteral:
3612 case Branch::kFarLiteral:
3613 return GetLabelLocation(&pc_rel_base_label_);
3614 default:
3615 return branch->GetLocation();
3616 }
3617}
3618
3619uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003620 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003621 // `this->GetLocation()` for everything else.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003622 // If the branch is still unresolved or already long, nothing to do.
3623 if (IsLong() || !IsResolved()) {
3624 return 0;
3625 }
3626 // Promote the short branch to long if the offset size is too small
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003627 // to hold the distance between location and target_.
3628 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003629 PromoteToLong();
3630 uint32_t old_size = GetOldSize();
3631 uint32_t new_size = GetSize();
3632 CHECK_GT(new_size, old_size);
3633 return new_size - old_size;
3634 }
3635 // The following logic is for debugging/testing purposes.
3636 // Promote some short branches to long when it's not really required.
Alexey Frunze0cab6562017-07-25 15:19:36 -07003637 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003638 int64_t distance = static_cast<int64_t>(target_) - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003639 distance = (distance >= 0) ? distance : -distance;
3640 if (distance >= max_short_distance) {
3641 PromoteToLong();
3642 uint32_t old_size = GetOldSize();
3643 uint32_t new_size = GetSize();
3644 CHECK_GT(new_size, old_size);
3645 return new_size - old_size;
3646 }
3647 }
3648 return 0;
3649}
3650
3651uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003652 return location_ + GetPrecedingInstructionSize(type_) +
3653 branch_info_[type_].instr_offset * sizeof(uint32_t);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003654}
3655
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003656uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
3657 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003658 case Branch::kLabel:
3659 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003660 case Branch::kLiteral:
3661 case Branch::kFarLiteral:
3662 return GetLabelLocation(&pc_rel_base_label_);
3663 default:
3664 return branch->GetOffsetLocation() +
3665 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
3666 }
3667}
3668
3669uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
Alexey Frunze96b66822016-09-10 02:32:44 -07003670 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003671 // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)`
3672 // for everything else.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003673 CHECK(IsResolved());
3674 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
3675 // Calculate the byte distance between instructions and also account for
3676 // different PC-relative origins.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003677 uint32_t offset = target_ - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003678 // Prepare the offset for encoding into the instruction(s).
3679 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
3680 return offset;
3681}
3682
3683MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
3684 CHECK_LT(branch_id, branches_.size());
3685 return &branches_[branch_id];
3686}
3687
3688const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
3689 CHECK_LT(branch_id, branches_.size());
3690 return &branches_[branch_id];
3691}
3692
3693void MipsAssembler::Bind(MipsLabel* label) {
3694 CHECK(!label->IsBound());
3695 uint32_t bound_pc = buffer_.Size();
3696
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003697 // Make the delay slot FSM aware of the new label.
3698 DsFsmLabel();
3699
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003700 // Walk the list of branches referring to and preceding this label.
3701 // Store the previously unknown target addresses in them.
3702 while (label->IsLinked()) {
3703 uint32_t branch_id = label->Position();
3704 Branch* branch = GetBranch(branch_id);
3705 branch->Resolve(bound_pc);
3706
3707 uint32_t branch_location = branch->GetLocation();
3708 // Extract the location of the previous branch in the list (walking the list backwards;
3709 // the previous branch ID was stored in the space reserved for this branch).
3710 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
3711
3712 // On to the previous branch in the list...
3713 label->position_ = prev;
3714 }
3715
3716 // Now make the label object contain its own location (relative to the end of the preceding
3717 // branch, if any; it will be used by the branches referring to and following this label).
3718 label->prev_branch_id_plus_one_ = branches_.size();
3719 if (label->prev_branch_id_plus_one_) {
3720 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
3721 const Branch* branch = GetBranch(branch_id);
3722 bound_pc -= branch->GetEndLocation();
3723 }
3724 label->BindTo(bound_pc);
3725}
3726
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003727uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003728 CHECK(label->IsBound());
3729 uint32_t target = label->Position();
3730 if (label->prev_branch_id_plus_one_) {
3731 // Get label location based on the branch preceding it.
3732 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
3733 const Branch* branch = GetBranch(branch_id);
3734 target += branch->GetEndLocation();
3735 }
3736 return target;
3737}
3738
3739uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
3740 // We can reconstruct the adjustment by going through all the branches from the beginning
3741 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
3742 // with increasing old_position, we can use the data from last AdjustedPosition() to
3743 // continue where we left off and the whole loop should be O(m+n) where m is the number
3744 // of positions to adjust and n is the number of branches.
3745 if (old_position < last_old_position_) {
3746 last_position_adjustment_ = 0;
3747 last_old_position_ = 0;
3748 last_branch_id_ = 0;
3749 }
3750 while (last_branch_id_ != branches_.size()) {
3751 const Branch* branch = GetBranch(last_branch_id_);
3752 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
3753 break;
3754 }
3755 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
3756 ++last_branch_id_;
3757 }
3758 last_old_position_ = old_position;
3759 return old_position + last_position_adjustment_;
3760}
3761
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003762void MipsAssembler::BindPcRelBaseLabel() {
3763 Bind(&pc_rel_base_label_);
3764}
3765
Alexey Frunze06a46c42016-07-19 15:00:40 -07003766uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const {
3767 return GetLabelLocation(&pc_rel_base_label_);
3768}
3769
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003770void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
3771 uint32_t length = branches_.back().GetLength();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003772 // Commit the last branch target label (if any).
3773 DsFsmCommitLabel();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003774 if (!label->IsBound()) {
3775 // Branch forward (to a following label), distance is unknown.
3776 // The first branch forward will contain 0, serving as the terminator of
3777 // the list of forward-reaching branches.
3778 Emit(label->position_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003779 // Nothing for the delay slot (yet).
3780 DsFsmInstrNop(0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003781 length--;
3782 // Now make the label object point to this branch
3783 // (this forms a linked list of branches preceding this label).
3784 uint32_t branch_id = branches_.size() - 1;
3785 label->LinkTo(branch_id);
3786 }
3787 // Reserve space for the branch.
3788 while (length--) {
3789 Nop();
3790 }
3791}
3792
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003793bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const {
3794 if (delay_slot.instruction_ == 0) {
3795 // NOP or no instruction for the delay slot.
3796 return false;
3797 }
3798 switch (type_) {
3799 // R2 unconditional branches.
3800 case kUncondBranch:
3801 case kLongUncondBranch:
3802 // There are no register interdependencies.
3803 return true;
3804
3805 // R2 calls.
3806 case kCall:
3807 case kLongCall:
3808 // Instructions depending on or modifying RA should not be moved into delay slots
3809 // of branches modifying RA.
3810 return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0;
3811
3812 // R2 conditional branches.
3813 case kCondBranch:
3814 case kLongCondBranch:
3815 switch (condition_) {
3816 // Branches with one GPR source.
3817 case kCondLTZ:
3818 case kCondGEZ:
3819 case kCondLEZ:
3820 case kCondGTZ:
3821 case kCondEQZ:
3822 case kCondNEZ:
3823 return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0;
3824
3825 // Branches with two GPR sources.
3826 case kCondEQ:
3827 case kCondNE:
3828 return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
3829
3830 // Branches with one FPU condition code source.
3831 case kCondF:
3832 case kCondT:
3833 return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0;
3834
3835 default:
3836 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3837 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3838 LOG(FATAL) << "Unexpected branch condition " << condition_;
3839 UNREACHABLE();
3840 }
3841
3842 // R6 unconditional branches.
3843 case kR6UncondBranch:
3844 case kR6LongUncondBranch:
3845 // R6 calls.
3846 case kR6Call:
3847 case kR6LongCall:
3848 // There are no delay slots.
3849 return false;
3850
3851 // R6 conditional branches.
3852 case kR6CondBranch:
3853 case kR6LongCondBranch:
3854 switch (condition_) {
3855 // Branches with one FPU register source.
3856 case kCondF:
3857 case kCondT:
3858 return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0;
3859 // Others have a forbidden slot instead of a delay slot.
3860 default:
3861 return false;
3862 }
3863
3864 // Literals.
3865 default:
3866 LOG(FATAL) << "Unexpected branch type " << type_;
3867 UNREACHABLE();
3868 }
3869}
3870
3871uint32_t MipsAssembler::Branch::GetDelayedInstruction() const {
3872 return delayed_instruction_;
3873}
3874
3875void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction) {
3876 CHECK_NE(instruction, kUnfilledDelaySlot);
3877 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot);
3878 delayed_instruction_ = instruction;
3879}
3880
3881void MipsAssembler::Branch::DecrementLocations() {
3882 // We first create a branch object, which gets its type and locations initialized,
3883 // and then we check if the branch can actually have the preceding instruction moved
3884 // into its delay slot. If it can, the branch locations need to be decremented.
3885 //
3886 // We could make the check before creating the branch object and avoid the location
3887 // adjustment, but the check is cleaner when performed on an initialized branch
3888 // object.
3889 //
3890 // If the branch is backwards (to a previously bound label), reducing the locations
3891 // cannot cause a short branch to exceed its offset range because the offset reduces.
3892 // And this is not at all a problem for a long branch backwards.
3893 //
3894 // If the branch is forward (not linked to any label yet), reducing the locations
3895 // is harmless. The branch will be promoted to long if needed when the target is known.
3896 CHECK_EQ(location_, old_location_);
3897 CHECK_GE(old_location_, sizeof(uint32_t));
3898 old_location_ -= sizeof(uint32_t);
3899 location_ = old_location_;
3900}
3901
3902void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003903 if (branch.IsBare()) {
3904 // Delay slots are filled manually in bare branches.
3905 return;
3906 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003907 if (branch.CanHaveDelayedInstruction(delay_slot_)) {
3908 // The last instruction cannot be used in a different delay slot,
3909 // do not commit the label before it (if any).
3910 DsFsmDropLabel();
3911 // Remove the last emitted instruction.
3912 size_t size = buffer_.Size();
3913 CHECK_GE(size, sizeof(uint32_t));
3914 size -= sizeof(uint32_t);
3915 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_);
3916 buffer_.Resize(size);
3917 // Attach it to the branch and adjust the branch locations.
3918 branch.DecrementLocations();
3919 branch.SetDelayedInstruction(delay_slot_.instruction_);
3920 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) {
3921 // If reordefing is disabled, prevent absorption of the target instruction.
3922 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot);
3923 }
3924}
3925
Alexey Frunze0cab6562017-07-25 15:19:36 -07003926void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003927 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003928 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ false, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003929 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003930 FinalizeLabeledBranch(label);
3931}
3932
Alexey Frunze0cab6562017-07-25 15:19:36 -07003933void MipsAssembler::Bcond(MipsLabel* label,
3934 bool is_r6,
3935 bool is_bare,
3936 BranchCondition condition,
3937 Register lhs,
3938 Register rhs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003939 // If lhs = rhs, this can be a NOP.
3940 if (Branch::IsNop(condition, lhs, rhs)) {
3941 return;
3942 }
3943 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003944 branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003945 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003946 FinalizeLabeledBranch(label);
3947}
3948
Alexey Frunze0cab6562017-07-25 15:19:36 -07003949void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003950 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003951 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ true, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003952 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003953 FinalizeLabeledBranch(label);
3954}
3955
Alexey Frunze96b66822016-09-10 02:32:44 -07003956void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
3957 // Label address loads are treated as pseudo branches since they require very similar handling.
3958 DCHECK(!label->IsBound());
3959 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
3960 FinalizeLabeledBranch(label);
3961}
3962
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003963Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
3964 DCHECK(size == 4u || size == 8u) << size;
3965 literals_.emplace_back(size, data);
3966 return &literals_.back();
3967}
3968
3969void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) {
3970 // Literal loads are treated as pseudo branches since they require very similar handling.
3971 DCHECK_EQ(literal->GetSize(), 4u);
3972 MipsLabel* label = literal->GetLabel();
3973 DCHECK(!label->IsBound());
Alexey Frunze96b66822016-09-10 02:32:44 -07003974 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003975 FinalizeLabeledBranch(label);
3976}
3977
Alexey Frunze96b66822016-09-10 02:32:44 -07003978JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
3979 jump_tables_.emplace_back(std::move(labels));
3980 JumpTable* table = &jump_tables_.back();
3981 DCHECK(!table->GetLabel()->IsBound());
3982 return table;
3983}
3984
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003985void MipsAssembler::EmitLiterals() {
3986 if (!literals_.empty()) {
3987 // We don't support byte and half-word literals.
3988 // TODO: proper alignment for 64-bit literals when they're implemented.
3989 for (Literal& literal : literals_) {
3990 MipsLabel* label = literal.GetLabel();
3991 Bind(label);
3992 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
3993 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
3994 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
3995 buffer_.Emit<uint8_t>(literal.GetData()[i]);
3996 }
3997 }
3998 }
3999}
4000
Alexey Frunze96b66822016-09-10 02:32:44 -07004001void MipsAssembler::ReserveJumpTableSpace() {
4002 if (!jump_tables_.empty()) {
4003 for (JumpTable& table : jump_tables_) {
4004 MipsLabel* label = table.GetLabel();
4005 Bind(label);
4006
4007 // Bulk ensure capacity, as this may be large.
4008 size_t orig_size = buffer_.Size();
4009 size_t required_capacity = orig_size + table.GetSize();
4010 if (required_capacity > buffer_.Capacity()) {
4011 buffer_.ExtendCapacity(required_capacity);
4012 }
4013#ifndef NDEBUG
4014 buffer_.has_ensured_capacity_ = true;
4015#endif
4016
4017 // Fill the space with dummy data as the data is not final
4018 // until the branches have been promoted. And we shouldn't
4019 // be moving uninitialized data during branch promotion.
4020 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
4021 buffer_.Emit<uint32_t>(0x1abe1234u);
4022 }
4023
4024#ifndef NDEBUG
4025 buffer_.has_ensured_capacity_ = false;
4026#endif
4027 }
4028 }
4029}
4030
4031void MipsAssembler::EmitJumpTables() {
4032 if (!jump_tables_.empty()) {
4033 CHECK(!overwriting_);
4034 // Switch from appending instructions at the end of the buffer to overwriting
4035 // existing instructions (here, jump tables) in the buffer.
4036 overwriting_ = true;
4037
4038 for (JumpTable& table : jump_tables_) {
4039 MipsLabel* table_label = table.GetLabel();
4040 uint32_t start = GetLabelLocation(table_label);
4041 overwrite_location_ = start;
4042
4043 for (MipsLabel* target : table.GetData()) {
4044 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
4045 // The table will contain target addresses relative to the table start.
4046 uint32_t offset = GetLabelLocation(target) - start;
4047 Emit(offset);
4048 }
4049 }
4050
4051 overwriting_ = false;
4052 }
4053}
4054
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004055void MipsAssembler::PromoteBranches() {
4056 // Promote short branches to long as necessary.
4057 bool changed;
4058 do {
4059 changed = false;
4060 for (auto& branch : branches_) {
4061 CHECK(branch.IsResolved());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004062 uint32_t base = GetBranchLocationOrPcRelBase(&branch);
4063 uint32_t delta = branch.PromoteIfNeeded(base);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004064 // If this branch has been promoted and needs to expand in size,
4065 // relocate all branches by the expansion size.
4066 if (delta) {
4067 changed = true;
4068 uint32_t expand_location = branch.GetLocation();
4069 for (auto& branch2 : branches_) {
4070 branch2.Relocate(expand_location, delta);
4071 }
4072 }
4073 }
4074 } while (changed);
4075
4076 // Account for branch expansion by resizing the code buffer
4077 // and moving the code in it to its final location.
4078 size_t branch_count = branches_.size();
4079 if (branch_count > 0) {
4080 // Resize.
4081 Branch& last_branch = branches_[branch_count - 1];
4082 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
4083 uint32_t old_size = buffer_.Size();
4084 buffer_.Resize(old_size + size_delta);
4085 // Move the code residing between branch placeholders.
4086 uint32_t end = old_size;
4087 for (size_t i = branch_count; i > 0; ) {
4088 Branch& branch = branches_[--i];
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004089 CHECK_GE(end, branch.GetOldEndLocation());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004090 uint32_t size = end - branch.GetOldEndLocation();
4091 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
4092 end = branch.GetOldLocation();
4093 }
4094 }
4095}
4096
4097// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
4098const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004099 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004100 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
4101 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004102 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall
Alexey Frunze0cab6562017-07-25 15:19:36 -07004103 // R2 short branches (can't be promoted to long), delay slots filled manually.
4104 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch
4105 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch
4106 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004107 // R2 near label.
4108 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004109 // R2 near literal.
4110 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004111 // R2 long branches.
4112 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
4113 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
4114 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004115 // R2 far label.
4116 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004117 // R2 far literal.
4118 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral
Alexey Frunze0cab6562017-07-25 15:19:36 -07004119 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004120 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
4121 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
4122 // Exception: kOffset23 for beqzc/bnezc.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004123 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call
Alexey Frunze0cab6562017-07-25 15:19:36 -07004124 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
4125 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch
4126 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch
4127 // Exception: kOffset23 for beqzc/bnezc.
4128 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004129 // R6 near label.
4130 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004131 // R6 near literal.
4132 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004133 // R6 long branches.
4134 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
4135 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004136 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07004137 // R6 far label.
4138 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004139 // R6 far literal.
4140 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004141};
4142
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004143// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004144void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
4145 CHECK_EQ(overwriting_, true);
4146 overwrite_location_ = branch->GetLocation();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004147 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004148 BranchCondition condition = branch->GetCondition();
4149 Register lhs = branch->GetLeftRegister();
4150 Register rhs = branch->GetRightRegister();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004151 uint32_t delayed_instruction = branch->GetDelayedInstruction();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004152 switch (branch->GetType()) {
4153 // R2 short branches.
4154 case Branch::kUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004155 if (delayed_instruction == Branch::kUnfillableDelaySlot) {
4156 // The branch was created when reordering was disabled, do not absorb the target
4157 // instruction.
4158 delayed_instruction = 0; // NOP.
4159 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4160 // Try to absorb the target instruction into the delay slot.
4161 delayed_instruction = 0; // NOP.
4162 // Incrementing the signed 16-bit offset past the target instruction must not
4163 // cause overflow into the negative subrange, check for the max offset.
4164 if (offset != 0x7FFF) {
4165 uint32_t target = branch->GetTarget();
4166 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) {
4167 delayed_instruction = buffer_.Load<uint32_t>(target);
4168 offset++;
4169 }
4170 }
4171 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004172 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4173 B(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004174 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004175 break;
4176 case Branch::kCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004177 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4178 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4179 delayed_instruction = 0; // NOP.
4180 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004181 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004182 EmitBcondR2(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004183 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004184 break;
4185 case Branch::kCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004186 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4187 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4188 delayed_instruction = 0; // NOP.
4189 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004190 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004191 Bal(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004192 Emit(delayed_instruction);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004193 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004194 case Branch::kBareUncondBranch:
4195 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4196 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4197 B(offset);
4198 break;
4199 case Branch::kBareCondBranch:
4200 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4201 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4202 EmitBcondR2(condition, lhs, rhs, offset);
4203 break;
4204 case Branch::kBareCall:
4205 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4206 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4207 Bal(offset);
4208 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004209
Alexey Frunze96b66822016-09-10 02:32:44 -07004210 // R2 near label.
4211 case Branch::kLabel:
4212 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4213 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4214 Addiu(lhs, rhs, offset);
4215 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004216 // R2 near literal.
4217 case Branch::kLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004218 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004219 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4220 Lw(lhs, rhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004221 break;
4222
4223 // R2 long branches.
4224 case Branch::kLongUncondBranch:
4225 // To get the value of the PC register we need to use the NAL instruction.
4226 // NAL clobbers the RA register. However, RA must be preserved if the
4227 // method is compiled without the entry/exit sequences that would take care
4228 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
4229 // So, we need to preserve RA in some temporary storage ourselves. The AT
4230 // register can't be used for this because we need it to load a constant
4231 // which will be added to the value that NAL stores in RA. And we can't
4232 // use T9 for this in the context of the JNI compiler, which uses it
4233 // as a scratch register (see InterproceduralScratchRegister()).
4234 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
4235 // we'd also need to use the ROTR instruction, which requires no less than
4236 // MIPSR2.
4237 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
4238 // (LO or HI) or even a floating-point register, but that doesn't seem
4239 // like a nice solution. We may want this to work on both R6 and pre-R6.
4240 // For now simply use the stack for RA. This should be OK since for the
4241 // vast majority of code a short PC-relative branch is sufficient.
4242 // TODO: can this be improved?
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004243 // TODO: consider generation of a shorter sequence when we know that RA
4244 // is explicitly preserved by the method entry/exit code.
4245 if (delayed_instruction != Branch::kUnfilledDelaySlot &&
4246 delayed_instruction != Branch::kUnfillableDelaySlot) {
4247 Emit(delayed_instruction);
4248 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004249 Push(RA);
4250 Nal();
4251 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4252 Lui(AT, High16Bits(offset));
4253 Ori(AT, AT, Low16Bits(offset));
4254 Addu(AT, AT, RA);
4255 Lw(RA, SP, 0);
4256 Jr(AT);
4257 DecreaseFrameSize(kMipsWordSize);
4258 break;
4259 case Branch::kLongCondBranch:
4260 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004261 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4262 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4263 Emit(delayed_instruction);
4264 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004265 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
4266 // number of instructions skipped:
4267 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004268 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004269 Push(RA);
4270 Nal();
4271 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4272 Lui(AT, High16Bits(offset));
4273 Ori(AT, AT, Low16Bits(offset));
4274 Addu(AT, AT, RA);
4275 Lw(RA, SP, 0);
4276 Jr(AT);
4277 DecreaseFrameSize(kMipsWordSize);
4278 break;
4279 case Branch::kLongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004280 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4281 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4282 Emit(delayed_instruction);
4283 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004284 Nal();
4285 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4286 Lui(AT, High16Bits(offset));
4287 Ori(AT, AT, Low16Bits(offset));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004288 Addu(AT, AT, RA);
4289 Jalr(AT);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004290 Nop();
4291 break;
4292
Alexey Frunze96b66822016-09-10 02:32:44 -07004293 // R2 far label.
4294 case Branch::kFarLabel:
4295 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4296 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4297 Lui(AT, High16Bits(offset));
4298 Ori(AT, AT, Low16Bits(offset));
4299 Addu(lhs, AT, rhs);
4300 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004301 // R2 far literal.
4302 case Branch::kFarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004303 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004304 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4305 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4306 Lui(AT, High16Bits(offset));
4307 Addu(AT, AT, rhs);
4308 Lw(lhs, AT, Low16Bits(offset));
4309 break;
4310
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004311 // R6 short branches.
4312 case Branch::kR6UncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004313 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004314 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4315 Bc(offset);
4316 break;
4317 case Branch::kR6CondBranch:
4318 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004319 EmitBcondR6(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004320 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4321 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4322 Emit(delayed_instruction);
4323 } else {
4324 // TODO: improve by filling the forbidden slot (IFF this is
4325 // a forbidden and not a delay slot).
4326 Nop();
4327 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004328 break;
4329 case Branch::kR6Call:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004330 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004331 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004332 Balc(offset);
4333 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004334 case Branch::kR6BareUncondBranch:
4335 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4336 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4337 Bc(offset);
4338 break;
4339 case Branch::kR6BareCondBranch:
4340 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4341 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4342 EmitBcondR6(condition, lhs, rhs, offset);
4343 break;
4344 case Branch::kR6BareCall:
4345 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4346 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4347 Balc(offset);
4348 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004349
Alexey Frunze96b66822016-09-10 02:32:44 -07004350 // R6 near label.
4351 case Branch::kR6Label:
4352 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4353 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4354 Addiupc(lhs, offset);
4355 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004356 // R6 near literal.
4357 case Branch::kR6Literal:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004358 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004359 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4360 Lwpc(lhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004361 break;
4362
4363 // R6 long branches.
4364 case Branch::kR6LongUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004365 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004366 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4367 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4368 Auipc(AT, High16Bits(offset));
4369 Jic(AT, Low16Bits(offset));
4370 break;
4371 case Branch::kR6LongCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004372 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4373 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4374 Emit(delayed_instruction);
4375 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004376 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004377 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4378 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4379 Auipc(AT, High16Bits(offset));
4380 Jic(AT, Low16Bits(offset));
4381 break;
4382 case Branch::kR6LongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004383 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004384 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004385 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004386 Auipc(AT, High16Bits(offset));
4387 Jialc(AT, Low16Bits(offset));
4388 break;
4389
Alexey Frunze96b66822016-09-10 02:32:44 -07004390 // R6 far label.
4391 case Branch::kR6FarLabel:
4392 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4393 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
4394 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4395 Auipc(AT, High16Bits(offset));
4396 Addiu(lhs, AT, Low16Bits(offset));
4397 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004398 // R6 far literal.
4399 case Branch::kR6FarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004400 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004401 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4402 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4403 Auipc(AT, High16Bits(offset));
4404 Lw(lhs, AT, Low16Bits(offset));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004405 break;
4406 }
4407 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
4408 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
4409}
4410
Alexey Frunze0cab6562017-07-25 15:19:36 -07004411void MipsAssembler::B(MipsLabel* label, bool is_bare) {
4412 Buncond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004413}
4414
Alexey Frunze0cab6562017-07-25 15:19:36 -07004415void MipsAssembler::Bal(MipsLabel* label, bool is_bare) {
4416 Call(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004417}
4418
Alexey Frunze0cab6562017-07-25 15:19:36 -07004419void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4420 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004421}
4422
Alexey Frunze0cab6562017-07-25 15:19:36 -07004423void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4424 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004425}
4426
Alexey Frunze0cab6562017-07-25 15:19:36 -07004427void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) {
4428 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004429}
4430
Alexey Frunze0cab6562017-07-25 15:19:36 -07004431void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) {
4432 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004433}
4434
Alexey Frunze0cab6562017-07-25 15:19:36 -07004435void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) {
4436 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004437}
4438
Alexey Frunze0cab6562017-07-25 15:19:36 -07004439void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) {
4440 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004441}
4442
Alexey Frunze0cab6562017-07-25 15:19:36 -07004443void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) {
4444 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004445}
4446
Alexey Frunze0cab6562017-07-25 15:19:36 -07004447void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) {
4448 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004449}
4450
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004451bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
4452 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u]
4453 // instruction because either slt[u] depends on `rs` or `rt` or the following
4454 // conditional branch depends on AT set by slt[u].
4455 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
4456 // because slt[u] changes AT.
4457 return (delay_slot_.instruction_ != 0 &&
4458 (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
4459 (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0);
4460}
4461
4462void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
4463 // Exchange the last two instructions in the assembler buffer.
4464 size_t size = buffer_.Size();
4465 CHECK_GE(size, 2 * sizeof(uint32_t));
4466 size_t pos1 = size - 2 * sizeof(uint32_t);
4467 size_t pos2 = size - sizeof(uint32_t);
4468 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
4469 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
4470 CHECK_EQ(instr1, forwarded_slot.instruction_);
4471 CHECK_EQ(instr2, delay_slot_.instruction_);
4472 buffer_.Store<uint32_t>(pos1, instr2);
4473 buffer_.Store<uint32_t>(pos2, instr1);
4474 // Set the current delay slot information to that of the last instruction
4475 // in the buffer.
4476 delay_slot_ = forwarded_slot;
4477}
4478
4479void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) {
4480 // If possible, exchange the slt[u] instruction with the preceding instruction,
4481 // so it can fill the delay slot.
4482 DelaySlot forwarded_slot = delay_slot_;
4483 bool exchange = CanExchangeWithSlt(rs, rt);
4484 if (exchange) {
4485 // The last instruction cannot be used in a different delay slot,
4486 // do not commit the label before it (if any).
4487 DsFsmDropLabel();
4488 }
4489 if (unsigned_slt) {
4490 Sltu(AT, rs, rt);
4491 } else {
4492 Slt(AT, rs, rt);
4493 }
4494 if (exchange) {
4495 ExchangeWithSlt(forwarded_slot);
4496 }
4497}
4498
Alexey Frunze0cab6562017-07-25 15:19:36 -07004499void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4500 if (IsR6() && !is_bare) {
4501 Bcond(label, IsR6(), is_bare, kCondLT, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004502 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
4503 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004504 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004505 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004506 }
4507}
4508
Alexey Frunze0cab6562017-07-25 15:19:36 -07004509void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4510 if (IsR6() && !is_bare) {
4511 Bcond(label, IsR6(), is_bare, kCondGE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004512 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004513 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004514 } else {
4515 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004516 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004517 Beqz(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004518 }
4519}
4520
Alexey Frunze0cab6562017-07-25 15:19:36 -07004521void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4522 if (IsR6() && !is_bare) {
4523 Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004524 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
4525 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004526 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004527 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004528 }
4529}
4530
Alexey Frunze0cab6562017-07-25 15:19:36 -07004531void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4532 if (IsR6() && !is_bare) {
4533 Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004534 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004535 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004536 } else {
4537 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004538 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004539 Beqz(AT, label, is_bare);
jeffhao7fbee072012-08-24 17:56:54 -07004540 }
4541}
4542
Alexey Frunze0cab6562017-07-25 15:19:36 -07004543void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) {
4544 Bc1f(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004545}
4546
Alexey Frunze0cab6562017-07-25 15:19:36 -07004547void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004548 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004549 Bcond(label, /* is_r6 */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004550}
4551
Alexey Frunze0cab6562017-07-25 15:19:36 -07004552void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) {
4553 Bc1t(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004554}
4555
Alexey Frunze0cab6562017-07-25 15:19:36 -07004556void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004557 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004558 Bcond(label, /* is_r6 */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004559}
4560
Alexey Frunze0cab6562017-07-25 15:19:36 -07004561void MipsAssembler::Bc(MipsLabel* label, bool is_bare) {
4562 Buncond(label, /* is_r6 */ true, is_bare);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004563}
4564
Alexey Frunze0cab6562017-07-25 15:19:36 -07004565void MipsAssembler::Balc(MipsLabel* label, bool is_bare) {
4566 Call(label, /* is_r6 */ true, is_bare);
4567}
4568
4569void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4570 Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt);
4571}
4572
4573void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4574 Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt);
4575}
4576
4577void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) {
4578 Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rt);
4579}
4580
4581void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) {
4582 Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rt);
4583}
4584
4585void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) {
4586 Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt);
4587}
4588
4589void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) {
4590 Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt);
4591}
4592
4593void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) {
4594 Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt);
4595}
4596
4597void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) {
4598 Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt);
4599}
4600
4601void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4602 Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt);
4603}
4604
4605void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4606 Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt);
4607}
4608
4609void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4610 Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt);
4611}
4612
4613void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4614 Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt);
4615}
4616
4617void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) {
4618 Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO);
4619}
4620
4621void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) {
4622 Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004623}
4624
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004625void MipsAssembler::AdjustBaseAndOffset(Register& base,
4626 int32_t& offset,
4627 bool is_doubleword,
4628 bool is_float) {
4629 // This method is used to adjust the base register and offset pair
4630 // for a load/store when the offset doesn't fit into int16_t.
4631 // It is assumed that `base + offset` is sufficiently aligned for memory
4632 // operands that are machine word in size or smaller. For doubleword-sized
4633 // operands it's assumed that `base` is a multiple of 8, while `offset`
4634 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
4635 // and spilled variables on the stack accessed relative to the stack
4636 // pointer register).
4637 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
4638 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4639
4640 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
4641 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
4642
4643 // IsInt<16> must be passed a signed value, hence the static cast below.
4644 if (IsInt<16>(offset) &&
4645 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
4646 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
4647 return;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004648 }
4649
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004650 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
4651 uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
4652
4653 // Do not load the whole 32-bit `offset` if it can be represented as
4654 // a sum of two 16-bit signed offsets. This can save an instruction or two.
4655 // To simplify matters, only do this for a symmetric range of offsets from
4656 // about -64KB to about +64KB, allowing further addition of 4 when accessing
4657 // 64-bit variables with two 32-bit accesses.
4658 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
4659 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4660 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4661 Addiu(AT, base, kMinOffsetForSimpleAdjustment);
4662 offset -= kMinOffsetForSimpleAdjustment;
4663 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4664 Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
4665 offset += kMinOffsetForSimpleAdjustment;
4666 } else if (IsR6()) {
4667 // On R6 take advantage of the aui instruction, e.g.:
4668 // aui AT, base, offset_high
4669 // lw reg_lo, offset_low(AT)
4670 // lw reg_hi, (offset_low+4)(AT)
4671 // or when offset_low+4 overflows int16_t:
4672 // aui AT, base, offset_high
4673 // addiu AT, AT, 8
4674 // lw reg_lo, (offset_low-8)(AT)
4675 // lw reg_hi, (offset_low-4)(AT)
4676 int16_t offset_high = High16Bits(offset);
4677 int16_t offset_low = Low16Bits(offset);
4678 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store.
4679 Aui(AT, base, offset_high);
4680 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
4681 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
4682 Addiu(AT, AT, kMipsDoublewordSize);
4683 offset_low -= kMipsDoublewordSize;
4684 }
4685 offset = offset_low;
4686 } else {
4687 // Do not load the whole 32-bit `offset` if it can be represented as
4688 // a sum of three 16-bit signed offsets. This can save an instruction.
4689 // To simplify matters, only do this for a symmetric range of offsets from
4690 // about -96KB to about +96KB, allowing further addition of 4 when accessing
4691 // 64-bit variables with two 32-bit accesses.
4692 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4693 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
4694 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4695 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
4696 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
4697 offset -= kMinOffsetForMediumAdjustment;
4698 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4699 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
4700 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
4701 offset += kMinOffsetForMediumAdjustment;
4702 } else {
4703 // Now that all shorter options have been exhausted, load the full 32-bit offset.
4704 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
4705 LoadConst32(AT, loaded_offset);
4706 Addu(AT, AT, base);
4707 offset -= loaded_offset;
4708 }
4709 }
4710 base = AT;
4711
4712 CHECK(IsInt<16>(offset));
4713 if (two_accesses) {
4714 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
4715 }
4716 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
4717}
4718
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004719void MipsAssembler::AdjustBaseOffsetAndElementSizeShift(Register& base,
4720 int32_t& offset,
4721 int& element_size_shift) {
4722 // This method is used to adjust the base register, offset and element_size_shift
4723 // for a vector load/store when the offset doesn't fit into allowed number of bits.
4724 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
4725 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
4726 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
4727 // If element_size_shift is non-negative at entry, it won't be changed, but offset
4728 // will be checked for appropriate alignment. If negative at entry, it will be
4729 // adjusted based on offset for maximum fit.
4730 // It's assumed that `base` is a multiple of 8.
4731 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4732
4733 if (element_size_shift >= 0) {
4734 CHECK_LE(element_size_shift, TIMES_8);
4735 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4736 } else if (IsAligned<kMipsDoublewordSize>(offset)) {
4737 element_size_shift = TIMES_8;
4738 } else if (IsAligned<kMipsWordSize>(offset)) {
4739 element_size_shift = TIMES_4;
4740 } else if (IsAligned<kMipsHalfwordSize>(offset)) {
4741 element_size_shift = TIMES_2;
4742 } else {
4743 element_size_shift = TIMES_1;
4744 }
4745
4746 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
4747 // will take.
4748 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
4749 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
4750 if (low == offset) {
4751 return; // `offset` fits into ld.df/st.df.
4752 }
4753
4754 // First, see if `offset` can be represented as a sum of two or three signed offsets.
4755 // This can save an instruction or two.
4756
4757 // Max int16_t that's a multiple of element size.
4758 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
4759 // Max ld.df/st.df offset that's a multiple of element size.
4760 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
4761 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
4762 const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment;
4763 const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset;
4764
4765 if (IsInt<16>(offset)) {
4766 Addiu(AT, base, offset);
4767 offset = 0;
4768 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4769 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4770 offset -= kMaxDeltaForSimpleAdjustment;
4771 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4772 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4773 offset += kMaxDeltaForSimpleAdjustment;
4774 } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4775 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4776 if (offset <= kMinOffsetForMediumAdjustment) {
4777 Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment);
4778 offset = 0;
4779 } else {
4780 Addiu(AT, AT, kMaxDeltaForSimpleAdjustment);
4781 offset -= kMinOffsetForMediumAdjustment;
4782 }
4783 } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4784 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4785 if (-kMinOffsetForMediumAdjustment <= offset) {
4786 Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment);
4787 offset = 0;
4788 } else {
4789 Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment);
4790 offset += kMinOffsetForMediumAdjustment;
4791 }
4792 } else {
4793 // 16-bit or smaller parts of `offset`:
4794 // |31 hi 16|15 mid 13-10|12-9 low 0|
4795 //
4796 // Instructions that supply each part as a signed integer addend:
4797 // |aui |addiu |ld.df/st.df |
4798 uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset`
4799 // (accounts for sign of `low`).
4800 tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu.
4801 int16_t mid = Low16Bits(tmp);
4802 int16_t hi = High16Bits(tmp);
4803 if (IsR6()) {
4804 Aui(AT, base, hi);
4805 } else {
4806 Lui(AT, hi);
4807 Addu(AT, AT, base);
4808 }
4809 if (mid != 0) {
4810 Addiu(AT, AT, mid);
4811 }
4812 offset = low;
4813 }
4814 base = AT;
4815 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4816 CHECK(IsInt<10>(offset >> element_size_shift));
4817}
4818
Alexey Frunze2923db72016-08-20 01:55:47 -07004819void MipsAssembler::LoadFromOffset(LoadOperandType type,
4820 Register reg,
4821 Register base,
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004822 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004823 LoadFromOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004824}
4825
4826void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004827 LoadSFromOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004828}
4829
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004830void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004831 LoadDFromOffset<>(reg, base, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004832}
4833
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004834void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) {
4835 LoadQFromOffset<>(reg, base, offset);
4836}
4837
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004838void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
4839 size_t size) {
4840 MipsManagedRegister dst = m_dst.AsMips();
4841 if (dst.IsNoRegister()) {
4842 CHECK_EQ(0u, size) << dst;
4843 } else if (dst.IsCoreRegister()) {
4844 CHECK_EQ(kMipsWordSize, size) << dst;
4845 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
4846 } else if (dst.IsRegisterPair()) {
4847 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4848 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
4849 } else if (dst.IsFRegister()) {
4850 if (size == kMipsWordSize) {
4851 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
4852 } else {
4853 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4854 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
4855 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08004856 } else if (dst.IsDRegister()) {
4857 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4858 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004859 }
jeffhao7fbee072012-08-24 17:56:54 -07004860}
4861
Alexey Frunze2923db72016-08-20 01:55:47 -07004862void MipsAssembler::StoreToOffset(StoreOperandType type,
4863 Register reg,
4864 Register base,
jeffhao7fbee072012-08-24 17:56:54 -07004865 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004866 StoreToOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004867}
4868
Goran Jakovljevicff734982015-08-24 12:58:55 +00004869void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004870 StoreSToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004871}
4872
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004873void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004874 StoreDToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004875}
4876
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004877void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) {
4878 StoreQToOffset<>(reg, base, offset);
4879}
4880
David Srbeckydd973932015-04-07 20:29:48 +01004881static dwarf::Reg DWARFReg(Register reg) {
4882 return dwarf::Reg::MipsCore(static_cast<int>(reg));
4883}
4884
Ian Rogers790a6b72014-04-01 10:36:00 -07004885constexpr size_t kFramePointerSize = 4;
4886
Vladimir Marko32248382016-05-19 10:37:24 +01004887void MipsAssembler::BuildFrame(size_t frame_size,
4888 ManagedRegister method_reg,
4889 ArrayRef<const ManagedRegister> callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07004890 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07004891 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004892 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07004893
4894 // Increase frame to required size.
4895 IncreaseFrameSize(frame_size);
4896
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004897 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07004898 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004899 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004900 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07004901 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07004902 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01004903 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07004904 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004905 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07004906 }
4907
4908 // Write out Method*.
4909 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
4910
4911 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00004912 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004913 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00004914 MipsManagedRegister reg = entry_spills.at(i).AsMips();
4915 if (reg.IsNoRegister()) {
4916 ManagedRegisterSpill spill = entry_spills.at(i);
4917 offset += spill.getSize();
4918 } else if (reg.IsCoreRegister()) {
4919 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004920 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004921 } else if (reg.IsFRegister()) {
4922 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004923 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004924 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004925 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
4926 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004927 }
jeffhao7fbee072012-08-24 17:56:54 -07004928 }
4929}
4930
4931void MipsAssembler::RemoveFrame(size_t frame_size,
Vladimir Marko32248382016-05-19 10:37:24 +01004932 ArrayRef<const ManagedRegister> callee_save_regs) {
jeffhao7fbee072012-08-24 17:56:54 -07004933 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004934 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01004935 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07004936
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004937 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07004938 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004939 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01004940 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07004941 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004942 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07004943 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004944 }
4945 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004946 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07004947
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004948 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
4949 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
4950 bool reordering = SetReorder(false);
4951 if (exchange) {
4952 // Jump to the return address.
4953 Jr(RA);
4954 // Decrease frame to required size.
4955 DecreaseFrameSize(frame_size); // Single instruction in delay slot.
4956 } else {
4957 // Decrease frame to required size.
4958 DecreaseFrameSize(frame_size);
4959 // Jump to the return address.
4960 Jr(RA);
4961 Nop(); // In delay slot.
4962 }
4963 SetReorder(reordering);
David Srbeckydd973932015-04-07 20:29:48 +01004964
4965 // The CFI should be restored for any code that follows the exit block.
4966 cfi_.RestoreState();
4967 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07004968}
4969
4970void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004971 CHECK_ALIGNED(adjust, kFramePointerSize);
4972 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01004973 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004974 if (overwriting_) {
4975 cfi_.OverrideDelayedPC(overwrite_location_);
4976 }
jeffhao7fbee072012-08-24 17:56:54 -07004977}
4978
4979void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004980 CHECK_ALIGNED(adjust, kFramePointerSize);
4981 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01004982 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004983 if (overwriting_) {
4984 cfi_.OverrideDelayedPC(overwrite_location_);
4985 }
jeffhao7fbee072012-08-24 17:56:54 -07004986}
4987
4988void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
4989 MipsManagedRegister src = msrc.AsMips();
4990 if (src.IsNoRegister()) {
4991 CHECK_EQ(0u, size);
4992 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004993 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07004994 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4995 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004996 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07004997 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
4998 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004999 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005000 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005001 if (size == kMipsWordSize) {
5002 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
5003 } else {
5004 CHECK_EQ(kMipsDoublewordSize, size);
5005 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
5006 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08005007 } else if (src.IsDRegister()) {
5008 CHECK_EQ(kMipsDoublewordSize, size);
5009 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005010 }
5011}
5012
5013void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
5014 MipsManagedRegister src = msrc.AsMips();
5015 CHECK(src.IsCoreRegister());
5016 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5017}
5018
5019void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
5020 MipsManagedRegister src = msrc.AsMips();
5021 CHECK(src.IsCoreRegister());
5022 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5023}
5024
5025void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
5026 ManagedRegister mscratch) {
5027 MipsManagedRegister scratch = mscratch.AsMips();
5028 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005029 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07005030 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
5031}
5032
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005033void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
5034 FrameOffset fr_offs,
jeffhao7fbee072012-08-24 17:56:54 -07005035 ManagedRegister mscratch) {
5036 MipsManagedRegister scratch = mscratch.AsMips();
5037 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005038 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005039 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5040 S1, thr_offs.Int32Value());
5041}
5042
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005043void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005044 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
5045}
5046
5047void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
5048 FrameOffset in_off, ManagedRegister mscratch) {
5049 MipsManagedRegister src = msrc.AsMips();
5050 MipsManagedRegister scratch = mscratch.AsMips();
5051 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5052 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005053 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005054}
5055
5056void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
5057 return EmitLoad(mdest, SP, src.Int32Value(), size);
5058}
5059
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005060void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005061 return EmitLoad(mdest, S1, src.Int32Value(), size);
5062}
5063
5064void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
5065 MipsManagedRegister dest = mdest.AsMips();
5066 CHECK(dest.IsCoreRegister());
5067 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
5068}
5069
Mathieu Chartiere401d142015-04-22 13:56:20 -07005070void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01005071 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07005072 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005073 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07005074 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
5075 base.AsMips().AsCoreRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08005076 if (unpoison_reference) {
5077 MaybeUnpoisonHeapReference(dest.AsCoreRegister());
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08005078 }
jeffhao7fbee072012-08-24 17:56:54 -07005079}
5080
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005081void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005082 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005083 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07005084 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
5085 base.AsMips().AsCoreRegister(), offs.Int32Value());
5086}
5087
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005088void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
jeffhao7fbee072012-08-24 17:56:54 -07005089 MipsManagedRegister dest = mdest.AsMips();
5090 CHECK(dest.IsCoreRegister());
5091 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
5092}
5093
5094void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
5095 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
5096}
5097
5098void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
5099 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
5100}
5101
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005102void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005103 MipsManagedRegister dest = mdest.AsMips();
5104 MipsManagedRegister src = msrc.AsMips();
5105 if (!dest.Equals(src)) {
5106 if (dest.IsCoreRegister()) {
5107 CHECK(src.IsCoreRegister()) << src;
5108 Move(dest.AsCoreRegister(), src.AsCoreRegister());
5109 } else if (dest.IsFRegister()) {
5110 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005111 if (size == kMipsWordSize) {
5112 MovS(dest.AsFRegister(), src.AsFRegister());
5113 } else {
5114 CHECK_EQ(kMipsDoublewordSize, size);
5115 MovD(dest.AsFRegister(), src.AsFRegister());
5116 }
jeffhao7fbee072012-08-24 17:56:54 -07005117 } else if (dest.IsDRegister()) {
5118 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005119 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07005120 } else {
5121 CHECK(dest.IsRegisterPair()) << dest;
5122 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005123 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07005124 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
5125 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
5126 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
5127 } else {
5128 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
5129 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
5130 }
5131 }
5132 }
5133}
5134
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005135void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005136 MipsManagedRegister scratch = mscratch.AsMips();
5137 CHECK(scratch.IsCoreRegister()) << scratch;
5138 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5139 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
5140}
5141
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005142void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
5143 ThreadOffset32 thr_offs,
5144 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005145 MipsManagedRegister scratch = mscratch.AsMips();
5146 CHECK(scratch.IsCoreRegister()) << scratch;
5147 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5148 S1, thr_offs.Int32Value());
5149 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5150 SP, fr_offs.Int32Value());
5151}
5152
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005153void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
5154 FrameOffset fr_offs,
5155 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005156 MipsManagedRegister scratch = mscratch.AsMips();
5157 CHECK(scratch.IsCoreRegister()) << scratch;
5158 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5159 SP, fr_offs.Int32Value());
5160 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5161 S1, thr_offs.Int32Value());
5162}
5163
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005164void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005165 MipsManagedRegister scratch = mscratch.AsMips();
5166 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005167 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
5168 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005169 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5170 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005171 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005172 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5173 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005174 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
5175 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005176 }
5177}
5178
5179void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
5180 ManagedRegister mscratch, size_t size) {
5181 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005182 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005183 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
5184 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
5185}
5186
5187void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
5188 ManagedRegister mscratch, size_t size) {
5189 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005190 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005191 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
5192 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5193}
5194
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005195void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5196 FrameOffset src_base ATTRIBUTE_UNUSED,
5197 Offset src_offset ATTRIBUTE_UNUSED,
5198 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5199 size_t size ATTRIBUTE_UNUSED) {
5200 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005201}
5202
5203void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
5204 ManagedRegister src, Offset src_offset,
5205 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005206 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005207 Register scratch = mscratch.AsMips().AsCoreRegister();
5208 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
5209 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5210}
5211
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005212void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5213 Offset dest_offset ATTRIBUTE_UNUSED,
5214 FrameOffset src ATTRIBUTE_UNUSED,
5215 Offset src_offset ATTRIBUTE_UNUSED,
5216 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5217 size_t size ATTRIBUTE_UNUSED) {
5218 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005219}
5220
5221void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005222 // TODO: sync?
5223 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005224}
5225
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005226void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005227 FrameOffset handle_scope_offset,
5228 ManagedRegister min_reg,
5229 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005230 MipsManagedRegister out_reg = mout_reg.AsMips();
5231 MipsManagedRegister in_reg = min_reg.AsMips();
5232 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
5233 CHECK(out_reg.IsCoreRegister()) << out_reg;
5234 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005235 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005236 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5237 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005238 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07005239 if (in_reg.IsNoRegister()) {
5240 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005241 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005242 in_reg = out_reg;
5243 }
5244 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005245 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005246 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005247 Beqz(in_reg.AsCoreRegister(), &null_arg);
5248 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5249 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005250 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005251 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005252 }
5253}
5254
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005255void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005256 FrameOffset handle_scope_offset,
5257 ManagedRegister mscratch,
5258 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005259 MipsManagedRegister scratch = mscratch.AsMips();
5260 CHECK(scratch.IsCoreRegister()) << scratch;
5261 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005262 MipsLabel null_arg;
5263 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005264 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5265 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005266 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
5267 Beqz(scratch.AsCoreRegister(), &null_arg);
5268 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5269 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005270 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005271 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005272 }
5273 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
5274}
5275
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005276// Given a handle scope entry, load the associated reference.
5277void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005278 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07005279 MipsManagedRegister out_reg = mout_reg.AsMips();
5280 MipsManagedRegister in_reg = min_reg.AsMips();
5281 CHECK(out_reg.IsCoreRegister()) << out_reg;
5282 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005283 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07005284 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005285 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005286 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005287 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005288 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
5289 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005290 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005291}
5292
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005293void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
5294 bool could_be_null ATTRIBUTE_UNUSED) {
5295 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005296}
5297
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005298void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
5299 bool could_be_null ATTRIBUTE_UNUSED) {
5300 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005301}
5302
5303void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
5304 MipsManagedRegister base = mbase.AsMips();
5305 MipsManagedRegister scratch = mscratch.AsMips();
5306 CHECK(base.IsCoreRegister()) << base;
5307 CHECK(scratch.IsCoreRegister()) << scratch;
5308 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5309 base.AsCoreRegister(), offset.Int32Value());
5310 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005311 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005312 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005313}
5314
5315void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
5316 MipsManagedRegister scratch = mscratch.AsMips();
5317 CHECK(scratch.IsCoreRegister()) << scratch;
5318 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005319 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005320 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5321 scratch.AsCoreRegister(), offset.Int32Value());
5322 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005323 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005324 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005325}
5326
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005327void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
5328 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07005329 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005330}
5331
5332void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
5333 Move(tr.AsMips().AsCoreRegister(), S1);
5334}
5335
5336void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005337 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07005338 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
5339}
5340
jeffhao7fbee072012-08-24 17:56:54 -07005341void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
5342 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005343 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07005344 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Andreas Gampe542451c2016-07-26 09:02:02 -07005345 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005346 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07005347}
5348
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005349void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
5350 Bind(exception->Entry());
5351 if (exception->stack_adjust_ != 0) { // Fix up the frame.
5352 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07005353 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005354 // Pass exception object as argument.
5355 // Don't care about preserving A0 as this call won't return.
5356 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5357 Move(A0, exception->scratch_.AsCoreRegister());
5358 // Set up call to Thread::Current()->pDeliverException.
5359 LoadFromOffset(kLoadWord, T9, S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07005360 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005361 Jr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005362 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005363
5364 // Call never returns.
5365 Break();
jeffhao7fbee072012-08-24 17:56:54 -07005366}
5367
5368} // namespace mips
5369} // namespace art