blob: 2218ef9af29e07a880480fa5e937b6f5b9dceaed [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),
Alexey Frunzea663d9d2017-07-31 18:43:18 -070045 patcher_label_(nullptr) {}
Alexey Frunze57eb0f52016-07-29 22:04:46 -070046
Alexey Frunzea247dea2017-11-03 18:43:04 -070047InOutRegMasks& MipsAssembler::DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -070048 if (!reordering_) {
49 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
50 CHECK_EQ(delay_slot_.instruction_, 0u);
Alexey Frunzea247dea2017-11-03 18:43:04 -070051 return delay_slot_.masks_;
Alexey Frunze57eb0f52016-07-29 22:04:46 -070052 }
53 switch (ds_fsm_state_) {
54 case kExpectingLabel:
55 break;
56 case kExpectingInstruction:
57 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
58 // If the last instruction is not suitable for delay slots, drop
59 // the PC of the label preceding it so that no unconditional branch
60 // uses this instruction to fill its delay slot.
61 if (instruction == 0) {
62 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
63 } else {
64 // Otherwise wait for another instruction or label before we can
65 // commit the label PC. The label PC will be dropped if instead
66 // of another instruction or label there's a call from the code
67 // generator to CodePosition() to record the buffer size.
68 // Instructions after which the buffer size is recorded cannot
69 // be moved into delay slots or anywhere else because they may
70 // trigger signals and the signal handlers expect these signals
71 // to be coming from the instructions immediately preceding the
72 // recorded buffer locations.
73 ds_fsm_state_ = kExpectingCommit;
74 }
75 break;
76 case kExpectingCommit:
77 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size());
78 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
79 break;
80 }
81 delay_slot_.instruction_ = instruction;
Alexey Frunzea247dea2017-11-03 18:43:04 -070082 delay_slot_.masks_ = InOutRegMasks();
Alexey Frunzea663d9d2017-07-31 18:43:18 -070083 delay_slot_.patcher_label_ = patcher_label;
Alexey Frunzea247dea2017-11-03 18:43:04 -070084 return delay_slot_.masks_;
Alexey Frunze57eb0f52016-07-29 22:04:46 -070085}
86
87void MipsAssembler::DsFsmLabel() {
88 if (!reordering_) {
89 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
90 CHECK_EQ(delay_slot_.instruction_, 0u);
91 return;
92 }
93 switch (ds_fsm_state_) {
94 case kExpectingLabel:
95 ds_fsm_target_pc_ = buffer_.Size();
96 ds_fsm_state_ = kExpectingInstruction;
97 break;
98 case kExpectingInstruction:
99 // Allow consecutive labels.
100 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size());
101 break;
102 case kExpectingCommit:
103 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
104 DsFsmCommitLabel();
105 ds_fsm_target_pc_ = buffer_.Size();
106 ds_fsm_state_ = kExpectingInstruction;
107 break;
108 }
109 // We cannot move instructions into delay slots across labels.
110 delay_slot_.instruction_ = 0;
111}
112
113void MipsAssembler::DsFsmCommitLabel() {
114 if (ds_fsm_state_ == kExpectingCommit) {
115 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_);
116 }
117 ds_fsm_state_ = kExpectingLabel;
118}
119
120void MipsAssembler::DsFsmDropLabel() {
121 ds_fsm_state_ = kExpectingLabel;
122}
123
124bool MipsAssembler::SetReorder(bool enable) {
125 bool last_state = reordering_;
126 if (last_state != enable) {
127 DsFsmCommitLabel();
128 DsFsmInstrNop(0);
129 }
130 reordering_ = enable;
131 return last_state;
132}
133
134size_t MipsAssembler::CodePosition() {
135 // The last instruction cannot be used in a delay slot, do not commit
136 // the label before it (if any) and clear the delay slot.
137 DsFsmDropLabel();
138 DsFsmInstrNop(0);
139 size_t size = buffer_.Size();
140 // In theory we can get the following sequence:
141 // label1:
142 // instr
143 // label2: # label1 gets committed when label2 is seen
144 // CodePosition() call
145 // and we need to uncommit label1.
146 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) {
147 ds_fsm_target_pcs_.pop_back();
148 }
149 return size;
150}
151
152void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700153 DsFsmInstr(0);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700154}
155
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200156void MipsAssembler::FinalizeCode() {
157 for (auto& exception_block : exception_blocks_) {
158 EmitExceptionPoll(&exception_block);
159 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700160 // Commit the last branch target label (if any) and disable instruction reordering.
161 DsFsmCommitLabel();
162 SetReorder(false);
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700163 EmitLiterals();
Alexey Frunze96b66822016-09-10 02:32:44 -0700164 ReserveJumpTableSpace();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200165 PromoteBranches();
166}
167
168void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
Vladimir Marko10ef6942015-10-22 15:25:54 +0100169 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200170 EmitBranches();
Alexey Frunze96b66822016-09-10 02:32:44 -0700171 EmitJumpTables();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200172 Assembler::FinalizeInstructions(region);
Vladimir Marko10ef6942015-10-22 15:25:54 +0100173 PatchCFI(number_of_delayed_adjust_pcs);
174}
175
176void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
177 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
178 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
179 return;
180 }
181
182 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
183 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
184 const std::vector<uint8_t>& old_stream = data.first;
185 const std::vector<DelayedAdvancePC>& advances = data.second;
186
187 // PCs recorded before EmitBranches() need to be adjusted.
188 // PCs recorded during EmitBranches() are already adjusted.
189 // Both ranges are separately sorted but they may overlap.
190 if (kIsDebugBuild) {
191 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
192 return lhs.pc < rhs.pc;
193 };
194 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
195 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
196 }
197
198 // Append initial CFI data if any.
199 size_t size = advances.size();
200 DCHECK_NE(size, 0u);
201 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
202 // Emit PC adjustments interleaved with the old CFI stream.
203 size_t adjust_pos = 0u;
204 size_t late_emit_pos = number_of_delayed_adjust_pcs;
205 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
206 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
207 ? GetAdjustedPosition(advances[adjust_pos].pc)
208 : static_cast<size_t>(-1);
209 size_t late_emit_pc = (late_emit_pos != size)
210 ? advances[late_emit_pos].pc
211 : static_cast<size_t>(-1);
212 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
213 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
214 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
215 if (adjusted_pc <= late_emit_pc) {
216 ++adjust_pos;
217 } else {
218 ++late_emit_pos;
219 }
220 cfi().AdvancePC(advance_pc);
221 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
222 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
223 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200224}
225
226void MipsAssembler::EmitBranches() {
227 CHECK(!overwriting_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700228 CHECK(!reordering_);
229 // Now that everything has its final position in the buffer (the branches have
230 // been promoted), adjust the target label PCs.
231 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) {
232 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]);
233 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200234 // Switch from appending instructions at the end of the buffer to overwriting
235 // existing instructions (branch placeholders) in the buffer.
236 overwriting_ = true;
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700237 for (size_t id = 0; id < branches_.size(); id++) {
238 EmitBranch(id);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200239 }
240 overwriting_ = false;
241}
242
243void MipsAssembler::Emit(uint32_t value) {
244 if (overwriting_) {
245 // Branches to labels are emitted into their placeholders here.
246 buffer_.Store<uint32_t>(overwrite_location_, value);
247 overwrite_location_ += sizeof(uint32_t);
248 } else {
249 // Other instructions are simply appended at the end here.
250 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
251 buffer_.Emit<uint32_t>(value);
252 }
jeffhao7fbee072012-08-24 17:56:54 -0700253}
254
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700255uint32_t MipsAssembler::EmitR(int opcode,
256 Register rs,
257 Register rt,
258 Register rd,
259 int shamt,
260 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700261 CHECK_NE(rs, kNoRegister);
262 CHECK_NE(rt, kNoRegister);
263 CHECK_NE(rd, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200264 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
265 static_cast<uint32_t>(rs) << kRsShift |
266 static_cast<uint32_t>(rt) << kRtShift |
267 static_cast<uint32_t>(rd) << kRdShift |
268 shamt << kShamtShift |
269 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700270 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700271 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700272}
273
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700274uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
jeffhao7fbee072012-08-24 17:56:54 -0700275 CHECK_NE(rs, kNoRegister);
276 CHECK_NE(rt, kNoRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200277 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
278 static_cast<uint32_t>(rs) << kRsShift |
279 static_cast<uint32_t>(rt) << kRtShift |
280 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700281 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700282 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700283}
284
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700285uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200286 CHECK_NE(rs, kNoRegister);
287 CHECK(IsUint<21>(imm21)) << imm21;
288 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
289 static_cast<uint32_t>(rs) << kRsShift |
290 imm21;
jeffhao7fbee072012-08-24 17:56:54 -0700291 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700292 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700293}
294
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700295uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200296 CHECK(IsUint<26>(imm26)) << imm26;
297 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
298 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700299 return encoding;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200300}
301
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700302uint32_t MipsAssembler::EmitFR(int opcode,
303 int fmt,
304 FRegister ft,
305 FRegister fs,
306 FRegister fd,
307 int funct) {
jeffhao7fbee072012-08-24 17:56:54 -0700308 CHECK_NE(ft, kNoFRegister);
309 CHECK_NE(fs, kNoFRegister);
310 CHECK_NE(fd, kNoFRegister);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200311 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
312 fmt << kFmtShift |
313 static_cast<uint32_t>(ft) << kFtShift |
314 static_cast<uint32_t>(fs) << kFsShift |
315 static_cast<uint32_t>(fd) << kFdShift |
316 funct;
jeffhao7fbee072012-08-24 17:56:54 -0700317 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700318 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700319}
320
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700321uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200322 CHECK_NE(ft, kNoFRegister);
323 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
324 fmt << kFmtShift |
325 static_cast<uint32_t>(ft) << kFtShift |
326 imm;
jeffhao7fbee072012-08-24 17:56:54 -0700327 Emit(encoding);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700328 return encoding;
jeffhao7fbee072012-08-24 17:56:54 -0700329}
330
Lena Djokic0758ae72017-05-23 11:06:23 +0200331uint32_t MipsAssembler::EmitMsa3R(int operation,
332 int df,
333 VectorRegister wt,
334 VectorRegister ws,
335 VectorRegister wd,
336 int minor_opcode) {
337 CHECK_NE(wt, kNoVectorRegister);
338 CHECK_NE(ws, kNoVectorRegister);
339 CHECK_NE(wd, kNoVectorRegister);
340 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
341 operation << kMsaOperationShift |
342 df << kDfShift |
343 static_cast<uint32_t>(wt) << kWtShift |
344 static_cast<uint32_t>(ws) << kWsShift |
345 static_cast<uint32_t>(wd) << kWdShift |
346 minor_opcode;
347 Emit(encoding);
348 return encoding;
349}
350
351uint32_t MipsAssembler::EmitMsaBIT(int operation,
352 int df_m,
353 VectorRegister ws,
354 VectorRegister wd,
355 int minor_opcode) {
356 CHECK_NE(ws, kNoVectorRegister);
357 CHECK_NE(wd, kNoVectorRegister);
358 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
359 operation << kMsaOperationShift |
360 df_m << kDfMShift |
361 static_cast<uint32_t>(ws) << kWsShift |
362 static_cast<uint32_t>(wd) << kWdShift |
363 minor_opcode;
364 Emit(encoding);
365 return encoding;
366}
367
368uint32_t MipsAssembler::EmitMsaELM(int operation,
369 int df_n,
370 VectorRegister ws,
371 VectorRegister wd,
372 int minor_opcode) {
373 CHECK_NE(ws, kNoVectorRegister);
374 CHECK_NE(wd, kNoVectorRegister);
375 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
376 operation << kMsaELMOperationShift |
377 df_n << kDfNShift |
378 static_cast<uint32_t>(ws) << kWsShift |
379 static_cast<uint32_t>(wd) << kWdShift |
380 minor_opcode;
381 Emit(encoding);
382 return encoding;
383}
384
385uint32_t MipsAssembler::EmitMsaMI10(int s10,
386 Register rs,
387 VectorRegister wd,
388 int minor_opcode,
389 int df) {
390 CHECK_NE(rs, kNoRegister);
391 CHECK_NE(wd, kNoVectorRegister);
392 CHECK(IsUint<10>(s10)) << s10;
393 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
394 s10 << kS10Shift |
395 static_cast<uint32_t>(rs) << kWsShift |
396 static_cast<uint32_t>(wd) << kWdShift |
397 minor_opcode << kS10MinorShift |
398 df;
399 Emit(encoding);
400 return encoding;
401}
402
403uint32_t MipsAssembler::EmitMsaI10(int operation,
404 int df,
405 int i10,
406 VectorRegister wd,
407 int minor_opcode) {
408 CHECK_NE(wd, kNoVectorRegister);
409 CHECK(IsUint<10>(i10)) << i10;
410 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
411 operation << kMsaOperationShift |
412 df << kDfShift |
413 i10 << kI10Shift |
414 static_cast<uint32_t>(wd) << kWdShift |
415 minor_opcode;
416 Emit(encoding);
417 return encoding;
418}
419
420uint32_t MipsAssembler::EmitMsa2R(int operation,
421 int df,
422 VectorRegister ws,
423 VectorRegister wd,
424 int minor_opcode) {
425 CHECK_NE(ws, kNoVectorRegister);
426 CHECK_NE(wd, kNoVectorRegister);
427 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
428 operation << kMsa2ROperationShift |
429 df << kDf2RShift |
430 static_cast<uint32_t>(ws) << kWsShift |
431 static_cast<uint32_t>(wd) << kWdShift |
432 minor_opcode;
433 Emit(encoding);
434 return encoding;
435}
436
437uint32_t MipsAssembler::EmitMsa2RF(int operation,
438 int df,
439 VectorRegister ws,
440 VectorRegister wd,
441 int minor_opcode) {
442 CHECK_NE(ws, kNoVectorRegister);
443 CHECK_NE(wd, kNoVectorRegister);
444 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
445 operation << kMsa2RFOperationShift |
446 df << kDf2RShift |
447 static_cast<uint32_t>(ws) << kWsShift |
448 static_cast<uint32_t>(wd) << kWdShift |
449 minor_opcode;
450 Emit(encoding);
451 return encoding;
452}
453
jeffhao7fbee072012-08-24 17:56:54 -0700454void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700455 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x21)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700456}
457
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700458void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
459 if (patcher_label != nullptr) {
460 Bind(patcher_label);
461 }
Alexey Frunzea247dea2017-11-03 18:43:04 -0700462 DsFsmInstr(EmitI(0x9, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs);
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700463}
464
jeffhao7fbee072012-08-24 17:56:54 -0700465void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700466 Addiu(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700467}
468
jeffhao7fbee072012-08-24 17:56:54 -0700469void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700470 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x23)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700471}
472
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200473void MipsAssembler::MultR2(Register rs, Register rt) {
474 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700475 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18)).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700476}
477
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200478void MipsAssembler::MultuR2(Register rs, Register rt) {
479 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700480 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19)).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700481}
482
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200483void MipsAssembler::DivR2(Register rs, Register rt) {
484 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700485 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a)).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700486}
487
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200488void MipsAssembler::DivuR2(Register rs, Register rt) {
489 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700490 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b)).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700491}
492
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200493void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
494 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700495 DsFsmInstr(EmitR(0x1c, rs, rt, rd, 0, 2)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200496}
497
498void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
499 CHECK(!IsR6());
500 DivR2(rs, rt);
501 Mflo(rd);
502}
503
504void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
505 CHECK(!IsR6());
506 DivR2(rs, rt);
507 Mfhi(rd);
508}
509
510void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
511 CHECK(!IsR6());
512 DivuR2(rs, rt);
513 Mflo(rd);
514}
515
516void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
517 CHECK(!IsR6());
518 DivuR2(rs, rt);
519 Mfhi(rd);
520}
521
522void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
523 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700524 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x18)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200525}
526
Alexey Frunze7e99e052015-11-24 19:28:01 -0800527void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
528 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700529 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x18)).GprOuts(rd).GprIns(rs, rt);
Alexey Frunze7e99e052015-11-24 19:28:01 -0800530}
531
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200532void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
533 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700534 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x19)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200535}
536
537void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
538 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700539 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1a)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200540}
541
542void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
543 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700544 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1a)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200545}
546
547void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
548 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700549 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1b)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200550}
551
552void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
553 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700554 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1b)).GprOuts(rd).GprIns(rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200555}
556
jeffhao7fbee072012-08-24 17:56:54 -0700557void MipsAssembler::And(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700558 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x24)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700559}
560
561void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700562 DsFsmInstr(EmitI(0xc, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700563}
564
565void MipsAssembler::Or(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700566 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x25)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700567}
568
569void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700570 DsFsmInstr(EmitI(0xd, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700571}
572
573void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700574 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x26)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700575}
576
577void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700578 DsFsmInstr(EmitI(0xe, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700579}
580
581void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700582 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x27)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700583}
584
Chris Larsene3845472015-11-18 12:27:15 -0800585void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
586 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700587 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0A)).GprInOuts(rd).GprIns(rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800588}
589
590void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
591 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700592 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0B)).GprInOuts(rd).GprIns(rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800593}
594
595void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
596 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700597 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x35)).GprOuts(rd).GprIns(rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800598}
599
600void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
601 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700602 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x37)).GprOuts(rd).GprIns(rs, rt);
Chris Larsene3845472015-11-18 12:27:15 -0800603}
604
605void MipsAssembler::ClzR6(Register rd, Register rs) {
606 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700607 DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10)).GprOuts(rd).GprIns(rs);
Chris Larsene3845472015-11-18 12:27:15 -0800608}
609
610void MipsAssembler::ClzR2(Register rd, Register rs) {
611 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700612 DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x20)).GprOuts(rd).GprIns(rs);
Chris Larsene3845472015-11-18 12:27:15 -0800613}
614
615void MipsAssembler::CloR6(Register rd, Register rs) {
616 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700617 DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11)).GprOuts(rd).GprIns(rs);
Chris Larsene3845472015-11-18 12:27:15 -0800618}
619
620void MipsAssembler::CloR2(Register rd, Register rs) {
621 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700622 DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x21)).GprOuts(rd).GprIns(rs);
Chris Larsene3845472015-11-18 12:27:15 -0800623}
624
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200625void MipsAssembler::Seb(Register rd, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700626 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20)).GprOuts(rd).GprIns(rt);
jeffhao7fbee072012-08-24 17:56:54 -0700627}
628
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200629void MipsAssembler::Seh(Register rd, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700630 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20)).GprOuts(rd).GprIns(rt);
jeffhao7fbee072012-08-24 17:56:54 -0700631}
632
Chris Larsen3f8bf652015-10-28 10:08:56 -0700633void MipsAssembler::Wsbh(Register rd, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700634 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20)).GprOuts(rd).GprIns(rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700635}
636
Chris Larsen70014c82015-11-18 12:26:08 -0800637void MipsAssembler::Bitswap(Register rd, Register rt) {
638 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700639 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20)).GprOuts(rd).GprIns(rt);
Chris Larsen70014c82015-11-18 12:26:08 -0800640}
641
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200642void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700643 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700644 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00)).GprOuts(rd).GprIns(rt);
jeffhao7fbee072012-08-24 17:56:54 -0700645}
646
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200647void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700648 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700649 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200650}
651
Chris Larsen3f8bf652015-10-28 10:08:56 -0700652void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
653 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700654 DsFsmInstr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700655}
656
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200657void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700658 CHECK(IsUint<5>(shamt)) << shamt;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700659 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03)).GprOuts(rd).GprIns(rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200660}
661
662void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700663 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x04)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700664}
665
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200666void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700667 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x06)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700668}
669
Chris Larsene16ce5a2015-11-18 12:30:20 -0800670void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700671 DsFsmInstr(EmitR(0, rs, rt, rd, 1, 0x06)).GprOuts(rd).GprIns(rs, rt);
Chris Larsene16ce5a2015-11-18 12:30:20 -0800672}
673
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200674void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700675 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x07)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700676}
677
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800678void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
679 CHECK(IsUint<5>(pos)) << pos;
680 CHECK(0 < size && size <= 32) << size;
681 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700682 DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00))
683 .GprOuts(rd).GprIns(rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800684}
685
686void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
687 CHECK(IsUint<5>(pos)) << pos;
688 CHECK(0 < size && size <= 32) << size;
689 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700690 DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04))
691 .GprInOuts(rd).GprIns(rt);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800692}
693
Chris Larsen692235e2016-11-21 16:04:53 -0800694void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
Lena Djokic0758ae72017-05-23 11:06:23 +0200695 CHECK(IsR6() || HasMsa());
Chris Larsen692235e2016-11-21 16:04:53 -0800696 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
697 int sa = saPlusOne - 1;
Alexey Frunzea247dea2017-11-03 18:43:04 -0700698 DsFsmInstr(EmitR(0x0, rs, rt, rd, sa, 0x05)).GprOuts(rd).GprIns(rs, rt);
Chris Larsen692235e2016-11-21 16:04:53 -0800699}
700
Chris Larsencd0295d2017-03-31 15:26:54 -0700701void MipsAssembler::ShiftAndAdd(Register dst,
702 Register src_idx,
703 Register src_base,
704 int shamt,
705 Register tmp) {
706 CHECK(0 <= shamt && shamt <= 4) << shamt;
707 CHECK_NE(src_base, tmp);
708 if (shamt == TIMES_1) {
709 // Catch the special case where the shift amount is zero (0).
710 Addu(dst, src_base, src_idx);
Lena Djokic0758ae72017-05-23 11:06:23 +0200711 } else if (IsR6() || HasMsa()) {
Chris Larsencd0295d2017-03-31 15:26:54 -0700712 Lsa(dst, src_idx, src_base, shamt);
713 } else {
714 Sll(tmp, src_idx, shamt);
715 Addu(dst, src_base, tmp);
716 }
717}
718
jeffhao7fbee072012-08-24 17:56:54 -0700719void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700720 DsFsmInstr(EmitI(0x20, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700721}
722
723void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700724 DsFsmInstr(EmitI(0x21, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700725}
726
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700727void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
728 if (patcher_label != nullptr) {
729 Bind(patcher_label);
730 }
Alexey Frunzea247dea2017-11-03 18:43:04 -0700731 DsFsmInstr(EmitI(0x23, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs);
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700732}
733
jeffhao7fbee072012-08-24 17:56:54 -0700734void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700735 Lw(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700736}
737
Chris Larsen3acee732015-11-18 13:31:08 -0800738void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
739 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700740 DsFsmInstr(EmitI(0x22, rs, rt, imm16)).GprInOuts(rt).GprIns(rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800741}
742
743void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
744 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700745 DsFsmInstr(EmitI(0x26, rs, rt, imm16)).GprInOuts(rt).GprIns(rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800746}
747
jeffhao7fbee072012-08-24 17:56:54 -0700748void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700749 DsFsmInstr(EmitI(0x24, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700750}
751
752void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700753 DsFsmInstr(EmitI(0x25, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700754}
755
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700756void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
757 CHECK(IsR6());
758 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700759 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700760}
761
jeffhao7fbee072012-08-24 17:56:54 -0700762void MipsAssembler::Lui(Register rt, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700763 DsFsmInstr(EmitI(0xf, static_cast<Register>(0), rt, imm16)).GprOuts(rt);
jeffhao7fbee072012-08-24 17:56:54 -0700764}
765
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700766void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
767 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700768 DsFsmInstr(EmitI(0xf, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -0700769}
770
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700771void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) {
772 bool increment = (rs == rt);
773 if (increment) {
774 CHECK_NE(rs, tmp);
775 }
776 if (IsR6()) {
777 Aui(rt, rs, imm16);
778 } else if (increment) {
779 Lui(tmp, imm16);
780 Addu(rt, rs, tmp);
781 } else {
782 Lui(rt, imm16);
783 Addu(rt, rs, rt);
784 }
785}
786
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200787void MipsAssembler::Sync(uint32_t stype) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700788 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200789}
790
jeffhao7fbee072012-08-24 17:56:54 -0700791void MipsAssembler::Mfhi(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200792 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700793 DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x10)).GprOuts(rd);
jeffhao7fbee072012-08-24 17:56:54 -0700794}
795
796void MipsAssembler::Mflo(Register rd) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200797 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700798 DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x12)).GprOuts(rd);
jeffhao7fbee072012-08-24 17:56:54 -0700799}
800
801void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700802 DsFsmInstr(EmitI(0x28, rs, rt, imm16)).GprIns(rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700803}
804
805void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700806 DsFsmInstr(EmitI(0x29, rs, rt, imm16)).GprIns(rt, rs);
jeffhao7fbee072012-08-24 17:56:54 -0700807}
808
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700809void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
810 if (patcher_label != nullptr) {
811 Bind(patcher_label);
812 }
Alexey Frunzea247dea2017-11-03 18:43:04 -0700813 DsFsmInstr(EmitI(0x2b, rs, rt, imm16), patcher_label).GprIns(rt, rs);
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700814}
815
jeffhao7fbee072012-08-24 17:56:54 -0700816void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700817 Sw(rt, rs, imm16, /* patcher_label */ nullptr);
jeffhao7fbee072012-08-24 17:56:54 -0700818}
819
Chris Larsen3acee732015-11-18 13:31:08 -0800820void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
821 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700822 DsFsmInstr(EmitI(0x2a, rs, rt, imm16)).GprIns(rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800823}
824
825void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
826 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700827 DsFsmInstr(EmitI(0x2e, rs, rt, imm16)).GprIns(rt, rs);
Chris Larsen3acee732015-11-18 13:31:08 -0800828}
829
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700830void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
831 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700832 DsFsmInstr(EmitI(0x30, base, rt, imm16)).GprOuts(rt).GprIns(base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700833}
834
835void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
836 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -0700837 DsFsmInstr(EmitI(0x38, base, rt, imm16)).GprInOuts(rt).GprIns(base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700838}
839
840void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
841 CHECK(IsR6());
842 CHECK(IsInt<9>(imm9));
Alexey Frunzea247dea2017-11-03 18:43:04 -0700843 DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36)).GprOuts(rt).GprIns(base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700844}
845
846void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
847 CHECK(IsR6());
848 CHECK(IsInt<9>(imm9));
Alexey Frunzea247dea2017-11-03 18:43:04 -0700849 DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26)).GprInOuts(rt).GprIns(base);
Alexey Frunze51aff3a2016-03-17 17:21:45 -0700850}
851
jeffhao7fbee072012-08-24 17:56:54 -0700852void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700853 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2a)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700854}
855
856void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700857 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2b)).GprOuts(rd).GprIns(rs, rt);
jeffhao7fbee072012-08-24 17:56:54 -0700858}
859
860void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700861 DsFsmInstr(EmitI(0xa, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700862}
863
864void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -0700865 DsFsmInstr(EmitI(0xb, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -0700866}
867
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200868void MipsAssembler::B(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700869 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200870}
871
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700872void MipsAssembler::Bal(uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700873 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16));
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700874}
875
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200876void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700877 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700878}
879
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200880void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700881 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16));
jeffhao7fbee072012-08-24 17:56:54 -0700882}
883
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200884void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700885 Beq(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700886}
887
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200888void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
Alexey Frunze0cab6562017-07-25 15:19:36 -0700889 Bne(rt, ZERO, imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700890}
891
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200892void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700893 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200894}
895
896void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700897 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200898}
899
900void MipsAssembler::Blez(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700901 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200902}
903
904void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700905 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200906}
907
Chris Larsenb74353a2015-11-20 09:07:09 -0800908void MipsAssembler::Bc1f(uint16_t imm16) {
909 Bc1f(0, imm16);
910}
911
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800912void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
913 CHECK(!IsR6());
914 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700915 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800916}
917
Chris Larsenb74353a2015-11-20 09:07:09 -0800918void MipsAssembler::Bc1t(uint16_t imm16) {
919 Bc1t(0, imm16);
920}
921
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800922void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
923 CHECK(!IsR6());
924 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700925 DsFsmInstrNop(EmitI(0x11,
926 static_cast<Register>(0x8),
927 static_cast<Register>((cc << 2) | 1),
928 imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800929}
930
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200931void MipsAssembler::J(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700932 DsFsmInstrNop(EmitI26(0x2, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200933}
934
935void MipsAssembler::Jal(uint32_t addr26) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700936 DsFsmInstrNop(EmitI26(0x3, addr26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200937}
938
939void MipsAssembler::Jalr(Register rd, Register rs) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700940 uint32_t last_instruction = delay_slot_.instruction_;
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700941 MipsLabel* patcher_label = delay_slot_.patcher_label_;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700942 bool exchange = (last_instruction != 0 &&
Alexey Frunzea247dea2017-11-03 18:43:04 -0700943 (delay_slot_.masks_.gpr_outs_ & (1u << rs)) == 0 &&
944 ((delay_slot_.masks_.gpr_ins_ | delay_slot_.masks_.gpr_outs_) & (1u << rd)) == 0);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700945 if (exchange) {
946 // The last instruction cannot be used in a different delay slot,
947 // do not commit the label before it (if any).
948 DsFsmDropLabel();
949 }
950 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09));
951 if (exchange) {
952 // Exchange the last two instructions in the assembler buffer.
953 size_t size = buffer_.Size();
954 CHECK_GE(size, 2 * sizeof(uint32_t));
955 size_t pos1 = size - 2 * sizeof(uint32_t);
956 size_t pos2 = size - sizeof(uint32_t);
957 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
958 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
959 CHECK_EQ(instr1, last_instruction);
960 buffer_.Store<uint32_t>(pos1, instr2);
961 buffer_.Store<uint32_t>(pos2, instr1);
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700962 // Move the patcher label along with the patched instruction.
963 if (patcher_label != nullptr) {
964 patcher_label->AdjustBoundPosition(sizeof(uint32_t));
965 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700966 } else if (reordering_) {
967 Nop();
968 }
jeffhao7fbee072012-08-24 17:56:54 -0700969}
970
971void MipsAssembler::Jalr(Register rs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200972 Jalr(RA, rs);
973}
974
975void MipsAssembler::Jr(Register rs) {
976 Jalr(ZERO, rs);
977}
978
979void MipsAssembler::Nal() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700980 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200981}
982
983void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
984 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700985 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200986}
987
988void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
989 CHECK(IsR6());
990 CHECK(IsUint<19>(imm19)) << imm19;
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700991 DsFsmInstrNop(EmitI21(0x3B, rs, imm19));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200992}
993
994void MipsAssembler::Bc(uint32_t imm26) {
995 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700996 DsFsmInstrNop(EmitI26(0x32, imm26));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200997}
998
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700999void MipsAssembler::Balc(uint32_t imm26) {
1000 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001001 DsFsmInstrNop(EmitI26(0x3A, imm26));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001002}
1003
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001004void MipsAssembler::Jic(Register rt, uint16_t imm16) {
1005 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001006 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001007}
1008
1009void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
1010 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001011 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001012}
1013
1014void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
1015 CHECK(IsR6());
1016 CHECK_NE(rs, ZERO);
1017 CHECK_NE(rt, ZERO);
1018 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001019 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001020}
1021
1022void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
1023 CHECK(IsR6());
1024 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001025 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001026}
1027
1028void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
1029 CHECK(IsR6());
1030 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001031 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001032}
1033
1034void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
1035 CHECK(IsR6());
1036 CHECK_NE(rs, ZERO);
1037 CHECK_NE(rt, ZERO);
1038 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001039 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001040}
1041
1042void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
1043 CHECK(IsR6());
1044 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001045 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001046}
1047
1048void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
1049 CHECK(IsR6());
1050 CHECK_NE(rt, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001051 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001052}
1053
1054void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
1055 CHECK(IsR6());
1056 CHECK_NE(rs, ZERO);
1057 CHECK_NE(rt, ZERO);
1058 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001059 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001060}
1061
1062void MipsAssembler::Bgeuc(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(0x6, rs, rt, imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001068}
1069
1070void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
1071 CHECK(IsR6());
1072 CHECK_NE(rs, ZERO);
1073 CHECK_NE(rt, ZERO);
1074 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001075 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001076}
1077
1078void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
1079 CHECK(IsR6());
1080 CHECK_NE(rs, ZERO);
1081 CHECK_NE(rt, ZERO);
1082 CHECK_NE(rs, rt);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001083 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001084}
1085
1086void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
1087 CHECK(IsR6());
1088 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001089 DsFsmInstrNop(EmitI21(0x36, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001090}
1091
1092void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
1093 CHECK(IsR6());
1094 CHECK_NE(rs, ZERO);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001095 DsFsmInstrNop(EmitI21(0x3E, rs, imm21));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001096}
1097
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001098void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
1099 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001100 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001101}
1102
1103void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
1104 CHECK(IsR6());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001105 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16));
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001106}
1107
1108void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001109 switch (cond) {
1110 case kCondLTZ:
1111 CHECK_EQ(rt, ZERO);
1112 Bltz(rs, imm16);
1113 break;
1114 case kCondGEZ:
1115 CHECK_EQ(rt, ZERO);
1116 Bgez(rs, imm16);
1117 break;
1118 case kCondLEZ:
1119 CHECK_EQ(rt, ZERO);
1120 Blez(rs, imm16);
1121 break;
1122 case kCondGTZ:
1123 CHECK_EQ(rt, ZERO);
1124 Bgtz(rs, imm16);
1125 break;
1126 case kCondEQ:
1127 Beq(rs, rt, imm16);
1128 break;
1129 case kCondNE:
1130 Bne(rs, rt, imm16);
1131 break;
1132 case kCondEQZ:
1133 CHECK_EQ(rt, ZERO);
1134 Beqz(rs, imm16);
1135 break;
1136 case kCondNEZ:
1137 CHECK_EQ(rt, ZERO);
1138 Bnez(rs, imm16);
1139 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001140 case kCondF:
1141 CHECK_EQ(rt, ZERO);
1142 Bc1f(static_cast<int>(rs), imm16);
1143 break;
1144 case kCondT:
1145 CHECK_EQ(rt, ZERO);
1146 Bc1t(static_cast<int>(rs), imm16);
1147 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001148 case kCondLT:
1149 case kCondGE:
1150 case kCondLE:
1151 case kCondGT:
1152 case kCondLTU:
1153 case kCondGEU:
1154 case kUncond:
1155 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1156 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1157 LOG(FATAL) << "Unexpected branch condition " << cond;
1158 UNREACHABLE();
1159 }
1160}
1161
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001162void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001163 switch (cond) {
1164 case kCondLT:
1165 Bltc(rs, rt, imm16_21);
1166 break;
1167 case kCondGE:
1168 Bgec(rs, rt, imm16_21);
1169 break;
1170 case kCondLE:
1171 Bgec(rt, rs, imm16_21);
1172 break;
1173 case kCondGT:
1174 Bltc(rt, rs, imm16_21);
1175 break;
1176 case kCondLTZ:
1177 CHECK_EQ(rt, ZERO);
1178 Bltzc(rs, imm16_21);
1179 break;
1180 case kCondGEZ:
1181 CHECK_EQ(rt, ZERO);
1182 Bgezc(rs, imm16_21);
1183 break;
1184 case kCondLEZ:
1185 CHECK_EQ(rt, ZERO);
1186 Blezc(rs, imm16_21);
1187 break;
1188 case kCondGTZ:
1189 CHECK_EQ(rt, ZERO);
1190 Bgtzc(rs, imm16_21);
1191 break;
1192 case kCondEQ:
1193 Beqc(rs, rt, imm16_21);
1194 break;
1195 case kCondNE:
1196 Bnec(rs, rt, imm16_21);
1197 break;
1198 case kCondEQZ:
1199 CHECK_EQ(rt, ZERO);
1200 Beqzc(rs, imm16_21);
1201 break;
1202 case kCondNEZ:
1203 CHECK_EQ(rt, ZERO);
1204 Bnezc(rs, imm16_21);
1205 break;
1206 case kCondLTU:
1207 Bltuc(rs, rt, imm16_21);
1208 break;
1209 case kCondGEU:
1210 Bgeuc(rs, rt, imm16_21);
1211 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001212 case kCondF:
1213 CHECK_EQ(rt, ZERO);
1214 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
1215 break;
1216 case kCondT:
1217 CHECK_EQ(rt, ZERO);
1218 Bc1nez(static_cast<FRegister>(rs), imm16_21);
1219 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001220 case kUncond:
1221 LOG(FATAL) << "Unexpected branch condition " << cond;
1222 UNREACHABLE();
1223 }
jeffhao7fbee072012-08-24 17:56:54 -07001224}
1225
1226void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001227 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001228}
1229
1230void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001231 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001232}
1233
1234void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001235 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001236}
1237
1238void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001239 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001240}
1241
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001242void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001243 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001244}
1245
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001246void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001247 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001248}
1249
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001250void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001251 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001252}
1253
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001254void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001255 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft);
jeffhao7fbee072012-08-24 17:56:54 -07001256}
1257
Chris Larsenb74353a2015-11-20 09:07:09 -08001258void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001259 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001260}
1261
1262void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001263 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001264}
1265
1266void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001267 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001268}
1269
1270void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001271 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001272}
1273
jeffhao7fbee072012-08-24 17:56:54 -07001274void MipsAssembler::MovS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001275 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs);
jeffhao7fbee072012-08-24 17:56:54 -07001276}
1277
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001278void MipsAssembler::MovD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001279 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001280}
1281
1282void MipsAssembler::NegS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001283 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001284}
1285
1286void MipsAssembler::NegD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001287 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001288}
1289
Chris Larsenb74353a2015-11-20 09:07:09 -08001290void MipsAssembler::CunS(FRegister fs, FRegister ft) {
1291 CunS(0, fs, ft);
1292}
1293
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001294void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
1295 CHECK(!IsR6());
1296 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001297 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31))
1298 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001299}
1300
Chris Larsenb74353a2015-11-20 09:07:09 -08001301void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
1302 CeqS(0, fs, ft);
1303}
1304
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001305void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
1306 CHECK(!IsR6());
1307 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001308 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32))
1309 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001310}
1311
Chris Larsenb74353a2015-11-20 09:07:09 -08001312void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
1313 CueqS(0, fs, ft);
1314}
1315
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001316void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
1317 CHECK(!IsR6());
1318 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001319 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33))
1320 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001321}
1322
Chris Larsenb74353a2015-11-20 09:07:09 -08001323void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
1324 ColtS(0, fs, ft);
1325}
1326
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001327void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
1328 CHECK(!IsR6());
1329 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001330 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34))
1331 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001332}
1333
Chris Larsenb74353a2015-11-20 09:07:09 -08001334void MipsAssembler::CultS(FRegister fs, FRegister ft) {
1335 CultS(0, fs, ft);
1336}
1337
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001338void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
1339 CHECK(!IsR6());
1340 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001341 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35))
1342 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001343}
1344
Chris Larsenb74353a2015-11-20 09:07:09 -08001345void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
1346 ColeS(0, fs, ft);
1347}
1348
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001349void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
1350 CHECK(!IsR6());
1351 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001352 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36))
1353 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001354}
1355
Chris Larsenb74353a2015-11-20 09:07:09 -08001356void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
1357 CuleS(0, fs, ft);
1358}
1359
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001360void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
1361 CHECK(!IsR6());
1362 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001363 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37))
1364 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001365}
1366
Chris Larsenb74353a2015-11-20 09:07:09 -08001367void MipsAssembler::CunD(FRegister fs, FRegister ft) {
1368 CunD(0, fs, ft);
1369}
1370
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001371void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
1372 CHECK(!IsR6());
1373 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001374 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31))
1375 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001376}
1377
Chris Larsenb74353a2015-11-20 09:07:09 -08001378void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
1379 CeqD(0, fs, ft);
1380}
1381
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001382void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
1383 CHECK(!IsR6());
1384 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001385 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32))
1386 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001387}
1388
Chris Larsenb74353a2015-11-20 09:07:09 -08001389void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
1390 CueqD(0, fs, ft);
1391}
1392
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001393void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1394 CHECK(!IsR6());
1395 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001396 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33))
1397 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001398}
1399
Chris Larsenb74353a2015-11-20 09:07:09 -08001400void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1401 ColtD(0, fs, ft);
1402}
1403
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001404void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1405 CHECK(!IsR6());
1406 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001407 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34))
1408 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001409}
1410
Chris Larsenb74353a2015-11-20 09:07:09 -08001411void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1412 CultD(0, fs, ft);
1413}
1414
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001415void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1416 CHECK(!IsR6());
1417 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001418 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35))
1419 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001420}
1421
Chris Larsenb74353a2015-11-20 09:07:09 -08001422void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1423 ColeD(0, fs, ft);
1424}
1425
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001426void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1427 CHECK(!IsR6());
1428 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001429 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36))
1430 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001431}
1432
Chris Larsenb74353a2015-11-20 09:07:09 -08001433void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1434 CuleD(0, fs, ft);
1435}
1436
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001437void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1438 CHECK(!IsR6());
1439 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001440 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37))
1441 .CcOuts(cc).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001442}
1443
1444void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1445 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001446 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001447}
1448
1449void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1450 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001451 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001452}
1453
1454void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1455 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001456 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001457}
1458
1459void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1460 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001461 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001462}
1463
1464void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1465 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001466 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001467}
1468
1469void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1470 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001471 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001472}
1473
1474void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1475 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001476 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001477}
1478
1479void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1480 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001481 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001482}
1483
1484void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1485 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001486 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001487}
1488
1489void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1490 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001491 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001492}
1493
1494void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1495 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001496 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001497}
1498
1499void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1500 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001501 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001502}
1503
1504void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1505 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001506 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001507}
1508
1509void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1510 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001511 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001512}
1513
1514void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1515 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001516 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001517}
1518
1519void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1520 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001521 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001522}
1523
1524void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1525 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001526 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001527}
1528
1529void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1530 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001531 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001532}
1533
1534void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1535 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001536 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001537}
1538
1539void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1540 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001541 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001542}
1543
1544void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1545 CHECK(!IsR6());
1546 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001547 DsFsmInstr(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01))
1548 .GprInOuts(rd).GprIns(rs).CcIns(cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001549}
1550
1551void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1552 CHECK(!IsR6());
1553 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001554 DsFsmInstr(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01))
1555 .GprInOuts(rd).GprIns(rs).CcIns(cc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08001556}
1557
Chris Larsenb74353a2015-11-20 09:07:09 -08001558void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1559 CHECK(!IsR6());
1560 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001561 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11))
1562 .FprInOuts(fd).FprIns(fs).CcIns(cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001563}
1564
1565void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1566 CHECK(!IsR6());
1567 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001568 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11))
1569 .FprInOuts(fd).FprIns(fs).CcIns(cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001570}
1571
1572void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1573 CHECK(!IsR6());
1574 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001575 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11))
1576 .FprInOuts(fd).FprIns(fs).CcIns(cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001577}
1578
1579void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1580 CHECK(!IsR6());
1581 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunzea247dea2017-11-03 18:43:04 -07001582 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11))
1583 .FprInOuts(fd).FprIns(fs).CcIns(cc);
Chris Larsenb74353a2015-11-20 09:07:09 -08001584}
1585
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001586void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
1587 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001588 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12))
1589 .FprInOuts(fd).FprIns(fs).GprIns(rt);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001590}
1591
1592void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
1593 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001594 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12))
1595 .FprInOuts(fd).FprIns(fs).GprIns(rt);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001596}
1597
1598void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
1599 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001600 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13))
1601 .FprInOuts(fd).FprIns(fs).GprIns(rt);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001602}
1603
1604void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
1605 CHECK(!IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001606 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13))
1607 .FprInOuts(fd).FprIns(fs).GprIns(rt);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001608}
1609
Chris Larsenb74353a2015-11-20 09:07:09 -08001610void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1611 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001612 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001613}
1614
1615void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1616 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001617 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001618}
1619
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001620void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
1621 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001622 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001623}
1624
1625void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
1626 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001627 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001628}
1629
1630void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
1631 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001632 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001633}
1634
1635void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
1636 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001637 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07001638}
1639
Chris Larsenb74353a2015-11-20 09:07:09 -08001640void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1641 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001642 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001643}
1644
1645void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1646 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001647 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001648}
1649
1650void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1651 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001652 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001653}
1654
1655void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1656 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001657 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001658}
1659
1660void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1661 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001662 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001663}
1664
1665void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1666 CHECK(IsR6());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001667 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft);
Chris Larsenb74353a2015-11-20 09:07:09 -08001668}
1669
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001670void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001671 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001672}
1673
1674void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001675 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001676}
1677
1678void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001679 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001680}
1681
1682void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001683 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001684}
1685
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001686void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001687 DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001688}
1689
1690void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001691 DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001692}
1693
1694void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001695 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001696}
1697
1698void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001699 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
jeffhao7fbee072012-08-24 17:56:54 -07001700}
1701
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001702void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001703 DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001704}
1705
1706void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001707 DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08001708}
1709
Chris Larsenb74353a2015-11-20 09:07:09 -08001710void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001711 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs);
Chris Larsenb74353a2015-11-20 09:07:09 -08001712}
1713
1714void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001715 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs);
1716}
1717
1718FRegister MipsAssembler::GetFpuRegLow(FRegister reg) {
1719 // If FPRs are 32-bit (and get paired to hold 64-bit values), accesses to
1720 // odd-numbered FPRs are reattributed to even-numbered FPRs. This lets us
1721 // use only even-numbered FPRs irrespective of whether we're doing single-
1722 // or double-precision arithmetic. (We don't use odd-numbered 32-bit FPRs
1723 // to hold single-precision values).
1724 return Is32BitFPU() ? static_cast<FRegister>(reg & ~1u) : reg;
Chris Larsenb74353a2015-11-20 09:07:09 -08001725}
1726
jeffhao7fbee072012-08-24 17:56:54 -07001727void MipsAssembler::Mfc1(Register rt, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001728 DsFsmInstr(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
1729 .GprOuts(rt).FprIns(GetFpuRegLow(fs));
jeffhao7fbee072012-08-24 17:56:54 -07001730}
1731
Alexey Frunzea247dea2017-11-03 18:43:04 -07001732// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
1733// when loading the value as 32-bit halves.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001734void MipsAssembler::Mtc1(Register rt, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001735 uint32_t encoding =
1736 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
1737 if (Is32BitFPU() && (fs % 2 != 0)) {
1738 // If mtc1 is used to simulate mthc1 by writing to the odd-numbered FPR in
1739 // a pair of 32-bit FPRs, the associated even-numbered FPR is an in/out.
1740 DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(fs)).GprIns(rt);
1741 } else {
1742 // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out.
1743 DsFsmInstr(encoding).FprOuts(fs).GprIns(rt);
1744 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001745}
1746
1747void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001748 DsFsmInstr(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
1749 .GprOuts(rt).FprIns(fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001750}
1751
Alexey Frunzea247dea2017-11-03 18:43:04 -07001752// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
1753// when loading the value as 32-bit halves.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001754void MipsAssembler::Mthc1(Register rt, FRegister fs) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001755 DsFsmInstr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
1756 .FprInOuts(fs).GprIns(rt);
jeffhao7fbee072012-08-24 17:56:54 -07001757}
1758
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001759void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1760 if (Is32BitFPU()) {
1761 CHECK_EQ(fs % 2, 0) << fs;
1762 Mfc1(rt, static_cast<FRegister>(fs + 1));
1763 } else {
1764 Mfhc1(rt, fs);
1765 }
1766}
1767
1768void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1769 if (Is32BitFPU()) {
1770 CHECK_EQ(fs % 2, 0) << fs;
1771 Mtc1(rt, static_cast<FRegister>(fs + 1));
1772 } else {
1773 Mthc1(rt, fs);
1774 }
1775}
1776
Alexey Frunzea247dea2017-11-03 18:43:04 -07001777// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
1778// when loading the value as 32-bit halves.
jeffhao7fbee072012-08-24 17:56:54 -07001779void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001780 uint32_t encoding = EmitI(0x31, rs, static_cast<Register>(ft), imm16);
1781 if (Is32BitFPU() && (ft % 2 != 0)) {
1782 // If lwc1 is used to load the odd-numbered FPR in a pair of 32-bit FPRs,
1783 // the associated even-numbered FPR is an in/out.
1784 DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(ft)).GprIns(rs);
1785 } else {
1786 // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out.
1787 DsFsmInstr(encoding).FprOuts(ft).GprIns(rs);
1788 }
jeffhao7fbee072012-08-24 17:56:54 -07001789}
1790
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001791void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001792 DsFsmInstr(EmitI(0x35, rs, static_cast<Register>(ft), imm16)).FprOuts(ft).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -07001793}
1794
1795void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001796 DsFsmInstr(EmitI(0x39, rs, static_cast<Register>(ft), imm16)).FprIns(GetFpuRegLow(ft)).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -07001797}
1798
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001799void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
Alexey Frunzea247dea2017-11-03 18:43:04 -07001800 DsFsmInstr(EmitI(0x3d, rs, static_cast<Register>(ft), imm16)).FprIns(ft).GprIns(rs);
jeffhao7fbee072012-08-24 17:56:54 -07001801}
1802
1803void MipsAssembler::Break() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001804 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD));
jeffhao7fbee072012-08-24 17:56:54 -07001805}
1806
jeffhao07030602012-09-26 14:33:14 -07001807void MipsAssembler::Nop() {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001808 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0));
1809}
1810
1811void MipsAssembler::NopIfNoReordering() {
1812 if (!reordering_) {
1813 Nop();
1814 }
jeffhao07030602012-09-26 14:33:14 -07001815}
1816
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001817void MipsAssembler::Move(Register rd, Register rs) {
1818 Or(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001819}
1820
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001821void MipsAssembler::Clear(Register rd) {
1822 Move(rd, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001823}
1824
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001825void MipsAssembler::Not(Register rd, Register rs) {
1826 Nor(rd, rs, ZERO);
jeffhao7fbee072012-08-24 17:56:54 -07001827}
1828
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001829void MipsAssembler::Push(Register rs) {
Chris Larsen715f43e2017-10-23 11:00:32 -07001830 IncreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001831 Sw(rs, SP, 0);
jeffhao7fbee072012-08-24 17:56:54 -07001832}
1833
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001834void MipsAssembler::Pop(Register rd) {
1835 Lw(rd, SP, 0);
Chris Larsen715f43e2017-10-23 11:00:32 -07001836 DecreaseFrameSize(kStackAlignment);
jeffhao7fbee072012-08-24 17:56:54 -07001837}
1838
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001839void MipsAssembler::PopAndReturn(Register rd, Register rt) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001840 bool reordering = SetReorder(false);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02001841 Lw(rd, SP, 0);
1842 Jr(rt);
Chris Larsen715f43e2017-10-23 11:00:32 -07001843 DecreaseFrameSize(kStackAlignment); // Single instruction in delay slot.
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001844 SetReorder(reordering);
jeffhao7fbee072012-08-24 17:56:54 -07001845}
1846
Lena Djokic0758ae72017-05-23 11:06:23 +02001847void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1848 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001849 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001850}
1851
1852void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1853 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001854 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001855}
1856
1857void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1858 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001859 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001860}
1861
1862void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1863 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001864 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001865}
1866
1867void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1868 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001869 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001870}
1871
1872void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1873 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001874 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001875}
1876
1877void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1878 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001879 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001880}
1881
1882void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1883 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001884 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001885}
1886
1887void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1888 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001889 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001890}
1891
1892void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1893 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001894 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001895}
1896
1897void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1898 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001899 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001900}
1901
1902void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1903 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001904 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001905}
1906
1907void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1908 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001909 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001910}
1911
1912void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1913 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001914 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001915}
1916
1917void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1918 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001919 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001920}
1921
1922void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1923 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001924 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001925}
1926
1927void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1928 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001929 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001930}
1931
1932void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1933 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001934 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001935}
1936
1937void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1938 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001939 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001940}
1941
1942void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1943 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001944 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001945}
1946
1947void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1948 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001949 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001950}
1951
1952void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1953 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001954 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001955}
1956
1957void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1958 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001959 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001960}
1961
1962void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1963 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001964 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001965}
1966
1967void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1968 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001969 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001970}
1971
1972void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1973 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001974 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001975}
1976
1977void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1978 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001979 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001980}
1981
1982void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1983 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001984 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001985}
1986
1987void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1988 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001989 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001990}
1991
1992void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1993 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001994 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02001995}
1996
1997void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1998 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07001999 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002000}
2001
2002void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2003 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002004 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002005}
2006
2007void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2008 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002009 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002010}
2011
2012void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2013 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002014 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002015}
2016
2017void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2018 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002019 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002020}
2021
2022void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2023 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002024 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002025}
2026
2027void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2028 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002029 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002030}
2031
2032void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2033 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002034 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002035}
2036
2037void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2038 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002039 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002040}
2041
2042void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2043 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002044 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002045}
2046
2047void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2048 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002049 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002050}
2051
2052void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2053 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002054 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002055}
2056
2057void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2058 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002059 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002060}
2061
2062void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2063 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002064 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002065}
2066
2067void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2068 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002069 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002070}
2071
2072void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2073 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002074 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002075}
2076
2077void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2078 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002079 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002080}
2081
2082void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2083 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002084 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002085}
2086
2087void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2088 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002089 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002090}
2091
2092void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2093 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002094 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002095}
2096
2097void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2098 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002099 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002100}
2101
2102void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2103 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002104 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002105}
2106
2107void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2108 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002109 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002110}
2111
2112void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2113 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002114 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002115}
2116
2117void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2118 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002119 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002120}
2121
2122void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2123 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002124 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002125}
2126
2127void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2128 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002129 DsFsmInstr(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002130}
2131
2132void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2133 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002134 DsFsmInstr(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002135}
2136
2137void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2138 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002139 DsFsmInstr(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002140}
2141
2142void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2143 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002144 DsFsmInstr(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002145}
2146
2147void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2148 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002149 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002150}
2151
2152void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2153 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002154 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002155}
2156
2157void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2158 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002159 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002160}
2161
2162void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2163 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002164 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002165}
2166
2167void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2168 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002169 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002170}
2171
2172void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2173 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002174 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002175}
2176
2177void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2178 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002179 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002180}
2181
2182void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2183 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002184 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002185}
2186
2187void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2188 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002189 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002190}
2191
2192void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2193 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002194 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002195}
2196
2197void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2198 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002199 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002200}
2201
2202void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2203 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002204 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002205}
2206
2207void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2208 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002209 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002210}
2211
2212void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2213 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002214 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002215}
2216
2217void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2218 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002219 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002220}
2221
2222void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2223 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002224 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002225}
2226
2227void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2228 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002229 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002230}
2231
2232void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2233 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002234 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002235}
2236
2237void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2238 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002239 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002240}
2241
2242void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2243 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002244 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002245}
2246
2247void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
2248 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002249 DsFsmInstr(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002250}
2251
2252void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
2253 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002254 DsFsmInstr(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002255}
2256
2257void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
2258 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002259 DsFsmInstr(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002260}
2261
2262void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
2263 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002264 DsFsmInstr(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002265}
2266
2267void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2268 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002269 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002270}
2271
2272void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2273 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002274 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002275}
2276
2277void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2278 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002279 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002280}
2281
2282void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2283 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002284 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002285}
2286
2287void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2288 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002289 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002290}
2291
2292void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2293 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002294 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002295}
2296
2297void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2298 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002299 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002300}
2301
2302void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2303 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002304 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002305}
2306
2307void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2308 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002309 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002310}
2311
2312void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2313 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002314 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002315}
2316
2317void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2318 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002319 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002320}
2321
2322void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2323 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002324 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002325}
2326
2327void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2328 CHECK(HasMsa());
2329 CHECK(IsUint<3>(shamt3)) << shamt3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002330 DsFsmInstr(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002331}
2332
2333void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2334 CHECK(HasMsa());
2335 CHECK(IsUint<4>(shamt4)) << shamt4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002336 DsFsmInstr(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002337}
2338
2339void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2340 CHECK(HasMsa());
2341 CHECK(IsUint<5>(shamt5)) << shamt5;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002342 DsFsmInstr(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002343}
2344
2345void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2346 CHECK(HasMsa());
2347 CHECK(IsUint<6>(shamt6)) << shamt6;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002348 DsFsmInstr(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002349}
2350
2351void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
2352 CHECK(HasMsa());
2353 CHECK(IsUint<3>(shamt3)) << shamt3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002354 DsFsmInstr(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002355}
2356
2357void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
2358 CHECK(HasMsa());
2359 CHECK(IsUint<4>(shamt4)) << shamt4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002360 DsFsmInstr(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002361}
2362
2363void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
2364 CHECK(HasMsa());
2365 CHECK(IsUint<5>(shamt5)) << shamt5;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002366 DsFsmInstr(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002367}
2368
2369void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
2370 CHECK(HasMsa());
2371 CHECK(IsUint<6>(shamt6)) << shamt6;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002372 DsFsmInstr(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002373}
2374
2375void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2376 CHECK(HasMsa());
2377 CHECK(IsUint<3>(shamt3)) << shamt3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002378 DsFsmInstr(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002379}
2380
2381void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2382 CHECK(HasMsa());
2383 CHECK(IsUint<4>(shamt4)) << shamt4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002384 DsFsmInstr(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002385}
2386
2387void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2388 CHECK(HasMsa());
2389 CHECK(IsUint<5>(shamt5)) << shamt5;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002390 DsFsmInstr(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002391}
2392
2393void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2394 CHECK(HasMsa());
2395 CHECK(IsUint<6>(shamt6)) << shamt6;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002396 DsFsmInstr(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002397}
2398
2399void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) {
2400 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002401 DsFsmInstr(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002402}
2403
2404void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
2405 CHECK(HasMsa());
2406 CHECK(IsUint<4>(n4)) << n4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002407 DsFsmInstr(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002408}
2409
2410void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
2411 CHECK(HasMsa());
2412 CHECK(IsUint<3>(n3)) << n3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002413 DsFsmInstr(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002414}
2415
2416void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
2417 CHECK(HasMsa());
2418 CHECK(IsUint<2>(n2)) << n2;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002419 DsFsmInstr(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002420}
2421
2422void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
2423 CHECK(HasMsa());
2424 CHECK(IsUint<1>(n1)) << n1;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002425 DsFsmInstr(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
Lena Djokic0758ae72017-05-23 11:06:23 +02002426}
2427
Lena Djokic3309c012017-10-13 14:34:32 +02002428void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) {
2429 CHECK(HasMsa());
2430 CHECK(IsUint<4>(n4)) << n4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002431 DsFsmInstr(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19))
2432 .GprOuts(rd).FprIns(ws);
Lena Djokic3309c012017-10-13 14:34:32 +02002433}
2434
2435void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) {
2436 CHECK(HasMsa());
2437 CHECK(IsUint<3>(n3)) << n3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002438 DsFsmInstr(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19))
2439 .GprOuts(rd).FprIns(ws);
Lena Djokic3309c012017-10-13 14:34:32 +02002440}
2441
2442void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) {
2443 CHECK(HasMsa());
2444 CHECK(IsUint<2>(n2)) << n2;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002445 DsFsmInstr(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19))
2446 .GprOuts(rd).FprIns(ws);
Lena Djokic3309c012017-10-13 14:34:32 +02002447}
2448
2449void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) {
2450 CHECK(HasMsa());
2451 CHECK(IsUint<4>(n4)) << n4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002452 DsFsmInstr(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19))
2453 .GprOuts(rd).FprIns(ws);
Lena Djokic3309c012017-10-13 14:34:32 +02002454}
2455
2456void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) {
2457 CHECK(HasMsa());
2458 CHECK(IsUint<3>(n3)) << n3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002459 DsFsmInstr(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19))
2460 .GprOuts(rd).FprIns(ws);
Lena Djokic3309c012017-10-13 14:34:32 +02002461}
2462
2463void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) {
2464 CHECK(HasMsa());
2465 CHECK(IsUint<4>(n4)) << n4;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002466 DsFsmInstr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19))
2467 .FprInOuts(wd).GprIns(rs);
Lena Djokic3309c012017-10-13 14:34:32 +02002468}
2469
2470void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) {
2471 CHECK(HasMsa());
2472 CHECK(IsUint<3>(n3)) << n3;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002473 DsFsmInstr(EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19))
2474 .FprInOuts(wd).GprIns(rs);
Lena Djokic3309c012017-10-13 14:34:32 +02002475}
2476
2477void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) {
2478 CHECK(HasMsa());
2479 CHECK(IsUint<2>(n2)) << n2;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002480 DsFsmInstr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19))
2481 .FprInOuts(wd).GprIns(rs);
Lena Djokic3309c012017-10-13 14:34:32 +02002482}
2483
Lena Djokic0758ae72017-05-23 11:06:23 +02002484void MipsAssembler::FillB(VectorRegister wd, Register rs) {
2485 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002486 DsFsmInstr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e))
2487 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002488}
2489
2490void MipsAssembler::FillH(VectorRegister wd, Register rs) {
2491 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002492 DsFsmInstr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e))
2493 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002494}
2495
2496void MipsAssembler::FillW(VectorRegister wd, Register rs) {
2497 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002498 DsFsmInstr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e))
2499 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002500}
2501
2502void MipsAssembler::LdiB(VectorRegister wd, int imm8) {
2503 CHECK(HasMsa());
2504 CHECK(IsInt<8>(imm8)) << imm8;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002505 DsFsmInstr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
Lena Djokic0758ae72017-05-23 11:06:23 +02002506}
2507
2508void MipsAssembler::LdiH(VectorRegister wd, int imm10) {
2509 CHECK(HasMsa());
2510 CHECK(IsInt<10>(imm10)) << imm10;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002511 DsFsmInstr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
Lena Djokic0758ae72017-05-23 11:06:23 +02002512}
2513
2514void MipsAssembler::LdiW(VectorRegister wd, int imm10) {
2515 CHECK(HasMsa());
2516 CHECK(IsInt<10>(imm10)) << imm10;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002517 DsFsmInstr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
Lena Djokic0758ae72017-05-23 11:06:23 +02002518}
2519
2520void MipsAssembler::LdiD(VectorRegister wd, int imm10) {
2521 CHECK(HasMsa());
2522 CHECK(IsInt<10>(imm10)) << imm10;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002523 DsFsmInstr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
Lena Djokic0758ae72017-05-23 11:06:23 +02002524}
2525
2526void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) {
2527 CHECK(HasMsa());
2528 CHECK(IsInt<10>(offset)) << offset;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002529 DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0)).FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002530}
2531
2532void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) {
2533 CHECK(HasMsa());
2534 CHECK(IsInt<11>(offset)) << offset;
2535 CHECK_ALIGNED(offset, kMipsHalfwordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002536 DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1))
2537 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002538}
2539
2540void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) {
2541 CHECK(HasMsa());
2542 CHECK(IsInt<12>(offset)) << offset;
2543 CHECK_ALIGNED(offset, kMipsWordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002544 DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2))
2545 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002546}
2547
2548void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) {
2549 CHECK(HasMsa());
2550 CHECK(IsInt<13>(offset)) << offset;
2551 CHECK_ALIGNED(offset, kMipsDoublewordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002552 DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3))
2553 .FprOuts(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002554}
2555
2556void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) {
2557 CHECK(HasMsa());
2558 CHECK(IsInt<10>(offset)) << offset;
Alexey Frunzea247dea2017-11-03 18:43:04 -07002559 DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0)).FprIns(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002560}
2561
2562void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) {
2563 CHECK(HasMsa());
2564 CHECK(IsInt<11>(offset)) << offset;
2565 CHECK_ALIGNED(offset, kMipsHalfwordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002566 DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1))
2567 .FprIns(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002568}
2569
2570void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) {
2571 CHECK(HasMsa());
2572 CHECK(IsInt<12>(offset)) << offset;
2573 CHECK_ALIGNED(offset, kMipsWordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002574 DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2))
2575 .FprIns(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002576}
2577
2578void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
2579 CHECK(HasMsa());
2580 CHECK(IsInt<13>(offset)) << offset;
2581 CHECK_ALIGNED(offset, kMipsDoublewordSize);
Alexey Frunzea247dea2017-11-03 18:43:04 -07002582 DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3))
2583 .FprIns(wd).GprIns(rs);
Lena Djokic0758ae72017-05-23 11:06:23 +02002584}
2585
Lena Djokic3309c012017-10-13 14:34:32 +02002586void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2587 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002588 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002589}
2590
2591void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2592 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002593 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002594}
2595
2596void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2597 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002598 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002599}
2600
2601void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2602 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002603 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002604}
2605
Lena Djokic0758ae72017-05-23 11:06:23 +02002606void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2607 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002608 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002609}
2610
2611void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2612 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002613 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002614}
2615
2616void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2617 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002618 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002619}
2620
2621void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2622 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002623 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic0758ae72017-05-23 11:06:23 +02002624}
2625
Lena Djokic3309c012017-10-13 14:34:32 +02002626void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2627 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002628 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002629}
2630
2631void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2632 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002633 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002634}
2635
2636void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2637 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002638 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002639}
2640
2641void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2642 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002643 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002644}
2645
2646void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2647 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002648 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002649}
2650
2651void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2652 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002653 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002654}
2655
2656void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2657 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002658 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002659}
2660
2661void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2662 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002663 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002664}
2665
Lena Djokicb3d79e42017-07-25 11:20:52 +02002666void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2667 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002668 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002669}
2670
2671void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2672 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002673 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002674}
2675
2676void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2677 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002678 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002679}
2680
2681void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2682 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002683 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002684}
2685
2686void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2687 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002688 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002689}
2690
2691void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2692 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002693 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002694}
2695
2696void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2697 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002698 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002699}
2700
2701void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2702 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002703 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002704}
2705
Lena Djokic72aba712017-10-30 15:47:20 +01002706void MipsAssembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2707 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002708 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002709}
2710
2711void MipsAssembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2712 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002713 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002714}
2715
2716void MipsAssembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2717 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002718 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002719}
2720
2721void MipsAssembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2722 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002723 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002724}
2725
2726void MipsAssembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2727 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002728 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002729}
2730
2731void MipsAssembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2732 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002733 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002734}
2735
2736void MipsAssembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2737 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002738 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002739}
2740
2741void MipsAssembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2742 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002743 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic72aba712017-10-30 15:47:20 +01002744}
2745
Lena Djokicb3d79e42017-07-25 11:20:52 +02002746void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2747 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002748 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002749}
2750
2751void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2752 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002753 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002754}
2755
2756void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2757 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002758 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002759}
2760
2761void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2762 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002763 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
Lena Djokicb3d79e42017-07-25 11:20:52 +02002764}
2765
Lena Djokic3309c012017-10-13 14:34:32 +02002766void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2767 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002768 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002769}
2770
2771void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2772 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002773 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002774}
2775
2776void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2777 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002778 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002779}
2780
2781void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2782 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002783 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002784}
2785
2786void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2787 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002788 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002789}
2790
2791void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2792 CHECK(HasMsa());
Alexey Frunzea247dea2017-11-03 18:43:04 -07002793 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
Lena Djokic3309c012017-10-13 14:34:32 +02002794}
2795
Lena Djokic51765b02017-06-22 13:49:59 +02002796void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
2797 FRegister src,
2798 bool is_double) {
2799 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
2800 if (is_double) {
2801 SplatiD(dst, static_cast<VectorRegister>(src), 0);
2802 } else {
2803 SplatiW(dst, static_cast<VectorRegister>(src), 0);
2804 }
2805}
2806
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002807void MipsAssembler::LoadConst32(Register rd, int32_t value) {
2808 if (IsUint<16>(value)) {
2809 // Use OR with (unsigned) immediate to encode 16b unsigned int.
2810 Ori(rd, ZERO, value);
2811 } else if (IsInt<16>(value)) {
2812 // Use ADD with (signed) immediate to encode 16b signed int.
2813 Addiu(rd, ZERO, value);
jeffhao7fbee072012-08-24 17:56:54 -07002814 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002815 Lui(rd, High16Bits(value));
2816 if (value & 0xFFFF)
2817 Ori(rd, rd, Low16Bits(value));
2818 }
2819}
2820
2821void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002822 uint32_t low = Low32Bits(value);
2823 uint32_t high = High32Bits(value);
2824 LoadConst32(reg_lo, low);
2825 if (high != low) {
2826 LoadConst32(reg_hi, high);
2827 } else {
2828 Move(reg_hi, reg_lo);
2829 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002830}
2831
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002832void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002833 if (value == 0) {
2834 temp = ZERO;
2835 } else {
2836 LoadConst32(temp, value);
2837 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002838 Mtc1(temp, r);
2839}
2840
2841void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002842 uint32_t low = Low32Bits(value);
2843 uint32_t high = High32Bits(value);
2844 if (low == 0) {
2845 Mtc1(ZERO, rd);
2846 } else {
2847 LoadConst32(temp, low);
2848 Mtc1(temp, rd);
2849 }
2850 if (high == 0) {
Alexey Frunzebb9863a2016-01-11 15:51:16 -08002851 MoveToFpuHigh(ZERO, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002852 } else {
2853 LoadConst32(temp, high);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08002854 MoveToFpuHigh(temp, rd);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002855 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002856}
2857
2858void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07002859 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002860 if (IsInt<16>(value)) {
2861 Addiu(rt, rs, value);
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07002862 } else if (IsR6()) {
2863 int16_t high = High16Bits(value);
2864 int16_t low = Low16Bits(value);
2865 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
2866 if (low != 0) {
2867 Aui(temp, rs, high);
2868 Addiu(rt, temp, low);
2869 } else {
2870 Aui(rt, rs, high);
2871 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002872 } else {
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07002873 // Do not load the whole 32-bit `value` if it can be represented as
2874 // a sum of two 16-bit signed values. This can save an instruction.
2875 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
2876 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
2877 if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
2878 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
2879 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
2880 } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
2881 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
2882 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
2883 } else {
2884 // Now that all shorter options have been exhausted, load the full 32-bit value.
2885 LoadConst32(temp, value);
2886 Addu(rt, rs, temp);
2887 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002888 }
2889}
2890
2891void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
2892 MipsAssembler::Branch::Type short_type,
2893 MipsAssembler::Branch::Type long_type) {
2894 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
2895}
2896
Alexey Frunze96b66822016-09-10 02:32:44 -07002897void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07002898 OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002899 if (is_r6) {
2900 // R6
Alexey Frunze96b66822016-09-10 02:32:44 -07002901 switch (initial_type) {
2902 case kLabel:
2903 CHECK(!IsResolved());
2904 type_ = kR6Label;
2905 break;
2906 case kLiteral:
2907 CHECK(!IsResolved());
2908 type_ = kR6Literal;
2909 break;
2910 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002911 InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07002912 break;
2913 case kCondBranch:
2914 switch (condition_) {
2915 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002916 InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07002917 break;
2918 case kCondEQZ:
2919 case kCondNEZ:
2920 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
Alexey Frunze0cab6562017-07-25 15:19:36 -07002921 type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
Alexey Frunze96b66822016-09-10 02:32:44 -07002922 break;
2923 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002924 InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07002925 break;
2926 }
2927 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07002928 case kBareCall:
2929 type_ = kR6BareCall;
2930 CHECK_LE(offset_size_needed, GetOffsetSize());
2931 break;
2932 case kBareCondBranch:
2933 type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch;
2934 CHECK_LE(offset_size_needed, GetOffsetSize());
2935 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07002936 default:
2937 LOG(FATAL) << "Unexpected branch type " << initial_type;
2938 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002939 }
2940 } else {
2941 // R2
Alexey Frunze96b66822016-09-10 02:32:44 -07002942 switch (initial_type) {
2943 case kLabel:
2944 CHECK(!IsResolved());
2945 type_ = kLabel;
2946 break;
2947 case kLiteral:
2948 CHECK(!IsResolved());
2949 type_ = kLiteral;
2950 break;
2951 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002952 InitShortOrLong(offset_size_needed, kCall, kLongCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07002953 break;
2954 case kCondBranch:
2955 switch (condition_) {
2956 case kUncond:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002957 InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07002958 break;
2959 default:
Alexey Frunze0cab6562017-07-25 15:19:36 -07002960 InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
Alexey Frunze96b66822016-09-10 02:32:44 -07002961 break;
2962 }
2963 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07002964 case kBareCall:
2965 type_ = kBareCall;
2966 CHECK_LE(offset_size_needed, GetOffsetSize());
2967 break;
2968 case kBareCondBranch:
2969 type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
2970 CHECK_LE(offset_size_needed, GetOffsetSize());
2971 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07002972 default:
2973 LOG(FATAL) << "Unexpected branch type " << initial_type;
2974 UNREACHABLE();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02002975 }
2976 }
2977 old_type_ = type_;
2978}
2979
2980bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
2981 switch (condition) {
2982 case kCondLT:
2983 case kCondGT:
2984 case kCondNE:
2985 case kCondLTU:
2986 return lhs == rhs;
2987 default:
2988 return false;
2989 }
2990}
2991
2992bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
2993 switch (condition) {
2994 case kUncond:
2995 return true;
2996 case kCondGE:
2997 case kCondLE:
2998 case kCondEQ:
2999 case kCondGEU:
3000 return lhs == rhs;
3001 default:
3002 return false;
3003 }
3004}
3005
Alexey Frunze0cab6562017-07-25 15:19:36 -07003006MipsAssembler::Branch::Branch(bool is_r6,
3007 uint32_t location,
3008 uint32_t target,
3009 bool is_call,
3010 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003011 : old_location_(location),
3012 location_(location),
3013 target_(target),
3014 lhs_reg_(0),
3015 rhs_reg_(0),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003016 condition_(kUncond),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003017 delayed_instruction_(kUnfilledDelaySlot),
3018 patcher_label_(nullptr) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003019 InitializeType(
3020 (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
3021 is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003022}
3023
3024MipsAssembler::Branch::Branch(bool is_r6,
3025 uint32_t location,
3026 uint32_t target,
3027 MipsAssembler::BranchCondition condition,
3028 Register lhs_reg,
Alexey Frunze0cab6562017-07-25 15:19:36 -07003029 Register rhs_reg,
3030 bool is_bare)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003031 : old_location_(location),
3032 location_(location),
3033 target_(target),
3034 lhs_reg_(lhs_reg),
3035 rhs_reg_(rhs_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003036 condition_(condition),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003037 delayed_instruction_(kUnfilledDelaySlot),
3038 patcher_label_(nullptr) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003039 CHECK_NE(condition, kUncond);
3040 switch (condition) {
3041 case kCondLT:
3042 case kCondGE:
3043 case kCondLE:
3044 case kCondGT:
3045 case kCondLTU:
3046 case kCondGEU:
3047 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3048 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3049 // We leave this up to the caller.
3050 CHECK(is_r6);
3051 FALLTHROUGH_INTENDED;
3052 case kCondEQ:
3053 case kCondNE:
3054 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3055 // To compare with 0, use dedicated kCond*Z conditions.
3056 CHECK_NE(lhs_reg, ZERO);
3057 CHECK_NE(rhs_reg, ZERO);
3058 break;
3059 case kCondLTZ:
3060 case kCondGEZ:
3061 case kCondLEZ:
3062 case kCondGTZ:
3063 case kCondEQZ:
3064 case kCondNEZ:
3065 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3066 CHECK_NE(lhs_reg, ZERO);
3067 CHECK_EQ(rhs_reg, ZERO);
3068 break;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003069 case kCondF:
3070 case kCondT:
3071 CHECK_EQ(rhs_reg, ZERO);
3072 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003073 case kUncond:
3074 UNREACHABLE();
3075 }
3076 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
3077 if (IsUncond(condition, lhs_reg, rhs_reg)) {
3078 // Branch condition is always true, make the branch unconditional.
3079 condition_ = kUncond;
3080 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07003081 InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003082}
3083
Alexey Frunze96b66822016-09-10 02:32:44 -07003084MipsAssembler::Branch::Branch(bool is_r6,
3085 uint32_t location,
3086 Register dest_reg,
3087 Register base_reg,
3088 Type label_or_literal_type)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003089 : old_location_(location),
3090 location_(location),
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003091 target_(kUnresolved),
3092 lhs_reg_(dest_reg),
3093 rhs_reg_(base_reg),
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003094 condition_(kUncond),
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003095 delayed_instruction_(kUnfilledDelaySlot),
3096 patcher_label_(nullptr) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003097 CHECK_NE(dest_reg, ZERO);
3098 if (is_r6) {
3099 CHECK_EQ(base_reg, ZERO);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003100 }
Alexey Frunze96b66822016-09-10 02:32:44 -07003101 InitializeType(label_or_literal_type, is_r6);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003102}
3103
3104MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
3105 MipsAssembler::BranchCondition cond) {
3106 switch (cond) {
3107 case kCondLT:
3108 return kCondGE;
3109 case kCondGE:
3110 return kCondLT;
3111 case kCondLE:
3112 return kCondGT;
3113 case kCondGT:
3114 return kCondLE;
3115 case kCondLTZ:
3116 return kCondGEZ;
3117 case kCondGEZ:
3118 return kCondLTZ;
3119 case kCondLEZ:
3120 return kCondGTZ;
3121 case kCondGTZ:
3122 return kCondLEZ;
3123 case kCondEQ:
3124 return kCondNE;
3125 case kCondNE:
3126 return kCondEQ;
3127 case kCondEQZ:
3128 return kCondNEZ;
3129 case kCondNEZ:
3130 return kCondEQZ;
3131 case kCondLTU:
3132 return kCondGEU;
3133 case kCondGEU:
3134 return kCondLTU;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003135 case kCondF:
3136 return kCondT;
3137 case kCondT:
3138 return kCondF;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003139 case kUncond:
3140 LOG(FATAL) << "Unexpected branch condition " << cond;
3141 }
3142 UNREACHABLE();
3143}
3144
3145MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
3146 return type_;
3147}
3148
3149MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
3150 return condition_;
3151}
3152
3153Register MipsAssembler::Branch::GetLeftRegister() const {
3154 return static_cast<Register>(lhs_reg_);
3155}
3156
3157Register MipsAssembler::Branch::GetRightRegister() const {
3158 return static_cast<Register>(rhs_reg_);
3159}
3160
3161uint32_t MipsAssembler::Branch::GetTarget() const {
3162 return target_;
3163}
3164
3165uint32_t MipsAssembler::Branch::GetLocation() const {
3166 return location_;
3167}
3168
3169uint32_t MipsAssembler::Branch::GetOldLocation() const {
3170 return old_location_;
3171}
3172
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003173uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const {
3174 // Short branches with delay slots always consist of two instructions, the branch
3175 // and the delay slot, irrespective of whether the delay slot is filled with a
3176 // useful instruction or not.
3177 // Long composite branches may have a length longer by one instruction than
3178 // specified in branch_info_[].length. This happens when an instruction is taken
3179 // to fill the short branch delay slot, but the branch eventually becomes long
3180 // and formally has no delay slot to fill. This instruction is placed at the
3181 // beginning of the long composite branch and this needs to be accounted for in
3182 // the branch length and the location of the offset encoded in the branch.
3183 switch (type) {
3184 case kLongUncondBranch:
3185 case kLongCondBranch:
3186 case kLongCall:
3187 case kR6LongCondBranch:
3188 return (delayed_instruction_ != kUnfilledDelaySlot &&
3189 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0;
3190 default:
3191 return 0;
3192 }
3193}
3194
3195uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const {
3196 return GetPrecedingInstructionLength(type) * sizeof(uint32_t);
3197}
3198
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003199uint32_t MipsAssembler::Branch::GetLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003200 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003201}
3202
3203uint32_t MipsAssembler::Branch::GetOldLength() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003204 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003205}
3206
3207uint32_t MipsAssembler::Branch::GetSize() const {
3208 return GetLength() * sizeof(uint32_t);
3209}
3210
3211uint32_t MipsAssembler::Branch::GetOldSize() const {
3212 return GetOldLength() * sizeof(uint32_t);
3213}
3214
3215uint32_t MipsAssembler::Branch::GetEndLocation() const {
3216 return GetLocation() + GetSize();
3217}
3218
3219uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
3220 return GetOldLocation() + GetOldSize();
3221}
3222
Alexey Frunze0cab6562017-07-25 15:19:36 -07003223bool MipsAssembler::Branch::IsBare() const {
3224 switch (type_) {
3225 // R2 short branches (can't be promoted to long), delay slots filled manually.
3226 case kBareUncondBranch:
3227 case kBareCondBranch:
3228 case kBareCall:
3229 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3230 case kR6BareUncondBranch:
3231 case kR6BareCondBranch:
3232 case kR6BareCall:
3233 return true;
3234 default:
3235 return false;
3236 }
3237}
3238
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003239bool MipsAssembler::Branch::IsLong() const {
3240 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003241 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003242 case kUncondBranch:
3243 case kCondBranch:
3244 case kCall:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003245 // R2 short branches (can't be promoted to long), delay slots filled manually.
3246 case kBareUncondBranch:
3247 case kBareCondBranch:
3248 case kBareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003249 // R2 near label.
3250 case kLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003251 // R2 near literal.
3252 case kLiteral:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003253 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003254 case kR6UncondBranch:
3255 case kR6CondBranch:
3256 case kR6Call:
Alexey Frunze0cab6562017-07-25 15:19:36 -07003257 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3258 case kR6BareUncondBranch:
3259 case kR6BareCondBranch:
3260 case kR6BareCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003261 // R6 near label.
3262 case kR6Label:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003263 // R6 near literal.
3264 case kR6Literal:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003265 return false;
3266 // R2 long branches.
3267 case kLongUncondBranch:
3268 case kLongCondBranch:
3269 case kLongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003270 // R2 far label.
3271 case kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003272 // R2 far literal.
3273 case kFarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003274 // R6 long branches.
3275 case kR6LongUncondBranch:
3276 case kR6LongCondBranch:
3277 case kR6LongCall:
Alexey Frunze96b66822016-09-10 02:32:44 -07003278 // R6 far label.
3279 case kR6FarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003280 // R6 far literal.
3281 case kR6FarLiteral:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003282 return true;
3283 }
3284 UNREACHABLE();
3285}
3286
3287bool MipsAssembler::Branch::IsResolved() const {
3288 return target_ != kUnresolved;
3289}
3290
3291MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003292 bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003293 OffsetBits offset_size =
Alexey Frunze0cab6562017-07-25 15:19:36 -07003294 (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003295 ? kOffset23
3296 : branch_info_[type_].offset_size;
3297 return offset_size;
3298}
3299
3300MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
3301 uint32_t target) {
3302 // For unresolved targets assume the shortest encoding
3303 // (later it will be made longer if needed).
3304 if (target == kUnresolved)
3305 return kOffset16;
3306 int64_t distance = static_cast<int64_t>(target) - location;
3307 // To simplify calculations in composite branches consisting of multiple instructions
3308 // bump up the distance by a value larger than the max byte size of a composite branch.
3309 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
3310 if (IsInt<kOffset16>(distance))
3311 return kOffset16;
3312 else if (IsInt<kOffset18>(distance))
3313 return kOffset18;
3314 else if (IsInt<kOffset21>(distance))
3315 return kOffset21;
3316 else if (IsInt<kOffset23>(distance))
3317 return kOffset23;
3318 else if (IsInt<kOffset28>(distance))
3319 return kOffset28;
3320 return kOffset32;
3321}
3322
3323void MipsAssembler::Branch::Resolve(uint32_t target) {
3324 target_ = target;
3325}
3326
3327void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
3328 if (location_ > expand_location) {
3329 location_ += delta;
3330 }
3331 if (!IsResolved()) {
3332 return; // Don't know the target yet.
3333 }
3334 if (target_ > expand_location) {
3335 target_ += delta;
3336 }
3337}
3338
3339void MipsAssembler::Branch::PromoteToLong() {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003340 CHECK(!IsBare()); // Bare branches do not promote.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003341 switch (type_) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003342 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003343 case kUncondBranch:
3344 type_ = kLongUncondBranch;
3345 break;
3346 case kCondBranch:
3347 type_ = kLongCondBranch;
3348 break;
3349 case kCall:
3350 type_ = kLongCall;
3351 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003352 // R2 near label.
3353 case kLabel:
3354 type_ = kFarLabel;
3355 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003356 // R2 near literal.
3357 case kLiteral:
3358 type_ = kFarLiteral;
3359 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003360 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003361 case kR6UncondBranch:
3362 type_ = kR6LongUncondBranch;
3363 break;
3364 case kR6CondBranch:
3365 type_ = kR6LongCondBranch;
3366 break;
3367 case kR6Call:
3368 type_ = kR6LongCall;
3369 break;
Alexey Frunze96b66822016-09-10 02:32:44 -07003370 // R6 near label.
3371 case kR6Label:
3372 type_ = kR6FarLabel;
3373 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003374 // R6 near literal.
3375 case kR6Literal:
3376 type_ = kR6FarLiteral;
3377 break;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003378 default:
3379 // Note: 'type_' is already long.
3380 break;
3381 }
3382 CHECK(IsLong());
3383}
3384
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003385uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
3386 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003387 case Branch::kLabel:
3388 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003389 case Branch::kLiteral:
3390 case Branch::kFarLiteral:
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003391 if (branch->GetRightRegister() != ZERO) {
3392 return GetLabelLocation(&pc_rel_base_label_);
3393 }
3394 // For those label/literal loads which come with their own NAL instruction
3395 // and don't depend on `pc_rel_base_label_` we can simply use the location
3396 // of the "branch" (the NAL precedes the "branch" immediately). The location
3397 // is close enough for the user of the returned location, PromoteIfNeeded(),
3398 // to not miss needed promotion to a far load.
3399 // (GetOffsetSizeNeeded() provides a little leeway by means of kMaxBranchSize,
3400 // which is larger than all composite branches and label/literal loads: it's
3401 // OK to promote a bit earlier than strictly necessary, it makes things
3402 // simpler.)
3403 FALLTHROUGH_INTENDED;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003404 default:
3405 return branch->GetLocation();
3406 }
3407}
3408
3409uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003410 // `location` comes from GetBranchLocationOrPcRelBase() and is either the location
3411 // of the PC-relative branch or (for some R2 label and literal loads) the location
3412 // of `pc_rel_base_label_`. The PC-relative offset of the branch/load is relative
3413 // to this location.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003414 // If the branch is still unresolved or already long, nothing to do.
3415 if (IsLong() || !IsResolved()) {
3416 return 0;
3417 }
3418 // Promote the short branch to long if the offset size is too small
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003419 // to hold the distance between location and target_.
3420 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003421 PromoteToLong();
3422 uint32_t old_size = GetOldSize();
3423 uint32_t new_size = GetSize();
3424 CHECK_GT(new_size, old_size);
3425 return new_size - old_size;
3426 }
3427 // The following logic is for debugging/testing purposes.
3428 // Promote some short branches to long when it's not really required.
Alexey Frunze0cab6562017-07-25 15:19:36 -07003429 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003430 int64_t distance = static_cast<int64_t>(target_) - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003431 distance = (distance >= 0) ? distance : -distance;
3432 if (distance >= max_short_distance) {
3433 PromoteToLong();
3434 uint32_t old_size = GetOldSize();
3435 uint32_t new_size = GetSize();
3436 CHECK_GT(new_size, old_size);
3437 return new_size - old_size;
3438 }
3439 }
3440 return 0;
3441}
3442
3443uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003444 return location_ + GetPrecedingInstructionSize(type_) +
3445 branch_info_[type_].instr_offset * sizeof(uint32_t);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003446}
3447
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003448uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
3449 switch (branch->GetType()) {
Alexey Frunze96b66822016-09-10 02:32:44 -07003450 case Branch::kLabel:
3451 case Branch::kFarLabel:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003452 case Branch::kLiteral:
3453 case Branch::kFarLiteral:
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003454 if (branch->GetRightRegister() == ZERO) {
3455 // These loads don't use `pc_rel_base_label_` and instead rely on their own
3456 // NAL instruction (it immediately precedes the "branch"). Therefore the
3457 // effective PC-relative base register is RA and it corresponds to the 2nd
3458 // instruction after the NAL.
3459 return branch->GetLocation() + sizeof(uint32_t);
3460 } else {
3461 return GetLabelLocation(&pc_rel_base_label_);
3462 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003463 default:
3464 return branch->GetOffsetLocation() +
3465 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
3466 }
3467}
3468
3469uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003470 // `location` comes from GetBranchOrPcRelBaseForEncoding() and is either a location
3471 // within/near the PC-relative branch or (for some R2 label and literal loads) the
3472 // location of `pc_rel_base_label_`. The PC-relative offset of the branch/load is
3473 // relative to this location.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003474 CHECK(IsResolved());
3475 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
3476 // Calculate the byte distance between instructions and also account for
3477 // different PC-relative origins.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003478 uint32_t offset = target_ - location;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003479 // Prepare the offset for encoding into the instruction(s).
3480 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
3481 return offset;
3482}
3483
3484MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
3485 CHECK_LT(branch_id, branches_.size());
3486 return &branches_[branch_id];
3487}
3488
3489const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
3490 CHECK_LT(branch_id, branches_.size());
3491 return &branches_[branch_id];
3492}
3493
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003494void MipsAssembler::BindRelativeToPrecedingBranch(MipsLabel* label,
3495 uint32_t prev_branch_id_plus_one,
3496 uint32_t position) {
3497 if (prev_branch_id_plus_one != 0) {
3498 const Branch* branch = GetBranch(prev_branch_id_plus_one - 1);
3499 position -= branch->GetEndLocation();
3500 }
3501 label->prev_branch_id_plus_one_ = prev_branch_id_plus_one;
3502 label->BindTo(position);
3503}
3504
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003505void MipsAssembler::Bind(MipsLabel* label) {
3506 CHECK(!label->IsBound());
3507 uint32_t bound_pc = buffer_.Size();
3508
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003509 // Make the delay slot FSM aware of the new label.
3510 DsFsmLabel();
3511
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003512 // Walk the list of branches referring to and preceding this label.
3513 // Store the previously unknown target addresses in them.
3514 while (label->IsLinked()) {
3515 uint32_t branch_id = label->Position();
3516 Branch* branch = GetBranch(branch_id);
3517 branch->Resolve(bound_pc);
3518
3519 uint32_t branch_location = branch->GetLocation();
3520 // Extract the location of the previous branch in the list (walking the list backwards;
3521 // the previous branch ID was stored in the space reserved for this branch).
3522 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
3523
3524 // On to the previous branch in the list...
3525 label->position_ = prev;
3526 }
3527
3528 // Now make the label object contain its own location (relative to the end of the preceding
3529 // branch, if any; it will be used by the branches referring to and following this label).
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003530 BindRelativeToPrecedingBranch(label, branches_.size(), bound_pc);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003531}
3532
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003533uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003534 CHECK(label->IsBound());
3535 uint32_t target = label->Position();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003536 if (label->prev_branch_id_plus_one_ != 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003537 // Get label location based on the branch preceding it.
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003538 const Branch* branch = GetBranch(label->prev_branch_id_plus_one_ - 1);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003539 target += branch->GetEndLocation();
3540 }
3541 return target;
3542}
3543
3544uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
3545 // We can reconstruct the adjustment by going through all the branches from the beginning
3546 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
3547 // with increasing old_position, we can use the data from last AdjustedPosition() to
3548 // continue where we left off and the whole loop should be O(m+n) where m is the number
3549 // of positions to adjust and n is the number of branches.
3550 if (old_position < last_old_position_) {
3551 last_position_adjustment_ = 0;
3552 last_old_position_ = 0;
3553 last_branch_id_ = 0;
3554 }
3555 while (last_branch_id_ != branches_.size()) {
3556 const Branch* branch = GetBranch(last_branch_id_);
3557 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
3558 break;
3559 }
3560 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
3561 ++last_branch_id_;
3562 }
3563 last_old_position_ = old_position;
3564 return old_position + last_position_adjustment_;
3565}
3566
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003567void MipsAssembler::BindPcRelBaseLabel() {
3568 Bind(&pc_rel_base_label_);
3569}
3570
Alexey Frunze06a46c42016-07-19 15:00:40 -07003571uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const {
3572 return GetLabelLocation(&pc_rel_base_label_);
3573}
3574
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003575void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
3576 uint32_t length = branches_.back().GetLength();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003577 // Commit the last branch target label (if any).
3578 DsFsmCommitLabel();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003579 if (!label->IsBound()) {
3580 // Branch forward (to a following label), distance is unknown.
3581 // The first branch forward will contain 0, serving as the terminator of
3582 // the list of forward-reaching branches.
3583 Emit(label->position_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003584 // Nothing for the delay slot (yet).
3585 DsFsmInstrNop(0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003586 length--;
3587 // Now make the label object point to this branch
3588 // (this forms a linked list of branches preceding this label).
3589 uint32_t branch_id = branches_.size() - 1;
3590 label->LinkTo(branch_id);
3591 }
3592 // Reserve space for the branch.
3593 while (length--) {
3594 Nop();
3595 }
3596}
3597
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003598bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const {
3599 if (delay_slot.instruction_ == 0) {
3600 // NOP or no instruction for the delay slot.
3601 return false;
3602 }
3603 switch (type_) {
3604 // R2 unconditional branches.
3605 case kUncondBranch:
3606 case kLongUncondBranch:
3607 // There are no register interdependencies.
3608 return true;
3609
3610 // R2 calls.
3611 case kCall:
3612 case kLongCall:
3613 // Instructions depending on or modifying RA should not be moved into delay slots
3614 // of branches modifying RA.
Alexey Frunzea247dea2017-11-03 18:43:04 -07003615 return ((delay_slot.masks_.gpr_ins_ | delay_slot.masks_.gpr_outs_) & (1u << RA)) == 0;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003616
3617 // R2 conditional branches.
3618 case kCondBranch:
3619 case kLongCondBranch:
3620 switch (condition_) {
3621 // Branches with one GPR source.
3622 case kCondLTZ:
3623 case kCondGEZ:
3624 case kCondLEZ:
3625 case kCondGTZ:
3626 case kCondEQZ:
3627 case kCondNEZ:
Alexey Frunzea247dea2017-11-03 18:43:04 -07003628 return (delay_slot.masks_.gpr_outs_ & (1u << lhs_reg_)) == 0;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003629
3630 // Branches with two GPR sources.
3631 case kCondEQ:
3632 case kCondNE:
Alexey Frunzea247dea2017-11-03 18:43:04 -07003633 return (delay_slot.masks_.gpr_outs_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003634
3635 // Branches with one FPU condition code source.
3636 case kCondF:
3637 case kCondT:
Alexey Frunzea247dea2017-11-03 18:43:04 -07003638 return (delay_slot.masks_.cc_outs_ & (1u << lhs_reg_)) == 0;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003639
3640 default:
3641 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3642 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3643 LOG(FATAL) << "Unexpected branch condition " << condition_;
3644 UNREACHABLE();
3645 }
3646
3647 // R6 unconditional branches.
3648 case kR6UncondBranch:
3649 case kR6LongUncondBranch:
3650 // R6 calls.
3651 case kR6Call:
3652 case kR6LongCall:
3653 // There are no delay slots.
3654 return false;
3655
3656 // R6 conditional branches.
3657 case kR6CondBranch:
3658 case kR6LongCondBranch:
3659 switch (condition_) {
3660 // Branches with one FPU register source.
3661 case kCondF:
3662 case kCondT:
Alexey Frunzea247dea2017-11-03 18:43:04 -07003663 return (delay_slot.masks_.fpr_outs_ & (1u << lhs_reg_)) == 0;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003664 // Others have a forbidden slot instead of a delay slot.
3665 default:
3666 return false;
3667 }
3668
3669 // Literals.
3670 default:
3671 LOG(FATAL) << "Unexpected branch type " << type_;
3672 UNREACHABLE();
3673 }
3674}
3675
3676uint32_t MipsAssembler::Branch::GetDelayedInstruction() const {
3677 return delayed_instruction_;
3678}
3679
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003680MipsLabel* MipsAssembler::Branch::GetPatcherLabel() const {
3681 return patcher_label_;
3682}
3683
3684void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction, MipsLabel* patcher_label) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003685 CHECK_NE(instruction, kUnfilledDelaySlot);
3686 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot);
3687 delayed_instruction_ = instruction;
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003688 patcher_label_ = patcher_label;
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003689}
3690
3691void MipsAssembler::Branch::DecrementLocations() {
3692 // We first create a branch object, which gets its type and locations initialized,
3693 // and then we check if the branch can actually have the preceding instruction moved
3694 // into its delay slot. If it can, the branch locations need to be decremented.
3695 //
3696 // We could make the check before creating the branch object and avoid the location
3697 // adjustment, but the check is cleaner when performed on an initialized branch
3698 // object.
3699 //
3700 // If the branch is backwards (to a previously bound label), reducing the locations
3701 // cannot cause a short branch to exceed its offset range because the offset reduces.
3702 // And this is not at all a problem for a long branch backwards.
3703 //
3704 // If the branch is forward (not linked to any label yet), reducing the locations
3705 // is harmless. The branch will be promoted to long if needed when the target is known.
3706 CHECK_EQ(location_, old_location_);
3707 CHECK_GE(old_location_, sizeof(uint32_t));
3708 old_location_ -= sizeof(uint32_t);
3709 location_ = old_location_;
3710}
3711
3712void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003713 if (branch.IsBare()) {
3714 // Delay slots are filled manually in bare branches.
3715 return;
3716 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003717 if (branch.CanHaveDelayedInstruction(delay_slot_)) {
3718 // The last instruction cannot be used in a different delay slot,
3719 // do not commit the label before it (if any).
3720 DsFsmDropLabel();
3721 // Remove the last emitted instruction.
3722 size_t size = buffer_.Size();
3723 CHECK_GE(size, sizeof(uint32_t));
3724 size -= sizeof(uint32_t);
3725 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_);
3726 buffer_.Resize(size);
3727 // Attach it to the branch and adjust the branch locations.
3728 branch.DecrementLocations();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003729 branch.SetDelayedInstruction(delay_slot_.instruction_, delay_slot_.patcher_label_);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003730 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) {
3731 // If reordefing is disabled, prevent absorption of the target instruction.
3732 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot);
3733 }
3734}
3735
Alexey Frunze0cab6562017-07-25 15:19:36 -07003736void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003737 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003738 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ false, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003739 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003740 FinalizeLabeledBranch(label);
3741}
3742
Alexey Frunze0cab6562017-07-25 15:19:36 -07003743void MipsAssembler::Bcond(MipsLabel* label,
3744 bool is_r6,
3745 bool is_bare,
3746 BranchCondition condition,
3747 Register lhs,
3748 Register rhs) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003749 // If lhs = rhs, this can be a NOP.
3750 if (Branch::IsNop(condition, lhs, rhs)) {
3751 return;
3752 }
3753 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003754 branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003755 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003756 FinalizeLabeledBranch(label);
3757}
3758
Alexey Frunze0cab6562017-07-25 15:19:36 -07003759void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003760 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
Alexey Frunze0cab6562017-07-25 15:19:36 -07003761 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ true, is_bare);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003762 MoveInstructionToDelaySlot(branches_.back());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003763 FinalizeLabeledBranch(label);
3764}
3765
Alexey Frunze96b66822016-09-10 02:32:44 -07003766void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
3767 // Label address loads are treated as pseudo branches since they require very similar handling.
3768 DCHECK(!label->IsBound());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003769 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
3770 // may generate an individual NAL instruction to simulate PC-relative addressing on R2
3771 // by specifying `base_reg` of `ZERO`. Check for it.
3772 if (base_reg == ZERO && !IsR6()) {
3773 Nal();
3774 }
Alexey Frunze96b66822016-09-10 02:32:44 -07003775 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
3776 FinalizeLabeledBranch(label);
3777}
3778
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003779Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
3780 DCHECK(size == 4u || size == 8u) << size;
3781 literals_.emplace_back(size, data);
3782 return &literals_.back();
3783}
3784
3785void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) {
3786 // Literal loads are treated as pseudo branches since they require very similar handling.
3787 DCHECK_EQ(literal->GetSize(), 4u);
3788 MipsLabel* label = literal->GetLabel();
3789 DCHECK(!label->IsBound());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003790 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
3791 // may generate an individual NAL instruction to simulate PC-relative addressing on R2
3792 // by specifying `base_reg` of `ZERO`. Check for it.
3793 if (base_reg == ZERO && !IsR6()) {
3794 Nal();
3795 }
Alexey Frunze96b66822016-09-10 02:32:44 -07003796 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003797 FinalizeLabeledBranch(label);
3798}
3799
Alexey Frunze96b66822016-09-10 02:32:44 -07003800JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
3801 jump_tables_.emplace_back(std::move(labels));
3802 JumpTable* table = &jump_tables_.back();
3803 DCHECK(!table->GetLabel()->IsBound());
3804 return table;
3805}
3806
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003807void MipsAssembler::EmitLiterals() {
3808 if (!literals_.empty()) {
3809 // We don't support byte and half-word literals.
3810 // TODO: proper alignment for 64-bit literals when they're implemented.
3811 for (Literal& literal : literals_) {
3812 MipsLabel* label = literal.GetLabel();
3813 Bind(label);
3814 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
3815 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
3816 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
3817 buffer_.Emit<uint8_t>(literal.GetData()[i]);
3818 }
3819 }
3820 }
3821}
3822
Alexey Frunze96b66822016-09-10 02:32:44 -07003823void MipsAssembler::ReserveJumpTableSpace() {
3824 if (!jump_tables_.empty()) {
3825 for (JumpTable& table : jump_tables_) {
3826 MipsLabel* label = table.GetLabel();
3827 Bind(label);
3828
3829 // Bulk ensure capacity, as this may be large.
3830 size_t orig_size = buffer_.Size();
3831 size_t required_capacity = orig_size + table.GetSize();
3832 if (required_capacity > buffer_.Capacity()) {
3833 buffer_.ExtendCapacity(required_capacity);
3834 }
3835#ifndef NDEBUG
3836 buffer_.has_ensured_capacity_ = true;
3837#endif
3838
3839 // Fill the space with dummy data as the data is not final
3840 // until the branches have been promoted. And we shouldn't
3841 // be moving uninitialized data during branch promotion.
3842 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
3843 buffer_.Emit<uint32_t>(0x1abe1234u);
3844 }
3845
3846#ifndef NDEBUG
3847 buffer_.has_ensured_capacity_ = false;
3848#endif
3849 }
3850 }
3851}
3852
3853void MipsAssembler::EmitJumpTables() {
3854 if (!jump_tables_.empty()) {
3855 CHECK(!overwriting_);
3856 // Switch from appending instructions at the end of the buffer to overwriting
3857 // existing instructions (here, jump tables) in the buffer.
3858 overwriting_ = true;
3859
3860 for (JumpTable& table : jump_tables_) {
3861 MipsLabel* table_label = table.GetLabel();
3862 uint32_t start = GetLabelLocation(table_label);
3863 overwrite_location_ = start;
3864
3865 for (MipsLabel* target : table.GetData()) {
3866 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
3867 // The table will contain target addresses relative to the table start.
3868 uint32_t offset = GetLabelLocation(target) - start;
3869 Emit(offset);
3870 }
3871 }
3872
3873 overwriting_ = false;
3874 }
3875}
3876
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003877void MipsAssembler::PromoteBranches() {
3878 // Promote short branches to long as necessary.
3879 bool changed;
3880 do {
3881 changed = false;
3882 for (auto& branch : branches_) {
3883 CHECK(branch.IsResolved());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003884 uint32_t base = GetBranchLocationOrPcRelBase(&branch);
3885 uint32_t delta = branch.PromoteIfNeeded(base);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003886 // If this branch has been promoted and needs to expand in size,
3887 // relocate all branches by the expansion size.
3888 if (delta) {
3889 changed = true;
3890 uint32_t expand_location = branch.GetLocation();
3891 for (auto& branch2 : branches_) {
3892 branch2.Relocate(expand_location, delta);
3893 }
3894 }
3895 }
3896 } while (changed);
3897
3898 // Account for branch expansion by resizing the code buffer
3899 // and moving the code in it to its final location.
3900 size_t branch_count = branches_.size();
3901 if (branch_count > 0) {
3902 // Resize.
3903 Branch& last_branch = branches_[branch_count - 1];
3904 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
3905 uint32_t old_size = buffer_.Size();
3906 buffer_.Resize(old_size + size_delta);
3907 // Move the code residing between branch placeholders.
3908 uint32_t end = old_size;
3909 for (size_t i = branch_count; i > 0; ) {
3910 Branch& branch = branches_[--i];
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003911 CHECK_GE(end, branch.GetOldEndLocation());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003912 uint32_t size = end - branch.GetOldEndLocation();
3913 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
3914 end = branch.GetOldLocation();
3915 }
3916 }
3917}
3918
3919// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
3920const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
Alexey Frunze0cab6562017-07-25 15:19:36 -07003921 // R2 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003922 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
3923 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003924 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall
Alexey Frunze0cab6562017-07-25 15:19:36 -07003925 // R2 short branches (can't be promoted to long), delay slots filled manually.
3926 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch
3927 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch
3928 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07003929 // R2 near label.
3930 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003931 // R2 near literal.
3932 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003933 // R2 long branches.
3934 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
3935 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
3936 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07003937 // R2 far label.
3938 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003939 // R2 far literal.
3940 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral
Alexey Frunze0cab6562017-07-25 15:19:36 -07003941 // R6 short branches (can be promoted to long).
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003942 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
3943 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
3944 // Exception: kOffset23 for beqzc/bnezc.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003945 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call
Alexey Frunze0cab6562017-07-25 15:19:36 -07003946 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
3947 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch
3948 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch
3949 // Exception: kOffset23 for beqzc/bnezc.
3950 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall
Alexey Frunze96b66822016-09-10 02:32:44 -07003951 // R6 near label.
3952 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003953 // R6 near literal.
3954 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003955 // R6 long branches.
3956 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
3957 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003958 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
Alexey Frunze96b66822016-09-10 02:32:44 -07003959 // R6 far label.
3960 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003961 // R6 far literal.
3962 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003963};
3964
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003965static inline bool IsAbsorbableInstruction(uint32_t instruction) {
3966 // The relative patcher patches addiu, lw and sw with an immediate operand of 0x5678.
3967 // We want to make sure that these instructions do not get absorbed into delay slots
3968 // of unconditional branches on R2. Absorption would otherwise make copies of
3969 // unpatched instructions.
3970 if ((instruction & 0xFFFF) != 0x5678) {
3971 return true;
3972 }
3973 switch (instruction >> kOpcodeShift) {
3974 case 0x09: // Addiu.
3975 case 0x23: // Lw.
3976 case 0x2B: // Sw.
3977 return false;
3978 default:
3979 return true;
3980 }
3981}
3982
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07003983static inline Register GetR2PcRelBaseRegister(Register reg) {
3984 // LoadLabelAddress() and LoadLiteral() generate individual NAL
3985 // instructions on R2 when the specified base register is ZERO
3986 // and so the effective PC-relative base register is RA, not ZERO.
3987 return (reg == ZERO) ? RA : reg;
3988}
3989
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003990// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003991void MipsAssembler::EmitBranch(uint32_t branch_id) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003992 CHECK_EQ(overwriting_, true);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07003993 Branch* branch = GetBranch(branch_id);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003994 overwrite_location_ = branch->GetLocation();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07003995 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02003996 BranchCondition condition = branch->GetCondition();
3997 Register lhs = branch->GetLeftRegister();
3998 Register rhs = branch->GetRightRegister();
Alexey Frunze57eb0f52016-07-29 22:04:46 -07003999 uint32_t delayed_instruction = branch->GetDelayedInstruction();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004000 MipsLabel* patcher_label = branch->GetPatcherLabel();
4001 if (patcher_label != nullptr) {
4002 // Update the patcher label location to account for branch promotion and
4003 // delay slot filling.
4004 CHECK(patcher_label->IsBound());
4005 uint32_t bound_pc = branch->GetLocation();
4006 if (!branch->IsLong()) {
4007 // Short branches precede delay slots.
4008 // Long branches follow "delay slots".
4009 bound_pc += sizeof(uint32_t);
4010 }
4011 // Rebind the label.
4012 patcher_label->Reinitialize();
4013 BindRelativeToPrecedingBranch(patcher_label, branch_id, bound_pc);
4014 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004015 switch (branch->GetType()) {
4016 // R2 short branches.
4017 case Branch::kUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004018 if (delayed_instruction == Branch::kUnfillableDelaySlot) {
4019 // The branch was created when reordering was disabled, do not absorb the target
4020 // instruction.
4021 delayed_instruction = 0; // NOP.
4022 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4023 // Try to absorb the target instruction into the delay slot.
4024 delayed_instruction = 0; // NOP.
4025 // Incrementing the signed 16-bit offset past the target instruction must not
4026 // cause overflow into the negative subrange, check for the max offset.
4027 if (offset != 0x7FFF) {
4028 uint32_t target = branch->GetTarget();
4029 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) {
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004030 uint32_t target_instruction = buffer_.Load<uint32_t>(target);
4031 if (IsAbsorbableInstruction(target_instruction)) {
4032 delayed_instruction = target_instruction;
4033 offset++;
4034 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004035 }
4036 }
4037 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004038 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4039 B(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004040 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004041 break;
4042 case Branch::kCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004043 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4044 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4045 delayed_instruction = 0; // NOP.
4046 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004047 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004048 EmitBcondR2(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004049 Emit(delayed_instruction);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004050 break;
4051 case Branch::kCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004052 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4053 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4054 delayed_instruction = 0; // NOP.
4055 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004056 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004057 Bal(offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004058 Emit(delayed_instruction);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004059 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004060 case Branch::kBareUncondBranch:
4061 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4062 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4063 B(offset);
4064 break;
4065 case Branch::kBareCondBranch:
4066 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4067 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4068 EmitBcondR2(condition, lhs, rhs, offset);
4069 break;
4070 case Branch::kBareCall:
4071 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4072 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4073 Bal(offset);
4074 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004075
Alexey Frunze96b66822016-09-10 02:32:44 -07004076 // R2 near label.
4077 case Branch::kLabel:
4078 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4079 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004080 Addiu(lhs, GetR2PcRelBaseRegister(rhs), offset);
Alexey Frunze96b66822016-09-10 02:32:44 -07004081 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004082 // R2 near literal.
4083 case Branch::kLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004084 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004085 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004086 Lw(lhs, GetR2PcRelBaseRegister(rhs), offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004087 break;
4088
4089 // R2 long branches.
4090 case Branch::kLongUncondBranch:
4091 // To get the value of the PC register we need to use the NAL instruction.
4092 // NAL clobbers the RA register. However, RA must be preserved if the
4093 // method is compiled without the entry/exit sequences that would take care
4094 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
4095 // So, we need to preserve RA in some temporary storage ourselves. The AT
4096 // register can't be used for this because we need it to load a constant
4097 // which will be added to the value that NAL stores in RA. And we can't
4098 // use T9 for this in the context of the JNI compiler, which uses it
4099 // as a scratch register (see InterproceduralScratchRegister()).
4100 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
4101 // we'd also need to use the ROTR instruction, which requires no less than
4102 // MIPSR2.
4103 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
4104 // (LO or HI) or even a floating-point register, but that doesn't seem
4105 // like a nice solution. We may want this to work on both R6 and pre-R6.
4106 // For now simply use the stack for RA. This should be OK since for the
4107 // vast majority of code a short PC-relative branch is sufficient.
4108 // TODO: can this be improved?
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004109 // TODO: consider generation of a shorter sequence when we know that RA
4110 // is explicitly preserved by the method entry/exit code.
4111 if (delayed_instruction != Branch::kUnfilledDelaySlot &&
4112 delayed_instruction != Branch::kUnfillableDelaySlot) {
4113 Emit(delayed_instruction);
4114 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004115 Push(RA);
4116 Nal();
4117 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4118 Lui(AT, High16Bits(offset));
4119 Ori(AT, AT, Low16Bits(offset));
4120 Addu(AT, AT, RA);
4121 Lw(RA, SP, 0);
4122 Jr(AT);
Chris Larsen715f43e2017-10-23 11:00:32 -07004123 DecreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004124 break;
4125 case Branch::kLongCondBranch:
4126 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004127 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4128 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4129 Emit(delayed_instruction);
4130 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004131 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
4132 // number of instructions skipped:
4133 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004134 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004135 Push(RA);
4136 Nal();
4137 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4138 Lui(AT, High16Bits(offset));
4139 Ori(AT, AT, Low16Bits(offset));
4140 Addu(AT, AT, RA);
4141 Lw(RA, SP, 0);
4142 Jr(AT);
Chris Larsen715f43e2017-10-23 11:00:32 -07004143 DecreaseFrameSize(kStackAlignment);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004144 break;
4145 case Branch::kLongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004146 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4147 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4148 Emit(delayed_instruction);
4149 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004150 Nal();
4151 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4152 Lui(AT, High16Bits(offset));
4153 Ori(AT, AT, Low16Bits(offset));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004154 Addu(AT, AT, RA);
4155 Jalr(AT);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004156 Nop();
4157 break;
4158
Alexey Frunze96b66822016-09-10 02:32:44 -07004159 // R2 far label.
4160 case Branch::kFarLabel:
4161 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4162 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4163 Lui(AT, High16Bits(offset));
4164 Ori(AT, AT, Low16Bits(offset));
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004165 Addu(lhs, AT, GetR2PcRelBaseRegister(rhs));
Alexey Frunze96b66822016-09-10 02:32:44 -07004166 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004167 // R2 far literal.
4168 case Branch::kFarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004169 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004170 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4171 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4172 Lui(AT, High16Bits(offset));
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07004173 Addu(AT, AT, GetR2PcRelBaseRegister(rhs));
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004174 Lw(lhs, AT, Low16Bits(offset));
4175 break;
4176
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004177 // R6 short branches.
4178 case Branch::kR6UncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004179 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004180 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4181 Bc(offset);
4182 break;
4183 case Branch::kR6CondBranch:
4184 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004185 EmitBcondR6(condition, lhs, rhs, offset);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004186 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4187 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4188 Emit(delayed_instruction);
4189 } else {
4190 // TODO: improve by filling the forbidden slot (IFF this is
4191 // a forbidden and not a delay slot).
4192 Nop();
4193 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004194 break;
4195 case Branch::kR6Call:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004196 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004197 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004198 Balc(offset);
4199 break;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004200 case Branch::kR6BareUncondBranch:
4201 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4202 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4203 Bc(offset);
4204 break;
4205 case Branch::kR6BareCondBranch:
4206 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4207 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4208 EmitBcondR6(condition, lhs, rhs, offset);
4209 break;
4210 case Branch::kR6BareCall:
4211 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4212 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4213 Balc(offset);
4214 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004215
Alexey Frunze96b66822016-09-10 02:32:44 -07004216 // R6 near label.
4217 case Branch::kR6Label:
4218 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4219 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4220 Addiupc(lhs, offset);
4221 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004222 // R6 near literal.
4223 case Branch::kR6Literal:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004224 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004225 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4226 Lwpc(lhs, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004227 break;
4228
4229 // R6 long branches.
4230 case Branch::kR6LongUncondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004231 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004232 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4233 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4234 Auipc(AT, High16Bits(offset));
4235 Jic(AT, Low16Bits(offset));
4236 break;
4237 case Branch::kR6LongCondBranch:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004238 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4239 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4240 Emit(delayed_instruction);
4241 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004242 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004243 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4244 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4245 Auipc(AT, High16Bits(offset));
4246 Jic(AT, Low16Bits(offset));
4247 break;
4248 case Branch::kR6LongCall:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004249 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004250 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004251 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004252 Auipc(AT, High16Bits(offset));
4253 Jialc(AT, Low16Bits(offset));
4254 break;
4255
Alexey Frunze96b66822016-09-10 02:32:44 -07004256 // R6 far label.
4257 case Branch::kR6FarLabel:
4258 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4259 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
4260 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4261 Auipc(AT, High16Bits(offset));
4262 Addiu(lhs, AT, Low16Bits(offset));
4263 break;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004264 // R6 far literal.
4265 case Branch::kR6FarLiteral:
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004266 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004267 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4268 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4269 Auipc(AT, High16Bits(offset));
4270 Lw(lhs, AT, Low16Bits(offset));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004271 break;
4272 }
4273 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
4274 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
Alexey Frunzea663d9d2017-07-31 18:43:18 -07004275 if (patcher_label != nullptr) {
4276 // The patched instruction should look like one.
4277 uint32_t patched_instruction = buffer_.Load<uint32_t>(GetLabelLocation(patcher_label));
4278 CHECK(!IsAbsorbableInstruction(patched_instruction));
4279 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004280}
4281
Alexey Frunze0cab6562017-07-25 15:19:36 -07004282void MipsAssembler::B(MipsLabel* label, bool is_bare) {
4283 Buncond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004284}
4285
Alexey Frunze0cab6562017-07-25 15:19:36 -07004286void MipsAssembler::Bal(MipsLabel* label, bool is_bare) {
4287 Call(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004288}
4289
Alexey Frunze0cab6562017-07-25 15:19:36 -07004290void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4291 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004292}
4293
Alexey Frunze0cab6562017-07-25 15:19:36 -07004294void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4295 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004296}
4297
Alexey Frunze0cab6562017-07-25 15:19:36 -07004298void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) {
4299 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004300}
4301
Alexey Frunze0cab6562017-07-25 15:19:36 -07004302void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) {
4303 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004304}
4305
Alexey Frunze0cab6562017-07-25 15:19:36 -07004306void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) {
4307 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004308}
4309
Alexey Frunze0cab6562017-07-25 15:19:36 -07004310void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) {
4311 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004312}
4313
Alexey Frunze0cab6562017-07-25 15:19:36 -07004314void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) {
4315 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004316}
4317
Alexey Frunze0cab6562017-07-25 15:19:36 -07004318void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) {
4319 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004320}
4321
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004322bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
4323 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u]
4324 // instruction because either slt[u] depends on `rs` or `rt` or the following
4325 // conditional branch depends on AT set by slt[u].
4326 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
4327 // because slt[u] changes AT.
4328 return (delay_slot_.instruction_ != 0 &&
Alexey Frunzea247dea2017-11-03 18:43:04 -07004329 (delay_slot_.masks_.gpr_outs_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
4330 (delay_slot_.masks_.gpr_ins_ & (1u << AT)) == 0);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004331}
4332
4333void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
4334 // Exchange the last two instructions in the assembler buffer.
4335 size_t size = buffer_.Size();
4336 CHECK_GE(size, 2 * sizeof(uint32_t));
4337 size_t pos1 = size - 2 * sizeof(uint32_t);
4338 size_t pos2 = size - sizeof(uint32_t);
4339 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
4340 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
4341 CHECK_EQ(instr1, forwarded_slot.instruction_);
4342 CHECK_EQ(instr2, delay_slot_.instruction_);
4343 buffer_.Store<uint32_t>(pos1, instr2);
4344 buffer_.Store<uint32_t>(pos2, instr1);
4345 // Set the current delay slot information to that of the last instruction
4346 // in the buffer.
4347 delay_slot_ = forwarded_slot;
4348}
4349
4350void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) {
4351 // If possible, exchange the slt[u] instruction with the preceding instruction,
4352 // so it can fill the delay slot.
4353 DelaySlot forwarded_slot = delay_slot_;
4354 bool exchange = CanExchangeWithSlt(rs, rt);
4355 if (exchange) {
4356 // The last instruction cannot be used in a different delay slot,
4357 // do not commit the label before it (if any).
4358 DsFsmDropLabel();
4359 }
4360 if (unsigned_slt) {
4361 Sltu(AT, rs, rt);
4362 } else {
4363 Slt(AT, rs, rt);
4364 }
4365 if (exchange) {
4366 ExchangeWithSlt(forwarded_slot);
4367 }
4368}
4369
Alexey Frunze0cab6562017-07-25 15:19:36 -07004370void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4371 if (IsR6() && !is_bare) {
4372 Bcond(label, IsR6(), is_bare, kCondLT, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004373 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
4374 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004375 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004376 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004377 }
4378}
4379
Alexey Frunze0cab6562017-07-25 15:19:36 -07004380void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4381 if (IsR6() && !is_bare) {
4382 Bcond(label, IsR6(), is_bare, kCondGE, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004383 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004384 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004385 } else {
4386 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004387 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004388 Beqz(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004389 }
4390}
4391
Alexey Frunze0cab6562017-07-25 15:19:36 -07004392void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4393 if (IsR6() && !is_bare) {
4394 Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004395 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
4396 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004397 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004398 Bnez(AT, label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004399 }
4400}
4401
Alexey Frunze0cab6562017-07-25 15:19:36 -07004402void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4403 if (IsR6() && !is_bare) {
4404 Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004405 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07004406 B(label, is_bare);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004407 } else {
4408 // Synthesize the instruction (not available on R2).
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004409 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
Alexey Frunze0cab6562017-07-25 15:19:36 -07004410 Beqz(AT, label, is_bare);
jeffhao7fbee072012-08-24 17:56:54 -07004411 }
4412}
4413
Alexey Frunze0cab6562017-07-25 15:19:36 -07004414void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) {
4415 Bc1f(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004416}
4417
Alexey Frunze0cab6562017-07-25 15:19:36 -07004418void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004419 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004420 Bcond(label, /* is_r6 */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004421}
4422
Alexey Frunze0cab6562017-07-25 15:19:36 -07004423void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) {
4424 Bc1t(0, label, is_bare);
Chris Larsenb74353a2015-11-20 09:07:09 -08004425}
4426
Alexey Frunze0cab6562017-07-25 15:19:36 -07004427void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004428 CHECK(IsUint<3>(cc)) << cc;
Alexey Frunze0cab6562017-07-25 15:19:36 -07004429 Bcond(label, /* is_r6 */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004430}
4431
Alexey Frunze0cab6562017-07-25 15:19:36 -07004432void MipsAssembler::Bc(MipsLabel* label, bool is_bare) {
4433 Buncond(label, /* is_r6 */ true, is_bare);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004434}
4435
Alexey Frunze0cab6562017-07-25 15:19:36 -07004436void MipsAssembler::Balc(MipsLabel* label, bool is_bare) {
4437 Call(label, /* is_r6 */ true, is_bare);
4438}
4439
4440void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4441 Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt);
4442}
4443
4444void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4445 Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt);
4446}
4447
4448void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) {
4449 Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rt);
4450}
4451
4452void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) {
4453 Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rt);
4454}
4455
4456void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) {
4457 Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt);
4458}
4459
4460void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) {
4461 Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt);
4462}
4463
4464void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) {
4465 Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt);
4466}
4467
4468void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) {
4469 Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt);
4470}
4471
4472void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4473 Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt);
4474}
4475
4476void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4477 Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt);
4478}
4479
4480void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4481 Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt);
4482}
4483
4484void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
4485 Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt);
4486}
4487
4488void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) {
4489 Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO);
4490}
4491
4492void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) {
4493 Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004494}
4495
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004496void MipsAssembler::AdjustBaseAndOffset(Register& base,
4497 int32_t& offset,
4498 bool is_doubleword,
4499 bool is_float) {
4500 // This method is used to adjust the base register and offset pair
4501 // for a load/store when the offset doesn't fit into int16_t.
4502 // It is assumed that `base + offset` is sufficiently aligned for memory
4503 // operands that are machine word in size or smaller. For doubleword-sized
4504 // operands it's assumed that `base` is a multiple of 8, while `offset`
4505 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
4506 // and spilled variables on the stack accessed relative to the stack
4507 // pointer register).
4508 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
4509 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4510
4511 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
4512 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
4513
4514 // IsInt<16> must be passed a signed value, hence the static cast below.
4515 if (IsInt<16>(offset) &&
4516 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
4517 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
4518 return;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004519 }
4520
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004521 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
4522 uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
4523
4524 // Do not load the whole 32-bit `offset` if it can be represented as
4525 // a sum of two 16-bit signed offsets. This can save an instruction or two.
4526 // To simplify matters, only do this for a symmetric range of offsets from
4527 // about -64KB to about +64KB, allowing further addition of 4 when accessing
4528 // 64-bit variables with two 32-bit accesses.
4529 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
4530 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4531 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4532 Addiu(AT, base, kMinOffsetForSimpleAdjustment);
4533 offset -= kMinOffsetForSimpleAdjustment;
4534 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4535 Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
4536 offset += kMinOffsetForSimpleAdjustment;
4537 } else if (IsR6()) {
4538 // On R6 take advantage of the aui instruction, e.g.:
4539 // aui AT, base, offset_high
4540 // lw reg_lo, offset_low(AT)
4541 // lw reg_hi, (offset_low+4)(AT)
4542 // or when offset_low+4 overflows int16_t:
4543 // aui AT, base, offset_high
4544 // addiu AT, AT, 8
4545 // lw reg_lo, (offset_low-8)(AT)
4546 // lw reg_hi, (offset_low-4)(AT)
4547 int16_t offset_high = High16Bits(offset);
4548 int16_t offset_low = Low16Bits(offset);
4549 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store.
4550 Aui(AT, base, offset_high);
4551 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
4552 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
4553 Addiu(AT, AT, kMipsDoublewordSize);
4554 offset_low -= kMipsDoublewordSize;
4555 }
4556 offset = offset_low;
4557 } else {
4558 // Do not load the whole 32-bit `offset` if it can be represented as
4559 // a sum of three 16-bit signed offsets. This can save an instruction.
4560 // To simplify matters, only do this for a symmetric range of offsets from
4561 // about -96KB to about +96KB, allowing further addition of 4 when accessing
4562 // 64-bit variables with two 32-bit accesses.
4563 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4564 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
4565 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4566 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
4567 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
4568 offset -= kMinOffsetForMediumAdjustment;
4569 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4570 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
4571 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
4572 offset += kMinOffsetForMediumAdjustment;
4573 } else {
4574 // Now that all shorter options have been exhausted, load the full 32-bit offset.
4575 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
4576 LoadConst32(AT, loaded_offset);
4577 Addu(AT, AT, base);
4578 offset -= loaded_offset;
4579 }
4580 }
4581 base = AT;
4582
4583 CHECK(IsInt<16>(offset));
4584 if (two_accesses) {
4585 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
4586 }
4587 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
4588}
4589
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004590void MipsAssembler::AdjustBaseOffsetAndElementSizeShift(Register& base,
4591 int32_t& offset,
4592 int& element_size_shift) {
4593 // This method is used to adjust the base register, offset and element_size_shift
4594 // for a vector load/store when the offset doesn't fit into allowed number of bits.
4595 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
4596 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
4597 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
4598 // If element_size_shift is non-negative at entry, it won't be changed, but offset
4599 // will be checked for appropriate alignment. If negative at entry, it will be
4600 // adjusted based on offset for maximum fit.
4601 // It's assumed that `base` is a multiple of 8.
4602 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4603
4604 if (element_size_shift >= 0) {
4605 CHECK_LE(element_size_shift, TIMES_8);
4606 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4607 } else if (IsAligned<kMipsDoublewordSize>(offset)) {
4608 element_size_shift = TIMES_8;
4609 } else if (IsAligned<kMipsWordSize>(offset)) {
4610 element_size_shift = TIMES_4;
4611 } else if (IsAligned<kMipsHalfwordSize>(offset)) {
4612 element_size_shift = TIMES_2;
4613 } else {
4614 element_size_shift = TIMES_1;
4615 }
4616
4617 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
4618 // will take.
4619 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
4620 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
4621 if (low == offset) {
4622 return; // `offset` fits into ld.df/st.df.
4623 }
4624
4625 // First, see if `offset` can be represented as a sum of two or three signed offsets.
4626 // This can save an instruction or two.
4627
4628 // Max int16_t that's a multiple of element size.
4629 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
4630 // Max ld.df/st.df offset that's a multiple of element size.
4631 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
4632 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
4633 const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment;
4634 const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset;
4635
4636 if (IsInt<16>(offset)) {
4637 Addiu(AT, base, offset);
4638 offset = 0;
4639 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4640 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4641 offset -= kMaxDeltaForSimpleAdjustment;
4642 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4643 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4644 offset += kMaxDeltaForSimpleAdjustment;
4645 } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4646 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4647 if (offset <= kMinOffsetForMediumAdjustment) {
4648 Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment);
4649 offset = 0;
4650 } else {
4651 Addiu(AT, AT, kMaxDeltaForSimpleAdjustment);
4652 offset -= kMinOffsetForMediumAdjustment;
4653 }
4654 } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4655 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4656 if (-kMinOffsetForMediumAdjustment <= offset) {
4657 Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment);
4658 offset = 0;
4659 } else {
4660 Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment);
4661 offset += kMinOffsetForMediumAdjustment;
4662 }
4663 } else {
4664 // 16-bit or smaller parts of `offset`:
4665 // |31 hi 16|15 mid 13-10|12-9 low 0|
4666 //
4667 // Instructions that supply each part as a signed integer addend:
4668 // |aui |addiu |ld.df/st.df |
4669 uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset`
4670 // (accounts for sign of `low`).
4671 tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu.
4672 int16_t mid = Low16Bits(tmp);
4673 int16_t hi = High16Bits(tmp);
4674 if (IsR6()) {
4675 Aui(AT, base, hi);
4676 } else {
4677 Lui(AT, hi);
4678 Addu(AT, AT, base);
4679 }
4680 if (mid != 0) {
4681 Addiu(AT, AT, mid);
4682 }
4683 offset = low;
4684 }
4685 base = AT;
4686 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4687 CHECK(IsInt<10>(offset >> element_size_shift));
4688}
4689
Alexey Frunze2923db72016-08-20 01:55:47 -07004690void MipsAssembler::LoadFromOffset(LoadOperandType type,
4691 Register reg,
4692 Register base,
Alexey Frunzecad3a4c2016-06-07 23:40:37 -07004693 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004694 LoadFromOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004695}
4696
4697void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004698 LoadSFromOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004699}
4700
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004701void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004702 LoadDFromOffset<>(reg, base, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004703}
4704
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004705void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) {
4706 LoadQFromOffset<>(reg, base, offset);
4707}
4708
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004709void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
4710 size_t size) {
4711 MipsManagedRegister dst = m_dst.AsMips();
4712 if (dst.IsNoRegister()) {
4713 CHECK_EQ(0u, size) << dst;
4714 } else if (dst.IsCoreRegister()) {
4715 CHECK_EQ(kMipsWordSize, size) << dst;
4716 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
4717 } else if (dst.IsRegisterPair()) {
4718 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4719 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
4720 } else if (dst.IsFRegister()) {
4721 if (size == kMipsWordSize) {
4722 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
4723 } else {
4724 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4725 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
4726 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08004727 } else if (dst.IsDRegister()) {
4728 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4729 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004730 }
jeffhao7fbee072012-08-24 17:56:54 -07004731}
4732
Alexey Frunze2923db72016-08-20 01:55:47 -07004733void MipsAssembler::StoreToOffset(StoreOperandType type,
4734 Register reg,
4735 Register base,
jeffhao7fbee072012-08-24 17:56:54 -07004736 int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004737 StoreToOffset<>(type, reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004738}
4739
Goran Jakovljevicff734982015-08-24 12:58:55 +00004740void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004741 StoreSToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004742}
4743
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004744void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004745 StoreDToOffset<>(reg, base, offset);
jeffhao7fbee072012-08-24 17:56:54 -07004746}
4747
Lena Djokic2e0a7e52017-07-06 11:55:24 +02004748void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) {
4749 StoreQToOffset<>(reg, base, offset);
4750}
4751
David Srbeckydd973932015-04-07 20:29:48 +01004752static dwarf::Reg DWARFReg(Register reg) {
4753 return dwarf::Reg::MipsCore(static_cast<int>(reg));
4754}
4755
Ian Rogers790a6b72014-04-01 10:36:00 -07004756constexpr size_t kFramePointerSize = 4;
4757
Vladimir Marko32248382016-05-19 10:37:24 +01004758void MipsAssembler::BuildFrame(size_t frame_size,
4759 ManagedRegister method_reg,
4760 ArrayRef<const ManagedRegister> callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +07004761 const ManagedRegisterEntrySpills& entry_spills) {
jeffhao7fbee072012-08-24 17:56:54 -07004762 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004763 DCHECK(!overwriting_);
jeffhao7fbee072012-08-24 17:56:54 -07004764
4765 // Increase frame to required size.
4766 IncreaseFrameSize(frame_size);
4767
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004768 // Push callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07004769 int stack_offset = frame_size - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004770 StoreToOffset(kStoreWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004771 cfi_.RelOffset(DWARFReg(RA), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07004772 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
Ian Rogers790a6b72014-04-01 10:36:00 -07004773 stack_offset -= kFramePointerSize;
Vladimir Marko32248382016-05-19 10:37:24 +01004774 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07004775 StoreToOffset(kStoreWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004776 cfi_.RelOffset(DWARFReg(reg), stack_offset);
jeffhao7fbee072012-08-24 17:56:54 -07004777 }
4778
4779 // Write out Method*.
4780 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
4781
4782 // Write out entry spills.
Goran Jakovljevicff734982015-08-24 12:58:55 +00004783 int32_t offset = frame_size + kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004784 for (size_t i = 0; i < entry_spills.size(); ++i) {
Goran Jakovljevicff734982015-08-24 12:58:55 +00004785 MipsManagedRegister reg = entry_spills.at(i).AsMips();
4786 if (reg.IsNoRegister()) {
4787 ManagedRegisterSpill spill = entry_spills.at(i);
4788 offset += spill.getSize();
4789 } else if (reg.IsCoreRegister()) {
4790 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004791 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004792 } else if (reg.IsFRegister()) {
4793 StoreSToOffset(reg.AsFRegister(), SP, offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004794 offset += kMipsWordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004795 } else if (reg.IsDRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004796 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
4797 offset += kMipsDoublewordSize;
Goran Jakovljevicff734982015-08-24 12:58:55 +00004798 }
jeffhao7fbee072012-08-24 17:56:54 -07004799 }
4800}
4801
4802void MipsAssembler::RemoveFrame(size_t frame_size,
Roland Levillain0d127e12017-07-05 17:01:11 +01004803 ArrayRef<const ManagedRegister> callee_save_regs,
4804 bool may_suspend ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07004805 CHECK_ALIGNED(frame_size, kStackAlignment);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004806 DCHECK(!overwriting_);
David Srbeckydd973932015-04-07 20:29:48 +01004807 cfi_.RememberState();
jeffhao7fbee072012-08-24 17:56:54 -07004808
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004809 // Pop callee saves and return address.
Ian Rogers790a6b72014-04-01 10:36:00 -07004810 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004811 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
Vladimir Marko32248382016-05-19 10:37:24 +01004812 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
jeffhao7fbee072012-08-24 17:56:54 -07004813 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004814 cfi_.Restore(DWARFReg(reg));
Ian Rogers790a6b72014-04-01 10:36:00 -07004815 stack_offset += kFramePointerSize;
jeffhao7fbee072012-08-24 17:56:54 -07004816 }
4817 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
David Srbeckydd973932015-04-07 20:29:48 +01004818 cfi_.Restore(DWARFReg(RA));
jeffhao7fbee072012-08-24 17:56:54 -07004819
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004820 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
4821 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
4822 bool reordering = SetReorder(false);
4823 if (exchange) {
4824 // Jump to the return address.
4825 Jr(RA);
4826 // Decrease frame to required size.
4827 DecreaseFrameSize(frame_size); // Single instruction in delay slot.
4828 } else {
4829 // Decrease frame to required size.
4830 DecreaseFrameSize(frame_size);
4831 // Jump to the return address.
4832 Jr(RA);
4833 Nop(); // In delay slot.
4834 }
4835 SetReorder(reordering);
David Srbeckydd973932015-04-07 20:29:48 +01004836
4837 // The CFI should be restored for any code that follows the exit block.
4838 cfi_.RestoreState();
4839 cfi_.DefCFAOffset(frame_size);
jeffhao7fbee072012-08-24 17:56:54 -07004840}
4841
4842void MipsAssembler::IncreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004843 CHECK_ALIGNED(adjust, kFramePointerSize);
4844 Addiu32(SP, SP, -adjust);
David Srbeckydd973932015-04-07 20:29:48 +01004845 cfi_.AdjustCFAOffset(adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004846 if (overwriting_) {
4847 cfi_.OverrideDelayedPC(overwrite_location_);
4848 }
jeffhao7fbee072012-08-24 17:56:54 -07004849}
4850
4851void MipsAssembler::DecreaseFrameSize(size_t adjust) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004852 CHECK_ALIGNED(adjust, kFramePointerSize);
4853 Addiu32(SP, SP, adjust);
David Srbeckydd973932015-04-07 20:29:48 +01004854 cfi_.AdjustCFAOffset(-adjust);
Vladimir Marko10ef6942015-10-22 15:25:54 +01004855 if (overwriting_) {
4856 cfi_.OverrideDelayedPC(overwrite_location_);
4857 }
jeffhao7fbee072012-08-24 17:56:54 -07004858}
4859
4860void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
4861 MipsManagedRegister src = msrc.AsMips();
4862 if (src.IsNoRegister()) {
4863 CHECK_EQ(0u, size);
4864 } else if (src.IsCoreRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004865 CHECK_EQ(kMipsWordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07004866 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4867 } else if (src.IsRegisterPair()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004868 CHECK_EQ(kMipsDoublewordSize, size);
jeffhao7fbee072012-08-24 17:56:54 -07004869 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
4870 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004871 SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07004872 } else if (src.IsFRegister()) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004873 if (size == kMipsWordSize) {
4874 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
4875 } else {
4876 CHECK_EQ(kMipsDoublewordSize, size);
4877 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
4878 }
Alexey Frunze1b8464d2016-11-12 17:22:05 -08004879 } else if (src.IsDRegister()) {
4880 CHECK_EQ(kMipsDoublewordSize, size);
4881 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07004882 }
4883}
4884
4885void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
4886 MipsManagedRegister src = msrc.AsMips();
4887 CHECK(src.IsCoreRegister());
4888 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4889}
4890
4891void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
4892 MipsManagedRegister src = msrc.AsMips();
4893 CHECK(src.IsCoreRegister());
4894 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4895}
4896
4897void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
4898 ManagedRegister mscratch) {
4899 MipsManagedRegister scratch = mscratch.AsMips();
4900 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004901 LoadConst32(scratch.AsCoreRegister(), imm);
jeffhao7fbee072012-08-24 17:56:54 -07004902 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
4903}
4904
Andreas Gampe3b165bc2016-08-01 22:07:04 -07004905void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
4906 FrameOffset fr_offs,
jeffhao7fbee072012-08-24 17:56:54 -07004907 ManagedRegister mscratch) {
4908 MipsManagedRegister scratch = mscratch.AsMips();
4909 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004910 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07004911 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
4912 S1, thr_offs.Int32Value());
4913}
4914
Andreas Gampe3b165bc2016-08-01 22:07:04 -07004915void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
jeffhao7fbee072012-08-24 17:56:54 -07004916 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
4917}
4918
4919void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
4920 FrameOffset in_off, ManagedRegister mscratch) {
4921 MipsManagedRegister src = msrc.AsMips();
4922 MipsManagedRegister scratch = mscratch.AsMips();
4923 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4924 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004925 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07004926}
4927
4928void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
4929 return EmitLoad(mdest, SP, src.Int32Value(), size);
4930}
4931
Andreas Gampe3b165bc2016-08-01 22:07:04 -07004932void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07004933 return EmitLoad(mdest, S1, src.Int32Value(), size);
4934}
4935
4936void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
4937 MipsManagedRegister dest = mdest.AsMips();
4938 CHECK(dest.IsCoreRegister());
4939 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
4940}
4941
Mathieu Chartiere401d142015-04-22 13:56:20 -07004942void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +01004943 bool unpoison_reference) {
jeffhao7fbee072012-08-24 17:56:54 -07004944 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004945 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07004946 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
4947 base.AsMips().AsCoreRegister(), offs.Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08004948 if (unpoison_reference) {
4949 MaybeUnpoisonHeapReference(dest.AsCoreRegister());
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -08004950 }
jeffhao7fbee072012-08-24 17:56:54 -07004951}
4952
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004953void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
jeffhao7fbee072012-08-24 17:56:54 -07004954 MipsManagedRegister dest = mdest.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004955 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
jeffhao7fbee072012-08-24 17:56:54 -07004956 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
4957 base.AsMips().AsCoreRegister(), offs.Int32Value());
4958}
4959
Andreas Gampe3b165bc2016-08-01 22:07:04 -07004960void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
jeffhao7fbee072012-08-24 17:56:54 -07004961 MipsManagedRegister dest = mdest.AsMips();
4962 CHECK(dest.IsCoreRegister());
4963 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
4964}
4965
4966void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
4967 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
4968}
4969
4970void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
4971 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
4972}
4973
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004974void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07004975 MipsManagedRegister dest = mdest.AsMips();
4976 MipsManagedRegister src = msrc.AsMips();
4977 if (!dest.Equals(src)) {
4978 if (dest.IsCoreRegister()) {
4979 CHECK(src.IsCoreRegister()) << src;
4980 Move(dest.AsCoreRegister(), src.AsCoreRegister());
4981 } else if (dest.IsFRegister()) {
4982 CHECK(src.IsFRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004983 if (size == kMipsWordSize) {
4984 MovS(dest.AsFRegister(), src.AsFRegister());
4985 } else {
4986 CHECK_EQ(kMipsDoublewordSize, size);
4987 MovD(dest.AsFRegister(), src.AsFRegister());
4988 }
jeffhao7fbee072012-08-24 17:56:54 -07004989 } else if (dest.IsDRegister()) {
4990 CHECK(src.IsDRegister()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004991 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
jeffhao7fbee072012-08-24 17:56:54 -07004992 } else {
4993 CHECK(dest.IsRegisterPair()) << dest;
4994 CHECK(src.IsRegisterPair()) << src;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02004995 // Ensure that the first move doesn't clobber the input of the second.
jeffhao7fbee072012-08-24 17:56:54 -07004996 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
4997 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
4998 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
4999 } else {
5000 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
5001 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
5002 }
5003 }
5004 }
5005}
5006
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005007void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005008 MipsManagedRegister scratch = mscratch.AsMips();
5009 CHECK(scratch.IsCoreRegister()) << scratch;
5010 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5011 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
5012}
5013
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005014void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
5015 ThreadOffset32 thr_offs,
5016 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005017 MipsManagedRegister scratch = mscratch.AsMips();
5018 CHECK(scratch.IsCoreRegister()) << scratch;
5019 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5020 S1, thr_offs.Int32Value());
5021 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5022 SP, fr_offs.Int32Value());
5023}
5024
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005025void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
5026 FrameOffset fr_offs,
5027 ManagedRegister mscratch) {
jeffhao7fbee072012-08-24 17:56:54 -07005028 MipsManagedRegister scratch = mscratch.AsMips();
5029 CHECK(scratch.IsCoreRegister()) << scratch;
5030 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5031 SP, fr_offs.Int32Value());
5032 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
5033 S1, thr_offs.Int32Value());
5034}
5035
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005036void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
jeffhao7fbee072012-08-24 17:56:54 -07005037 MipsManagedRegister scratch = mscratch.AsMips();
5038 CHECK(scratch.IsCoreRegister()) << scratch;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005039 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
5040 if (size == kMipsWordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005041 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5042 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005043 } else if (size == kMipsDoublewordSize) {
jeffhao7fbee072012-08-24 17:56:54 -07005044 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
5045 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005046 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
5047 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005048 }
5049}
5050
5051void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
5052 ManagedRegister mscratch, size_t size) {
5053 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005054 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005055 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
5056 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
5057}
5058
5059void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
5060 ManagedRegister mscratch, size_t size) {
5061 Register scratch = mscratch.AsMips().AsCoreRegister();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005062 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005063 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
5064 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5065}
5066
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005067void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5068 FrameOffset src_base ATTRIBUTE_UNUSED,
5069 Offset src_offset ATTRIBUTE_UNUSED,
5070 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5071 size_t size ATTRIBUTE_UNUSED) {
5072 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005073}
5074
5075void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
5076 ManagedRegister src, Offset src_offset,
5077 ManagedRegister mscratch, size_t size) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005078 CHECK_EQ(size, kMipsWordSize);
jeffhao7fbee072012-08-24 17:56:54 -07005079 Register scratch = mscratch.AsMips().AsCoreRegister();
5080 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
5081 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
5082}
5083
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005084void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
5085 Offset dest_offset ATTRIBUTE_UNUSED,
5086 FrameOffset src ATTRIBUTE_UNUSED,
5087 Offset src_offset ATTRIBUTE_UNUSED,
5088 ManagedRegister mscratch ATTRIBUTE_UNUSED,
5089 size_t size ATTRIBUTE_UNUSED) {
5090 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005091}
5092
5093void MipsAssembler::MemoryBarrier(ManagedRegister) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005094 // TODO: sync?
5095 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005096}
5097
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005098void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005099 FrameOffset handle_scope_offset,
5100 ManagedRegister min_reg,
5101 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005102 MipsManagedRegister out_reg = mout_reg.AsMips();
5103 MipsManagedRegister in_reg = min_reg.AsMips();
5104 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
5105 CHECK(out_reg.IsCoreRegister()) << out_reg;
5106 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005107 MipsLabel null_arg;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005108 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5109 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005110 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
jeffhao7fbee072012-08-24 17:56:54 -07005111 if (in_reg.IsNoRegister()) {
5112 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005113 SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005114 in_reg = out_reg;
5115 }
5116 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005117 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005118 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005119 Beqz(in_reg.AsCoreRegister(), &null_arg);
5120 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5121 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005122 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005123 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005124 }
5125}
5126
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005127void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005128 FrameOffset handle_scope_offset,
5129 ManagedRegister mscratch,
5130 bool null_allowed) {
jeffhao7fbee072012-08-24 17:56:54 -07005131 MipsManagedRegister scratch = mscratch.AsMips();
5132 CHECK(scratch.IsCoreRegister()) << scratch;
5133 if (null_allowed) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005134 MipsLabel null_arg;
5135 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005136 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5137 // the address in the handle scope holding the reference.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005138 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
5139 Beqz(scratch.AsCoreRegister(), &null_arg);
5140 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5141 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005142 } else {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005143 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005144 }
5145 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
5146}
5147
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07005148// Given a handle scope entry, load the associated reference.
5149void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005150 ManagedRegister min_reg) {
jeffhao7fbee072012-08-24 17:56:54 -07005151 MipsManagedRegister out_reg = mout_reg.AsMips();
5152 MipsManagedRegister in_reg = min_reg.AsMips();
5153 CHECK(out_reg.IsCoreRegister()) << out_reg;
5154 CHECK(in_reg.IsCoreRegister()) << in_reg;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005155 MipsLabel null_arg;
jeffhao7fbee072012-08-24 17:56:54 -07005156 if (!out_reg.Equals(in_reg)) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005157 LoadConst32(out_reg.AsCoreRegister(), 0);
jeffhao7fbee072012-08-24 17:56:54 -07005158 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005159 Beqz(in_reg.AsCoreRegister(), &null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005160 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
5161 in_reg.AsCoreRegister(), 0);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005162 Bind(&null_arg);
jeffhao7fbee072012-08-24 17:56:54 -07005163}
5164
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005165void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
5166 bool could_be_null ATTRIBUTE_UNUSED) {
5167 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005168}
5169
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005170void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
5171 bool could_be_null ATTRIBUTE_UNUSED) {
5172 // TODO: not validating references.
jeffhao7fbee072012-08-24 17:56:54 -07005173}
5174
5175void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
5176 MipsManagedRegister base = mbase.AsMips();
5177 MipsManagedRegister scratch = mscratch.AsMips();
5178 CHECK(base.IsCoreRegister()) << base;
5179 CHECK(scratch.IsCoreRegister()) << scratch;
5180 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5181 base.AsCoreRegister(), offset.Int32Value());
5182 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005183 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005184 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005185}
5186
5187void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
5188 MipsManagedRegister scratch = mscratch.AsMips();
5189 CHECK(scratch.IsCoreRegister()) << scratch;
5190 // Call *(*(SP + base) + offset)
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005191 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
jeffhao7fbee072012-08-24 17:56:54 -07005192 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5193 scratch.AsCoreRegister(), offset.Int32Value());
5194 Jalr(scratch.AsCoreRegister());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005195 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005196 // TODO: place reference map on call.
jeffhao7fbee072012-08-24 17:56:54 -07005197}
5198
Andreas Gampe3b165bc2016-08-01 22:07:04 -07005199void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
5200 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
Ian Rogers468532e2013-08-05 10:56:33 -07005201 UNIMPLEMENTED(FATAL) << "no mips implementation";
jeffhao7fbee072012-08-24 17:56:54 -07005202}
5203
5204void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
5205 Move(tr.AsMips().AsCoreRegister(), S1);
5206}
5207
5208void MipsAssembler::GetCurrentThread(FrameOffset offset,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005209 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
jeffhao7fbee072012-08-24 17:56:54 -07005210 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
5211}
5212
jeffhao7fbee072012-08-24 17:56:54 -07005213void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
5214 MipsManagedRegister scratch = mscratch.AsMips();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005215 exception_blocks_.emplace_back(scratch, stack_adjust);
jeffhao7fbee072012-08-24 17:56:54 -07005216 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Andreas Gampe542451c2016-07-26 09:02:02 -07005217 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005218 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
jeffhao7fbee072012-08-24 17:56:54 -07005219}
5220
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005221void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
5222 Bind(exception->Entry());
5223 if (exception->stack_adjust_ != 0) { // Fix up the frame.
5224 DecreaseFrameSize(exception->stack_adjust_);
jeffhao7fbee072012-08-24 17:56:54 -07005225 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005226 // Pass exception object as argument.
5227 // Don't care about preserving A0 as this call won't return.
5228 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5229 Move(A0, exception->scratch_.AsCoreRegister());
5230 // Set up call to Thread::Current()->pDeliverException.
5231 LoadFromOffset(kLoadWord, T9, S1,
Andreas Gampe542451c2016-07-26 09:02:02 -07005232 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value());
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005233 Jr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005234 NopIfNoReordering();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +02005235
5236 // Call never returns.
5237 Break();
jeffhao7fbee072012-08-24 17:56:54 -07005238}
5239
5240} // namespace mips
5241} // namespace art