1 /*
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
19 #include "base/bit_utils.h"
20 #include "base/casts.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "entrypoints/quick/quick_entrypoints_enum.h"
23 #include "memory_region.h"
24 #include "thread.h"
25
26 namespace art {
27 namespace mips {
28
29 static_assert(static_cast<size_t>(kMipsPointerSize) == kMipsWordSize,
30 "Unexpected Mips pointer size.");
31 static_assert(kMipsPointerSize == PointerSize::k32, "Unexpected Mips pointer size.");
32
33
operator <<(std::ostream & os,const DRegister & rhs)34 std::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
DelaySlot()43 MipsAssembler::DelaySlot::DelaySlot()
44 : instruction_(0),
45 gpr_outs_mask_(0),
46 gpr_ins_mask_(0),
47 fpr_outs_mask_(0),
48 fpr_ins_mask_(0),
49 cc_outs_mask_(0),
50 cc_ins_mask_(0) {}
51
DsFsmInstr(uint32_t instruction,uint32_t gpr_outs_mask,uint32_t gpr_ins_mask,uint32_t fpr_outs_mask,uint32_t fpr_ins_mask,uint32_t cc_outs_mask,uint32_t cc_ins_mask)52 void MipsAssembler::DsFsmInstr(uint32_t instruction,
53 uint32_t gpr_outs_mask,
54 uint32_t gpr_ins_mask,
55 uint32_t fpr_outs_mask,
56 uint32_t fpr_ins_mask,
57 uint32_t cc_outs_mask,
58 uint32_t cc_ins_mask) {
59 if (!reordering_) {
60 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
61 CHECK_EQ(delay_slot_.instruction_, 0u);
62 return;
63 }
64 switch (ds_fsm_state_) {
65 case kExpectingLabel:
66 break;
67 case kExpectingInstruction:
68 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
69 // If the last instruction is not suitable for delay slots, drop
70 // the PC of the label preceding it so that no unconditional branch
71 // uses this instruction to fill its delay slot.
72 if (instruction == 0) {
73 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
74 } else {
75 // Otherwise wait for another instruction or label before we can
76 // commit the label PC. The label PC will be dropped if instead
77 // of another instruction or label there's a call from the code
78 // generator to CodePosition() to record the buffer size.
79 // Instructions after which the buffer size is recorded cannot
80 // be moved into delay slots or anywhere else because they may
81 // trigger signals and the signal handlers expect these signals
82 // to be coming from the instructions immediately preceding the
83 // recorded buffer locations.
84 ds_fsm_state_ = kExpectingCommit;
85 }
86 break;
87 case kExpectingCommit:
88 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size());
89 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel.
90 break;
91 }
92 delay_slot_.instruction_ = instruction;
93 delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u; // Ignore register ZERO.
94 delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u; // Ignore register ZERO.
95 delay_slot_.fpr_outs_mask_ = fpr_outs_mask;
96 delay_slot_.fpr_ins_mask_ = fpr_ins_mask;
97 delay_slot_.cc_outs_mask_ = cc_outs_mask;
98 delay_slot_.cc_ins_mask_ = cc_ins_mask;
99 }
100
DsFsmLabel()101 void MipsAssembler::DsFsmLabel() {
102 if (!reordering_) {
103 CHECK_EQ(ds_fsm_state_, kExpectingLabel);
104 CHECK_EQ(delay_slot_.instruction_, 0u);
105 return;
106 }
107 switch (ds_fsm_state_) {
108 case kExpectingLabel:
109 ds_fsm_target_pc_ = buffer_.Size();
110 ds_fsm_state_ = kExpectingInstruction;
111 break;
112 case kExpectingInstruction:
113 // Allow consecutive labels.
114 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size());
115 break;
116 case kExpectingCommit:
117 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
118 DsFsmCommitLabel();
119 ds_fsm_target_pc_ = buffer_.Size();
120 ds_fsm_state_ = kExpectingInstruction;
121 break;
122 }
123 // We cannot move instructions into delay slots across labels.
124 delay_slot_.instruction_ = 0;
125 }
126
DsFsmCommitLabel()127 void MipsAssembler::DsFsmCommitLabel() {
128 if (ds_fsm_state_ == kExpectingCommit) {
129 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_);
130 }
131 ds_fsm_state_ = kExpectingLabel;
132 }
133
DsFsmDropLabel()134 void MipsAssembler::DsFsmDropLabel() {
135 ds_fsm_state_ = kExpectingLabel;
136 }
137
SetReorder(bool enable)138 bool MipsAssembler::SetReorder(bool enable) {
139 bool last_state = reordering_;
140 if (last_state != enable) {
141 DsFsmCommitLabel();
142 DsFsmInstrNop(0);
143 }
144 reordering_ = enable;
145 return last_state;
146 }
147
CodePosition()148 size_t MipsAssembler::CodePosition() {
149 // The last instruction cannot be used in a delay slot, do not commit
150 // the label before it (if any) and clear the delay slot.
151 DsFsmDropLabel();
152 DsFsmInstrNop(0);
153 size_t size = buffer_.Size();
154 // In theory we can get the following sequence:
155 // label1:
156 // instr
157 // label2: # label1 gets committed when label2 is seen
158 // CodePosition() call
159 // and we need to uncommit label1.
160 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) {
161 ds_fsm_target_pcs_.pop_back();
162 }
163 return size;
164 }
165
DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED)166 void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
167 DsFsmInstr(0, 0, 0, 0, 0, 0, 0);
168 }
169
DsFsmInstrRrr(uint32_t instruction,Register out,Register in1,Register in2)170 void MipsAssembler::DsFsmInstrRrr(uint32_t instruction, Register out, Register in1, Register in2) {
171 DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0);
172 }
173
DsFsmInstrRrrr(uint32_t instruction,Register in1_out,Register in2,Register in3)174 void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction,
175 Register in1_out,
176 Register in2,
177 Register in3) {
178 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0);
179 }
180
DsFsmInstrFff(uint32_t instruction,FRegister out,FRegister in1,FRegister in2)181 void MipsAssembler::DsFsmInstrFff(uint32_t instruction,
182 FRegister out,
183 FRegister in1,
184 FRegister in2) {
185 DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0);
186 }
187
DsFsmInstrFfff(uint32_t instruction,FRegister in1_out,FRegister in2,FRegister in3)188 void MipsAssembler::DsFsmInstrFfff(uint32_t instruction,
189 FRegister in1_out,
190 FRegister in2,
191 FRegister in3) {
192 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0);
193 }
194
DsFsmInstrFffr(uint32_t instruction,FRegister in1_out,FRegister in2,Register in3)195 void MipsAssembler::DsFsmInstrFffr(uint32_t instruction,
196 FRegister in1_out,
197 FRegister in2,
198 Register in3) {
199 DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0);
200 }
201
DsFsmInstrRf(uint32_t instruction,Register out,FRegister in)202 void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) {
203 DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0);
204 }
205
DsFsmInstrFr(uint32_t instruction,FRegister out,Register in)206 void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) {
207 DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0);
208 }
209
DsFsmInstrFR(uint32_t instruction,FRegister in1,Register in2)210 void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) {
211 DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0);
212 }
213
DsFsmInstrCff(uint32_t instruction,int cc_out,FRegister in1,FRegister in2)214 void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) {
215 DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0);
216 }
217
DsFsmInstrRrrc(uint32_t instruction,Register in1_out,Register in2,int cc_in)218 void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction,
219 Register in1_out,
220 Register in2,
221 int cc_in) {
222 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in));
223 }
224
DsFsmInstrFffc(uint32_t instruction,FRegister in1_out,FRegister in2,int cc_in)225 void MipsAssembler::DsFsmInstrFffc(uint32_t instruction,
226 FRegister in1_out,
227 FRegister in2,
228 int cc_in) {
229 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in));
230 }
231
FinalizeCode()232 void MipsAssembler::FinalizeCode() {
233 for (auto& exception_block : exception_blocks_) {
234 EmitExceptionPoll(&exception_block);
235 }
236 // Commit the last branch target label (if any) and disable instruction reordering.
237 DsFsmCommitLabel();
238 SetReorder(false);
239 EmitLiterals();
240 ReserveJumpTableSpace();
241 PromoteBranches();
242 }
243
FinalizeInstructions(const MemoryRegion & region)244 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
245 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
246 EmitBranches();
247 EmitJumpTables();
248 Assembler::FinalizeInstructions(region);
249 PatchCFI(number_of_delayed_adjust_pcs);
250 }
251
PatchCFI(size_t number_of_delayed_adjust_pcs)252 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
253 if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
254 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
255 return;
256 }
257
258 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
259 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
260 const std::vector<uint8_t>& old_stream = data.first;
261 const std::vector<DelayedAdvancePC>& advances = data.second;
262
263 // PCs recorded before EmitBranches() need to be adjusted.
264 // PCs recorded during EmitBranches() are already adjusted.
265 // Both ranges are separately sorted but they may overlap.
266 if (kIsDebugBuild) {
267 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
268 return lhs.pc < rhs.pc;
269 };
270 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
271 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
272 }
273
274 // Append initial CFI data if any.
275 size_t size = advances.size();
276 DCHECK_NE(size, 0u);
277 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
278 // Emit PC adjustments interleaved with the old CFI stream.
279 size_t adjust_pos = 0u;
280 size_t late_emit_pos = number_of_delayed_adjust_pcs;
281 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
282 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
283 ? GetAdjustedPosition(advances[adjust_pos].pc)
284 : static_cast<size_t>(-1);
285 size_t late_emit_pc = (late_emit_pos != size)
286 ? advances[late_emit_pos].pc
287 : static_cast<size_t>(-1);
288 size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
289 DCHECK_NE(advance_pc, static_cast<size_t>(-1));
290 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
291 if (adjusted_pc <= late_emit_pc) {
292 ++adjust_pos;
293 } else {
294 ++late_emit_pos;
295 }
296 cfi().AdvancePC(advance_pc);
297 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
298 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
299 }
300 }
301
EmitBranches()302 void MipsAssembler::EmitBranches() {
303 CHECK(!overwriting_);
304 CHECK(!reordering_);
305 // Now that everything has its final position in the buffer (the branches have
306 // been promoted), adjust the target label PCs.
307 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) {
308 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]);
309 }
310 // Switch from appending instructions at the end of the buffer to overwriting
311 // existing instructions (branch placeholders) in the buffer.
312 overwriting_ = true;
313 for (auto& branch : branches_) {
314 EmitBranch(&branch);
315 }
316 overwriting_ = false;
317 }
318
Emit(uint32_t value)319 void MipsAssembler::Emit(uint32_t value) {
320 if (overwriting_) {
321 // Branches to labels are emitted into their placeholders here.
322 buffer_.Store<uint32_t>(overwrite_location_, value);
323 overwrite_location_ += sizeof(uint32_t);
324 } else {
325 // Other instructions are simply appended at the end here.
326 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
327 buffer_.Emit<uint32_t>(value);
328 }
329 }
330
EmitR(int opcode,Register rs,Register rt,Register rd,int shamt,int funct)331 uint32_t MipsAssembler::EmitR(int opcode,
332 Register rs,
333 Register rt,
334 Register rd,
335 int shamt,
336 int funct) {
337 CHECK_NE(rs, kNoRegister);
338 CHECK_NE(rt, kNoRegister);
339 CHECK_NE(rd, kNoRegister);
340 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
341 static_cast<uint32_t>(rs) << kRsShift |
342 static_cast<uint32_t>(rt) << kRtShift |
343 static_cast<uint32_t>(rd) << kRdShift |
344 shamt << kShamtShift |
345 funct;
346 Emit(encoding);
347 return encoding;
348 }
349
EmitI(int opcode,Register rs,Register rt,uint16_t imm)350 uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
351 CHECK_NE(rs, kNoRegister);
352 CHECK_NE(rt, kNoRegister);
353 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
354 static_cast<uint32_t>(rs) << kRsShift |
355 static_cast<uint32_t>(rt) << kRtShift |
356 imm;
357 Emit(encoding);
358 return encoding;
359 }
360
EmitI21(int opcode,Register rs,uint32_t imm21)361 uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
362 CHECK_NE(rs, kNoRegister);
363 CHECK(IsUint<21>(imm21)) << imm21;
364 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
365 static_cast<uint32_t>(rs) << kRsShift |
366 imm21;
367 Emit(encoding);
368 return encoding;
369 }
370
EmitI26(int opcode,uint32_t imm26)371 uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
372 CHECK(IsUint<26>(imm26)) << imm26;
373 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
374 Emit(encoding);
375 return encoding;
376 }
377
EmitFR(int opcode,int fmt,FRegister ft,FRegister fs,FRegister fd,int funct)378 uint32_t MipsAssembler::EmitFR(int opcode,
379 int fmt,
380 FRegister ft,
381 FRegister fs,
382 FRegister fd,
383 int funct) {
384 CHECK_NE(ft, kNoFRegister);
385 CHECK_NE(fs, kNoFRegister);
386 CHECK_NE(fd, kNoFRegister);
387 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
388 fmt << kFmtShift |
389 static_cast<uint32_t>(ft) << kFtShift |
390 static_cast<uint32_t>(fs) << kFsShift |
391 static_cast<uint32_t>(fd) << kFdShift |
392 funct;
393 Emit(encoding);
394 return encoding;
395 }
396
EmitFI(int opcode,int fmt,FRegister ft,uint16_t imm)397 uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
398 CHECK_NE(ft, kNoFRegister);
399 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
400 fmt << kFmtShift |
401 static_cast<uint32_t>(ft) << kFtShift |
402 imm;
403 Emit(encoding);
404 return encoding;
405 }
406
EmitMsa3R(int operation,int df,VectorRegister wt,VectorRegister ws,VectorRegister wd,int minor_opcode)407 uint32_t MipsAssembler::EmitMsa3R(int operation,
408 int df,
409 VectorRegister wt,
410 VectorRegister ws,
411 VectorRegister wd,
412 int minor_opcode) {
413 CHECK_NE(wt, kNoVectorRegister);
414 CHECK_NE(ws, kNoVectorRegister);
415 CHECK_NE(wd, kNoVectorRegister);
416 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
417 operation << kMsaOperationShift |
418 df << kDfShift |
419 static_cast<uint32_t>(wt) << kWtShift |
420 static_cast<uint32_t>(ws) << kWsShift |
421 static_cast<uint32_t>(wd) << kWdShift |
422 minor_opcode;
423 Emit(encoding);
424 return encoding;
425 }
426
EmitMsaBIT(int operation,int df_m,VectorRegister ws,VectorRegister wd,int minor_opcode)427 uint32_t MipsAssembler::EmitMsaBIT(int operation,
428 int df_m,
429 VectorRegister ws,
430 VectorRegister wd,
431 int minor_opcode) {
432 CHECK_NE(ws, kNoVectorRegister);
433 CHECK_NE(wd, kNoVectorRegister);
434 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
435 operation << kMsaOperationShift |
436 df_m << kDfMShift |
437 static_cast<uint32_t>(ws) << kWsShift |
438 static_cast<uint32_t>(wd) << kWdShift |
439 minor_opcode;
440 Emit(encoding);
441 return encoding;
442 }
443
EmitMsaELM(int operation,int df_n,VectorRegister ws,VectorRegister wd,int minor_opcode)444 uint32_t MipsAssembler::EmitMsaELM(int operation,
445 int df_n,
446 VectorRegister ws,
447 VectorRegister wd,
448 int minor_opcode) {
449 CHECK_NE(ws, kNoVectorRegister);
450 CHECK_NE(wd, kNoVectorRegister);
451 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
452 operation << kMsaELMOperationShift |
453 df_n << kDfNShift |
454 static_cast<uint32_t>(ws) << kWsShift |
455 static_cast<uint32_t>(wd) << kWdShift |
456 minor_opcode;
457 Emit(encoding);
458 return encoding;
459 }
460
EmitMsaMI10(int s10,Register rs,VectorRegister wd,int minor_opcode,int df)461 uint32_t MipsAssembler::EmitMsaMI10(int s10,
462 Register rs,
463 VectorRegister wd,
464 int minor_opcode,
465 int df) {
466 CHECK_NE(rs, kNoRegister);
467 CHECK_NE(wd, kNoVectorRegister);
468 CHECK(IsUint<10>(s10)) << s10;
469 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
470 s10 << kS10Shift |
471 static_cast<uint32_t>(rs) << kWsShift |
472 static_cast<uint32_t>(wd) << kWdShift |
473 minor_opcode << kS10MinorShift |
474 df;
475 Emit(encoding);
476 return encoding;
477 }
478
EmitMsaI10(int operation,int df,int i10,VectorRegister wd,int minor_opcode)479 uint32_t MipsAssembler::EmitMsaI10(int operation,
480 int df,
481 int i10,
482 VectorRegister wd,
483 int minor_opcode) {
484 CHECK_NE(wd, kNoVectorRegister);
485 CHECK(IsUint<10>(i10)) << i10;
486 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
487 operation << kMsaOperationShift |
488 df << kDfShift |
489 i10 << kI10Shift |
490 static_cast<uint32_t>(wd) << kWdShift |
491 minor_opcode;
492 Emit(encoding);
493 return encoding;
494 }
495
EmitMsa2R(int operation,int df,VectorRegister ws,VectorRegister wd,int minor_opcode)496 uint32_t MipsAssembler::EmitMsa2R(int operation,
497 int df,
498 VectorRegister ws,
499 VectorRegister wd,
500 int minor_opcode) {
501 CHECK_NE(ws, kNoVectorRegister);
502 CHECK_NE(wd, kNoVectorRegister);
503 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
504 operation << kMsa2ROperationShift |
505 df << kDf2RShift |
506 static_cast<uint32_t>(ws) << kWsShift |
507 static_cast<uint32_t>(wd) << kWdShift |
508 minor_opcode;
509 Emit(encoding);
510 return encoding;
511 }
512
EmitMsa2RF(int operation,int df,VectorRegister ws,VectorRegister wd,int minor_opcode)513 uint32_t MipsAssembler::EmitMsa2RF(int operation,
514 int df,
515 VectorRegister ws,
516 VectorRegister wd,
517 int minor_opcode) {
518 CHECK_NE(ws, kNoVectorRegister);
519 CHECK_NE(wd, kNoVectorRegister);
520 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
521 operation << kMsa2RFOperationShift |
522 df << kDf2RShift |
523 static_cast<uint32_t>(ws) << kWsShift |
524 static_cast<uint32_t>(wd) << kWdShift |
525 minor_opcode;
526 Emit(encoding);
527 return encoding;
528 }
529
Addu(Register rd,Register rs,Register rt)530 void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
531 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt);
532 }
533
Addiu(Register rt,Register rs,uint16_t imm16)534 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
535 DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs);
536 }
537
Subu(Register rd,Register rs,Register rt)538 void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
539 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt);
540 }
541
MultR2(Register rs,Register rt)542 void MipsAssembler::MultR2(Register rs, Register rt) {
543 CHECK(!IsR6());
544 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt);
545 }
546
MultuR2(Register rs,Register rt)547 void MipsAssembler::MultuR2(Register rs, Register rt) {
548 CHECK(!IsR6());
549 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt);
550 }
551
DivR2(Register rs,Register rt)552 void MipsAssembler::DivR2(Register rs, Register rt) {
553 CHECK(!IsR6());
554 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt);
555 }
556
DivuR2(Register rs,Register rt)557 void MipsAssembler::DivuR2(Register rs, Register rt) {
558 CHECK(!IsR6());
559 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt);
560 }
561
MulR2(Register rd,Register rs,Register rt)562 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
563 CHECK(!IsR6());
564 DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt);
565 }
566
DivR2(Register rd,Register rs,Register rt)567 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
568 CHECK(!IsR6());
569 DivR2(rs, rt);
570 Mflo(rd);
571 }
572
ModR2(Register rd,Register rs,Register rt)573 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
574 CHECK(!IsR6());
575 DivR2(rs, rt);
576 Mfhi(rd);
577 }
578
DivuR2(Register rd,Register rs,Register rt)579 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
580 CHECK(!IsR6());
581 DivuR2(rs, rt);
582 Mflo(rd);
583 }
584
ModuR2(Register rd,Register rs,Register rt)585 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
586 CHECK(!IsR6());
587 DivuR2(rs, rt);
588 Mfhi(rd);
589 }
590
MulR6(Register rd,Register rs,Register rt)591 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
592 CHECK(IsR6());
593 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt);
594 }
595
MuhR6(Register rd,Register rs,Register rt)596 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
597 CHECK(IsR6());
598 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt);
599 }
600
MuhuR6(Register rd,Register rs,Register rt)601 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
602 CHECK(IsR6());
603 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt);
604 }
605
DivR6(Register rd,Register rs,Register rt)606 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
607 CHECK(IsR6());
608 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt);
609 }
610
ModR6(Register rd,Register rs,Register rt)611 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
612 CHECK(IsR6());
613 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt);
614 }
615
DivuR6(Register rd,Register rs,Register rt)616 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
617 CHECK(IsR6());
618 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt);
619 }
620
ModuR6(Register rd,Register rs,Register rt)621 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
622 CHECK(IsR6());
623 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt);
624 }
625
And(Register rd,Register rs,Register rt)626 void MipsAssembler::And(Register rd, Register rs, Register rt) {
627 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt);
628 }
629
Andi(Register rt,Register rs,uint16_t imm16)630 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
631 DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs);
632 }
633
Or(Register rd,Register rs,Register rt)634 void MipsAssembler::Or(Register rd, Register rs, Register rt) {
635 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt);
636 }
637
Ori(Register rt,Register rs,uint16_t imm16)638 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
639 DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs);
640 }
641
Xor(Register rd,Register rs,Register rt)642 void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
643 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt);
644 }
645
Xori(Register rt,Register rs,uint16_t imm16)646 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
647 DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs);
648 }
649
Nor(Register rd,Register rs,Register rt)650 void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
651 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt);
652 }
653
Movz(Register rd,Register rs,Register rt)654 void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
655 CHECK(!IsR6());
656 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt);
657 }
658
Movn(Register rd,Register rs,Register rt)659 void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
660 CHECK(!IsR6());
661 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt);
662 }
663
Seleqz(Register rd,Register rs,Register rt)664 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
665 CHECK(IsR6());
666 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt);
667 }
668
Selnez(Register rd,Register rs,Register rt)669 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
670 CHECK(IsR6());
671 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt);
672 }
673
ClzR6(Register rd,Register rs)674 void MipsAssembler::ClzR6(Register rd, Register rs) {
675 CHECK(IsR6());
676 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs);
677 }
678
ClzR2(Register rd,Register rs)679 void MipsAssembler::ClzR2(Register rd, Register rs) {
680 CHECK(!IsR6());
681 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs);
682 }
683
CloR6(Register rd,Register rs)684 void MipsAssembler::CloR6(Register rd, Register rs) {
685 CHECK(IsR6());
686 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs);
687 }
688
CloR2(Register rd,Register rs)689 void MipsAssembler::CloR2(Register rd, Register rs) {
690 CHECK(!IsR6());
691 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs);
692 }
693
Seb(Register rd,Register rt)694 void MipsAssembler::Seb(Register rd, Register rt) {
695 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt);
696 }
697
Seh(Register rd,Register rt)698 void MipsAssembler::Seh(Register rd, Register rt) {
699 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt);
700 }
701
Wsbh(Register rd,Register rt)702 void MipsAssembler::Wsbh(Register rd, Register rt) {
703 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt);
704 }
705
Bitswap(Register rd,Register rt)706 void MipsAssembler::Bitswap(Register rd, Register rt) {
707 CHECK(IsR6());
708 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt);
709 }
710
Sll(Register rd,Register rt,int shamt)711 void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
712 CHECK(IsUint<5>(shamt)) << shamt;
713 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt);
714 }
715
Srl(Register rd,Register rt,int shamt)716 void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
717 CHECK(IsUint<5>(shamt)) << shamt;
718 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt);
719 }
720
Rotr(Register rd,Register rt,int shamt)721 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
722 CHECK(IsUint<5>(shamt)) << shamt;
723 DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt);
724 }
725
Sra(Register rd,Register rt,int shamt)726 void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
727 CHECK(IsUint<5>(shamt)) << shamt;
728 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt);
729 }
730
Sllv(Register rd,Register rt,Register rs)731 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
732 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt);
733 }
734
Srlv(Register rd,Register rt,Register rs)735 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
736 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt);
737 }
738
Rotrv(Register rd,Register rt,Register rs)739 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
740 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt);
741 }
742
Srav(Register rd,Register rt,Register rs)743 void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
744 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt);
745 }
746
Ext(Register rd,Register rt,int pos,int size)747 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
748 CHECK(IsUint<5>(pos)) << pos;
749 CHECK(0 < size && size <= 32) << size;
750 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
751 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt);
752 }
753
Ins(Register rd,Register rt,int pos,int size)754 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
755 CHECK(IsUint<5>(pos)) << pos;
756 CHECK(0 < size && size <= 32) << size;
757 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
758 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
759 }
760
Lsa(Register rd,Register rs,Register rt,int saPlusOne)761 void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
762 CHECK(IsR6() || HasMsa());
763 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
764 int sa = saPlusOne - 1;
765 DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
766 }
767
ShiftAndAdd(Register dst,Register src_idx,Register src_base,int shamt,Register tmp)768 void MipsAssembler::ShiftAndAdd(Register dst,
769 Register src_idx,
770 Register src_base,
771 int shamt,
772 Register tmp) {
773 CHECK(0 <= shamt && shamt <= 4) << shamt;
774 CHECK_NE(src_base, tmp);
775 if (shamt == TIMES_1) {
776 // Catch the special case where the shift amount is zero (0).
777 Addu(dst, src_base, src_idx);
778 } else if (IsR6() || HasMsa()) {
779 Lsa(dst, src_idx, src_base, shamt);
780 } else {
781 Sll(tmp, src_idx, shamt);
782 Addu(dst, src_base, tmp);
783 }
784 }
785
Lb(Register rt,Register rs,uint16_t imm16)786 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
787 DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
788 }
789
Lh(Register rt,Register rs,uint16_t imm16)790 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
791 DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs);
792 }
793
Lw(Register rt,Register rs,uint16_t imm16)794 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
795 DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs);
796 }
797
Lwl(Register rt,Register rs,uint16_t imm16)798 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
799 CHECK(!IsR6());
800 DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs);
801 }
802
Lwr(Register rt,Register rs,uint16_t imm16)803 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
804 CHECK(!IsR6());
805 DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs);
806 }
807
Lbu(Register rt,Register rs,uint16_t imm16)808 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
809 DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs);
810 }
811
Lhu(Register rt,Register rs,uint16_t imm16)812 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
813 DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs);
814 }
815
Lwpc(Register rs,uint32_t imm19)816 void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
817 CHECK(IsR6());
818 CHECK(IsUint<19>(imm19)) << imm19;
819 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19));
820 }
821
Lui(Register rt,uint16_t imm16)822 void MipsAssembler::Lui(Register rt, uint16_t imm16) {
823 DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO);
824 }
825
Aui(Register rt,Register rs,uint16_t imm16)826 void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
827 CHECK(IsR6());
828 DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs);
829 }
830
Sync(uint32_t stype)831 void MipsAssembler::Sync(uint32_t stype) {
832 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf));
833 }
834
Mfhi(Register rd)835 void MipsAssembler::Mfhi(Register rd) {
836 CHECK(!IsR6());
837 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO);
838 }
839
Mflo(Register rd)840 void MipsAssembler::Mflo(Register rd) {
841 CHECK(!IsR6());
842 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO);
843 }
844
Sb(Register rt,Register rs,uint16_t imm16)845 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
846 DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs);
847 }
848
Sh(Register rt,Register rs,uint16_t imm16)849 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
850 DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs);
851 }
852
Sw(Register rt,Register rs,uint16_t imm16)853 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
854 DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs);
855 }
856
Swl(Register rt,Register rs,uint16_t imm16)857 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
858 CHECK(!IsR6());
859 DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs);
860 }
861
Swr(Register rt,Register rs,uint16_t imm16)862 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
863 CHECK(!IsR6());
864 DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs);
865 }
866
LlR2(Register rt,Register base,int16_t imm16)867 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
868 CHECK(!IsR6());
869 DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base);
870 }
871
ScR2(Register rt,Register base,int16_t imm16)872 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
873 CHECK(!IsR6());
874 DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base);
875 }
876
LlR6(Register rt,Register base,int16_t imm9)877 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
878 CHECK(IsR6());
879 CHECK(IsInt<9>(imm9));
880 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base);
881 }
882
ScR6(Register rt,Register base,int16_t imm9)883 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
884 CHECK(IsR6());
885 CHECK(IsInt<9>(imm9));
886 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base);
887 }
888
Slt(Register rd,Register rs,Register rt)889 void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
890 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt);
891 }
892
Sltu(Register rd,Register rs,Register rt)893 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
894 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt);
895 }
896
Slti(Register rt,Register rs,uint16_t imm16)897 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
898 DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs);
899 }
900
Sltiu(Register rt,Register rs,uint16_t imm16)901 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
902 DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs);
903 }
904
B(uint16_t imm16)905 void MipsAssembler::B(uint16_t imm16) {
906 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16));
907 }
908
Bal(uint16_t imm16)909 void MipsAssembler::Bal(uint16_t imm16) {
910 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16));
911 }
912
Beq(Register rs,Register rt,uint16_t imm16)913 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
914 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16));
915 }
916
Bne(Register rs,Register rt,uint16_t imm16)917 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
918 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16));
919 }
920
Beqz(Register rt,uint16_t imm16)921 void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
922 Beq(ZERO, rt, imm16);
923 }
924
Bnez(Register rt,uint16_t imm16)925 void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
926 Bne(ZERO, rt, imm16);
927 }
928
Bltz(Register rt,uint16_t imm16)929 void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
930 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16));
931 }
932
Bgez(Register rt,uint16_t imm16)933 void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
934 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16));
935 }
936
Blez(Register rt,uint16_t imm16)937 void MipsAssembler::Blez(Register rt, uint16_t imm16) {
938 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16));
939 }
940
Bgtz(Register rt,uint16_t imm16)941 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
942 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16));
943 }
944
Bc1f(uint16_t imm16)945 void MipsAssembler::Bc1f(uint16_t imm16) {
946 Bc1f(0, imm16);
947 }
948
Bc1f(int cc,uint16_t imm16)949 void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
950 CHECK(!IsR6());
951 CHECK(IsUint<3>(cc)) << cc;
952 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16));
953 }
954
Bc1t(uint16_t imm16)955 void MipsAssembler::Bc1t(uint16_t imm16) {
956 Bc1t(0, imm16);
957 }
958
Bc1t(int cc,uint16_t imm16)959 void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
960 CHECK(!IsR6());
961 CHECK(IsUint<3>(cc)) << cc;
962 DsFsmInstrNop(EmitI(0x11,
963 static_cast<Register>(0x8),
964 static_cast<Register>((cc << 2) | 1),
965 imm16));
966 }
967
J(uint32_t addr26)968 void MipsAssembler::J(uint32_t addr26) {
969 DsFsmInstrNop(EmitI26(0x2, addr26));
970 }
971
Jal(uint32_t addr26)972 void MipsAssembler::Jal(uint32_t addr26) {
973 DsFsmInstrNop(EmitI26(0x3, addr26));
974 }
975
Jalr(Register rd,Register rs)976 void MipsAssembler::Jalr(Register rd, Register rs) {
977 uint32_t last_instruction = delay_slot_.instruction_;
978 bool exchange = (last_instruction != 0 &&
979 (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 &&
980 ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0);
981 if (exchange) {
982 // The last instruction cannot be used in a different delay slot,
983 // do not commit the label before it (if any).
984 DsFsmDropLabel();
985 }
986 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09));
987 if (exchange) {
988 // Exchange the last two instructions in the assembler buffer.
989 size_t size = buffer_.Size();
990 CHECK_GE(size, 2 * sizeof(uint32_t));
991 size_t pos1 = size - 2 * sizeof(uint32_t);
992 size_t pos2 = size - sizeof(uint32_t);
993 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
994 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
995 CHECK_EQ(instr1, last_instruction);
996 buffer_.Store<uint32_t>(pos1, instr2);
997 buffer_.Store<uint32_t>(pos2, instr1);
998 } else if (reordering_) {
999 Nop();
1000 }
1001 }
1002
Jalr(Register rs)1003 void MipsAssembler::Jalr(Register rs) {
1004 Jalr(RA, rs);
1005 }
1006
Jr(Register rs)1007 void MipsAssembler::Jr(Register rs) {
1008 Jalr(ZERO, rs);
1009 }
1010
Nal()1011 void MipsAssembler::Nal() {
1012 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0));
1013 }
1014
Auipc(Register rs,uint16_t imm16)1015 void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
1016 CHECK(IsR6());
1017 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16));
1018 }
1019
Addiupc(Register rs,uint32_t imm19)1020 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
1021 CHECK(IsR6());
1022 CHECK(IsUint<19>(imm19)) << imm19;
1023 DsFsmInstrNop(EmitI21(0x3B, rs, imm19));
1024 }
1025
Bc(uint32_t imm26)1026 void MipsAssembler::Bc(uint32_t imm26) {
1027 CHECK(IsR6());
1028 DsFsmInstrNop(EmitI26(0x32, imm26));
1029 }
1030
Balc(uint32_t imm26)1031 void MipsAssembler::Balc(uint32_t imm26) {
1032 CHECK(IsR6());
1033 DsFsmInstrNop(EmitI26(0x3A, imm26));
1034 }
1035
Jic(Register rt,uint16_t imm16)1036 void MipsAssembler::Jic(Register rt, uint16_t imm16) {
1037 CHECK(IsR6());
1038 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16));
1039 }
1040
Jialc(Register rt,uint16_t imm16)1041 void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
1042 CHECK(IsR6());
1043 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16));
1044 }
1045
Bltc(Register rs,Register rt,uint16_t imm16)1046 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
1047 CHECK(IsR6());
1048 CHECK_NE(rs, ZERO);
1049 CHECK_NE(rt, ZERO);
1050 CHECK_NE(rs, rt);
1051 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16));
1052 }
1053
Bltzc(Register rt,uint16_t imm16)1054 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
1055 CHECK(IsR6());
1056 CHECK_NE(rt, ZERO);
1057 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16));
1058 }
1059
Bgtzc(Register rt,uint16_t imm16)1060 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
1061 CHECK(IsR6());
1062 CHECK_NE(rt, ZERO);
1063 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16));
1064 }
1065
Bgec(Register rs,Register rt,uint16_t imm16)1066 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
1067 CHECK(IsR6());
1068 CHECK_NE(rs, ZERO);
1069 CHECK_NE(rt, ZERO);
1070 CHECK_NE(rs, rt);
1071 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16));
1072 }
1073
Bgezc(Register rt,uint16_t imm16)1074 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
1075 CHECK(IsR6());
1076 CHECK_NE(rt, ZERO);
1077 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16));
1078 }
1079
Blezc(Register rt,uint16_t imm16)1080 void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
1081 CHECK(IsR6());
1082 CHECK_NE(rt, ZERO);
1083 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16));
1084 }
1085
Bltuc(Register rs,Register rt,uint16_t imm16)1086 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
1087 CHECK(IsR6());
1088 CHECK_NE(rs, ZERO);
1089 CHECK_NE(rt, ZERO);
1090 CHECK_NE(rs, rt);
1091 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16));
1092 }
1093
Bgeuc(Register rs,Register rt,uint16_t imm16)1094 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
1095 CHECK(IsR6());
1096 CHECK_NE(rs, ZERO);
1097 CHECK_NE(rt, ZERO);
1098 CHECK_NE(rs, rt);
1099 DsFsmInstrNop(EmitI(0x6, rs, rt, imm16));
1100 }
1101
Beqc(Register rs,Register rt,uint16_t imm16)1102 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
1103 CHECK(IsR6());
1104 CHECK_NE(rs, ZERO);
1105 CHECK_NE(rt, ZERO);
1106 CHECK_NE(rs, rt);
1107 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16));
1108 }
1109
Bnec(Register rs,Register rt,uint16_t imm16)1110 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
1111 CHECK(IsR6());
1112 CHECK_NE(rs, ZERO);
1113 CHECK_NE(rt, ZERO);
1114 CHECK_NE(rs, rt);
1115 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16));
1116 }
1117
Beqzc(Register rs,uint32_t imm21)1118 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
1119 CHECK(IsR6());
1120 CHECK_NE(rs, ZERO);
1121 DsFsmInstrNop(EmitI21(0x36, rs, imm21));
1122 }
1123
Bnezc(Register rs,uint32_t imm21)1124 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
1125 CHECK(IsR6());
1126 CHECK_NE(rs, ZERO);
1127 DsFsmInstrNop(EmitI21(0x3E, rs, imm21));
1128 }
1129
Bc1eqz(FRegister ft,uint16_t imm16)1130 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
1131 CHECK(IsR6());
1132 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16));
1133 }
1134
Bc1nez(FRegister ft,uint16_t imm16)1135 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
1136 CHECK(IsR6());
1137 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16));
1138 }
1139
EmitBcondR2(BranchCondition cond,Register rs,Register rt,uint16_t imm16)1140 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
1141 switch (cond) {
1142 case kCondLTZ:
1143 CHECK_EQ(rt, ZERO);
1144 Bltz(rs, imm16);
1145 break;
1146 case kCondGEZ:
1147 CHECK_EQ(rt, ZERO);
1148 Bgez(rs, imm16);
1149 break;
1150 case kCondLEZ:
1151 CHECK_EQ(rt, ZERO);
1152 Blez(rs, imm16);
1153 break;
1154 case kCondGTZ:
1155 CHECK_EQ(rt, ZERO);
1156 Bgtz(rs, imm16);
1157 break;
1158 case kCondEQ:
1159 Beq(rs, rt, imm16);
1160 break;
1161 case kCondNE:
1162 Bne(rs, rt, imm16);
1163 break;
1164 case kCondEQZ:
1165 CHECK_EQ(rt, ZERO);
1166 Beqz(rs, imm16);
1167 break;
1168 case kCondNEZ:
1169 CHECK_EQ(rt, ZERO);
1170 Bnez(rs, imm16);
1171 break;
1172 case kCondF:
1173 CHECK_EQ(rt, ZERO);
1174 Bc1f(static_cast<int>(rs), imm16);
1175 break;
1176 case kCondT:
1177 CHECK_EQ(rt, ZERO);
1178 Bc1t(static_cast<int>(rs), imm16);
1179 break;
1180 case kCondLT:
1181 case kCondGE:
1182 case kCondLE:
1183 case kCondGT:
1184 case kCondLTU:
1185 case kCondGEU:
1186 case kUncond:
1187 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1188 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1189 LOG(FATAL) << "Unexpected branch condition " << cond;
1190 UNREACHABLE();
1191 }
1192 }
1193
EmitBcondR6(BranchCondition cond,Register rs,Register rt,uint32_t imm16_21)1194 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
1195 switch (cond) {
1196 case kCondLT:
1197 Bltc(rs, rt, imm16_21);
1198 break;
1199 case kCondGE:
1200 Bgec(rs, rt, imm16_21);
1201 break;
1202 case kCondLE:
1203 Bgec(rt, rs, imm16_21);
1204 break;
1205 case kCondGT:
1206 Bltc(rt, rs, imm16_21);
1207 break;
1208 case kCondLTZ:
1209 CHECK_EQ(rt, ZERO);
1210 Bltzc(rs, imm16_21);
1211 break;
1212 case kCondGEZ:
1213 CHECK_EQ(rt, ZERO);
1214 Bgezc(rs, imm16_21);
1215 break;
1216 case kCondLEZ:
1217 CHECK_EQ(rt, ZERO);
1218 Blezc(rs, imm16_21);
1219 break;
1220 case kCondGTZ:
1221 CHECK_EQ(rt, ZERO);
1222 Bgtzc(rs, imm16_21);
1223 break;
1224 case kCondEQ:
1225 Beqc(rs, rt, imm16_21);
1226 break;
1227 case kCondNE:
1228 Bnec(rs, rt, imm16_21);
1229 break;
1230 case kCondEQZ:
1231 CHECK_EQ(rt, ZERO);
1232 Beqzc(rs, imm16_21);
1233 break;
1234 case kCondNEZ:
1235 CHECK_EQ(rt, ZERO);
1236 Bnezc(rs, imm16_21);
1237 break;
1238 case kCondLTU:
1239 Bltuc(rs, rt, imm16_21);
1240 break;
1241 case kCondGEU:
1242 Bgeuc(rs, rt, imm16_21);
1243 break;
1244 case kCondF:
1245 CHECK_EQ(rt, ZERO);
1246 Bc1eqz(static_cast<FRegister>(rs), imm16_21);
1247 break;
1248 case kCondT:
1249 CHECK_EQ(rt, ZERO);
1250 Bc1nez(static_cast<FRegister>(rs), imm16_21);
1251 break;
1252 case kUncond:
1253 LOG(FATAL) << "Unexpected branch condition " << cond;
1254 UNREACHABLE();
1255 }
1256 }
1257
AddS(FRegister fd,FRegister fs,FRegister ft)1258 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
1259 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft);
1260 }
1261
SubS(FRegister fd,FRegister fs,FRegister ft)1262 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
1263 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft);
1264 }
1265
MulS(FRegister fd,FRegister fs,FRegister ft)1266 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
1267 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft);
1268 }
1269
DivS(FRegister fd,FRegister fs,FRegister ft)1270 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
1271 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft);
1272 }
1273
AddD(FRegister fd,FRegister fs,FRegister ft)1274 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
1275 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft);
1276 }
1277
SubD(FRegister fd,FRegister fs,FRegister ft)1278 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
1279 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft);
1280 }
1281
MulD(FRegister fd,FRegister fs,FRegister ft)1282 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
1283 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft);
1284 }
1285
DivD(FRegister fd,FRegister fs,FRegister ft)1286 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
1287 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft);
1288 }
1289
SqrtS(FRegister fd,FRegister fs)1290 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
1291 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
1292 }
1293
SqrtD(FRegister fd,FRegister fs)1294 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
1295 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
1296 }
1297
AbsS(FRegister fd,FRegister fs)1298 void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
1299 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
1300 }
1301
AbsD(FRegister fd,FRegister fs)1302 void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
1303 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
1304 }
1305
MovS(FRegister fd,FRegister fs)1306 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
1307 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
1308 }
1309
MovD(FRegister fd,FRegister fs)1310 void MipsAssembler::MovD(FRegister fd, FRegister fs) {
1311 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
1312 }
1313
NegS(FRegister fd,FRegister fs)1314 void MipsAssembler::NegS(FRegister fd, FRegister fs) {
1315 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
1316 }
1317
NegD(FRegister fd,FRegister fs)1318 void MipsAssembler::NegD(FRegister fd, FRegister fs) {
1319 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
1320 }
1321
CunS(FRegister fs,FRegister ft)1322 void MipsAssembler::CunS(FRegister fs, FRegister ft) {
1323 CunS(0, fs, ft);
1324 }
1325
CunS(int cc,FRegister fs,FRegister ft)1326 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
1327 CHECK(!IsR6());
1328 CHECK(IsUint<3>(cc)) << cc;
1329 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
1330 }
1331
CeqS(FRegister fs,FRegister ft)1332 void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
1333 CeqS(0, fs, ft);
1334 }
1335
CeqS(int cc,FRegister fs,FRegister ft)1336 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
1337 CHECK(!IsR6());
1338 CHECK(IsUint<3>(cc)) << cc;
1339 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
1340 }
1341
CueqS(FRegister fs,FRegister ft)1342 void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
1343 CueqS(0, fs, ft);
1344 }
1345
CueqS(int cc,FRegister fs,FRegister ft)1346 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
1347 CHECK(!IsR6());
1348 CHECK(IsUint<3>(cc)) << cc;
1349 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
1350 }
1351
ColtS(FRegister fs,FRegister ft)1352 void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
1353 ColtS(0, fs, ft);
1354 }
1355
ColtS(int cc,FRegister fs,FRegister ft)1356 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
1357 CHECK(!IsR6());
1358 CHECK(IsUint<3>(cc)) << cc;
1359 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
1360 }
1361
CultS(FRegister fs,FRegister ft)1362 void MipsAssembler::CultS(FRegister fs, FRegister ft) {
1363 CultS(0, fs, ft);
1364 }
1365
CultS(int cc,FRegister fs,FRegister ft)1366 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
1367 CHECK(!IsR6());
1368 CHECK(IsUint<3>(cc)) << cc;
1369 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
1370 }
1371
ColeS(FRegister fs,FRegister ft)1372 void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
1373 ColeS(0, fs, ft);
1374 }
1375
ColeS(int cc,FRegister fs,FRegister ft)1376 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
1377 CHECK(!IsR6());
1378 CHECK(IsUint<3>(cc)) << cc;
1379 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
1380 }
1381
CuleS(FRegister fs,FRegister ft)1382 void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
1383 CuleS(0, fs, ft);
1384 }
1385
CuleS(int cc,FRegister fs,FRegister ft)1386 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
1387 CHECK(!IsR6());
1388 CHECK(IsUint<3>(cc)) << cc;
1389 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
1390 }
1391
CunD(FRegister fs,FRegister ft)1392 void MipsAssembler::CunD(FRegister fs, FRegister ft) {
1393 CunD(0, fs, ft);
1394 }
1395
CunD(int cc,FRegister fs,FRegister ft)1396 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
1397 CHECK(!IsR6());
1398 CHECK(IsUint<3>(cc)) << cc;
1399 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
1400 }
1401
CeqD(FRegister fs,FRegister ft)1402 void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
1403 CeqD(0, fs, ft);
1404 }
1405
CeqD(int cc,FRegister fs,FRegister ft)1406 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
1407 CHECK(!IsR6());
1408 CHECK(IsUint<3>(cc)) << cc;
1409 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
1410 }
1411
CueqD(FRegister fs,FRegister ft)1412 void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
1413 CueqD(0, fs, ft);
1414 }
1415
CueqD(int cc,FRegister fs,FRegister ft)1416 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1417 CHECK(!IsR6());
1418 CHECK(IsUint<3>(cc)) << cc;
1419 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
1420 }
1421
ColtD(FRegister fs,FRegister ft)1422 void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1423 ColtD(0, fs, ft);
1424 }
1425
ColtD(int cc,FRegister fs,FRegister ft)1426 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1427 CHECK(!IsR6());
1428 CHECK(IsUint<3>(cc)) << cc;
1429 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
1430 }
1431
CultD(FRegister fs,FRegister ft)1432 void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1433 CultD(0, fs, ft);
1434 }
1435
CultD(int cc,FRegister fs,FRegister ft)1436 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1437 CHECK(!IsR6());
1438 CHECK(IsUint<3>(cc)) << cc;
1439 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
1440 }
1441
ColeD(FRegister fs,FRegister ft)1442 void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1443 ColeD(0, fs, ft);
1444 }
1445
ColeD(int cc,FRegister fs,FRegister ft)1446 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1447 CHECK(!IsR6());
1448 CHECK(IsUint<3>(cc)) << cc;
1449 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
1450 }
1451
CuleD(FRegister fs,FRegister ft)1452 void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1453 CuleD(0, fs, ft);
1454 }
1455
CuleD(int cc,FRegister fs,FRegister ft)1456 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1457 CHECK(!IsR6());
1458 CHECK(IsUint<3>(cc)) << cc;
1459 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
1460 }
1461
CmpUnS(FRegister fd,FRegister fs,FRegister ft)1462 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1463 CHECK(IsR6());
1464 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft);
1465 }
1466
CmpEqS(FRegister fd,FRegister fs,FRegister ft)1467 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1468 CHECK(IsR6());
1469 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft);
1470 }
1471
CmpUeqS(FRegister fd,FRegister fs,FRegister ft)1472 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1473 CHECK(IsR6());
1474 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft);
1475 }
1476
CmpLtS(FRegister fd,FRegister fs,FRegister ft)1477 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1478 CHECK(IsR6());
1479 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft);
1480 }
1481
CmpUltS(FRegister fd,FRegister fs,FRegister ft)1482 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1483 CHECK(IsR6());
1484 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft);
1485 }
1486
CmpLeS(FRegister fd,FRegister fs,FRegister ft)1487 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1488 CHECK(IsR6());
1489 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft);
1490 }
1491
CmpUleS(FRegister fd,FRegister fs,FRegister ft)1492 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1493 CHECK(IsR6());
1494 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft);
1495 }
1496
CmpOrS(FRegister fd,FRegister fs,FRegister ft)1497 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1498 CHECK(IsR6());
1499 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft);
1500 }
1501
CmpUneS(FRegister fd,FRegister fs,FRegister ft)1502 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1503 CHECK(IsR6());
1504 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft);
1505 }
1506
CmpNeS(FRegister fd,FRegister fs,FRegister ft)1507 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1508 CHECK(IsR6());
1509 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft);
1510 }
1511
CmpUnD(FRegister fd,FRegister fs,FRegister ft)1512 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1513 CHECK(IsR6());
1514 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft);
1515 }
1516
CmpEqD(FRegister fd,FRegister fs,FRegister ft)1517 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1518 CHECK(IsR6());
1519 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft);
1520 }
1521
CmpUeqD(FRegister fd,FRegister fs,FRegister ft)1522 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1523 CHECK(IsR6());
1524 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft);
1525 }
1526
CmpLtD(FRegister fd,FRegister fs,FRegister ft)1527 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1528 CHECK(IsR6());
1529 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft);
1530 }
1531
CmpUltD(FRegister fd,FRegister fs,FRegister ft)1532 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1533 CHECK(IsR6());
1534 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft);
1535 }
1536
CmpLeD(FRegister fd,FRegister fs,FRegister ft)1537 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1538 CHECK(IsR6());
1539 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft);
1540 }
1541
CmpUleD(FRegister fd,FRegister fs,FRegister ft)1542 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1543 CHECK(IsR6());
1544 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft);
1545 }
1546
CmpOrD(FRegister fd,FRegister fs,FRegister ft)1547 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1548 CHECK(IsR6());
1549 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft);
1550 }
1551
CmpUneD(FRegister fd,FRegister fs,FRegister ft)1552 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1553 CHECK(IsR6());
1554 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft);
1555 }
1556
CmpNeD(FRegister fd,FRegister fs,FRegister ft)1557 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1558 CHECK(IsR6());
1559 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft);
1560 }
1561
Movf(Register rd,Register rs,int cc)1562 void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1563 CHECK(!IsR6());
1564 CHECK(IsUint<3>(cc)) << cc;
1565 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc);
1566 }
1567
Movt(Register rd,Register rs,int cc)1568 void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1569 CHECK(!IsR6());
1570 CHECK(IsUint<3>(cc)) << cc;
1571 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc);
1572 }
1573
MovfS(FRegister fd,FRegister fs,int cc)1574 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1575 CHECK(!IsR6());
1576 CHECK(IsUint<3>(cc)) << cc;
1577 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
1578 }
1579
MovfD(FRegister fd,FRegister fs,int cc)1580 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1581 CHECK(!IsR6());
1582 CHECK(IsUint<3>(cc)) << cc;
1583 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
1584 }
1585
MovtS(FRegister fd,FRegister fs,int cc)1586 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1587 CHECK(!IsR6());
1588 CHECK(IsUint<3>(cc)) << cc;
1589 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1590 fd,
1591 fs,
1592 cc);
1593 }
1594
MovtD(FRegister fd,FRegister fs,int cc)1595 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1596 CHECK(!IsR6());
1597 CHECK(IsUint<3>(cc)) << cc;
1598 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1599 fd,
1600 fs,
1601 cc);
1602 }
1603
MovzS(FRegister fd,FRegister fs,Register rt)1604 void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
1605 CHECK(!IsR6());
1606 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1607 }
1608
MovzD(FRegister fd,FRegister fs,Register rt)1609 void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
1610 CHECK(!IsR6());
1611 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1612 }
1613
MovnS(FRegister fd,FRegister fs,Register rt)1614 void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
1615 CHECK(!IsR6());
1616 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1617 }
1618
MovnD(FRegister fd,FRegister fs,Register rt)1619 void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
1620 CHECK(!IsR6());
1621 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1622 }
1623
SelS(FRegister fd,FRegister fs,FRegister ft)1624 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1625 CHECK(IsR6());
1626 DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft);
1627 }
1628
SelD(FRegister fd,FRegister fs,FRegister ft)1629 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1630 CHECK(IsR6());
1631 DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft);
1632 }
1633
SeleqzS(FRegister fd,FRegister fs,FRegister ft)1634 void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
1635 CHECK(IsR6());
1636 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft);
1637 }
1638
SeleqzD(FRegister fd,FRegister fs,FRegister ft)1639 void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
1640 CHECK(IsR6());
1641 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft);
1642 }
1643
SelnezS(FRegister fd,FRegister fs,FRegister ft)1644 void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
1645 CHECK(IsR6());
1646 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft);
1647 }
1648
SelnezD(FRegister fd,FRegister fs,FRegister ft)1649 void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
1650 CHECK(IsR6());
1651 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft);
1652 }
1653
ClassS(FRegister fd,FRegister fs)1654 void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1655 CHECK(IsR6());
1656 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
1657 }
1658
ClassD(FRegister fd,FRegister fs)1659 void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1660 CHECK(IsR6());
1661 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
1662 }
1663
MinS(FRegister fd,FRegister fs,FRegister ft)1664 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1665 CHECK(IsR6());
1666 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft);
1667 }
1668
MinD(FRegister fd,FRegister fs,FRegister ft)1669 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1670 CHECK(IsR6());
1671 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft);
1672 }
1673
MaxS(FRegister fd,FRegister fs,FRegister ft)1674 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1675 CHECK(IsR6());
1676 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft);
1677 }
1678
MaxD(FRegister fd,FRegister fs,FRegister ft)1679 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1680 CHECK(IsR6());
1681 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft);
1682 }
1683
TruncLS(FRegister fd,FRegister fs)1684 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1685 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
1686 }
1687
TruncLD(FRegister fd,FRegister fs)1688 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1689 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
1690 }
1691
TruncWS(FRegister fd,FRegister fs)1692 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1693 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
1694 }
1695
TruncWD(FRegister fd,FRegister fs)1696 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1697 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
1698 }
1699
Cvtsw(FRegister fd,FRegister fs)1700 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1701 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1702 }
1703
Cvtdw(FRegister fd,FRegister fs)1704 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1705 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1706 }
1707
Cvtsd(FRegister fd,FRegister fs)1708 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1709 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1710 }
1711
Cvtds(FRegister fd,FRegister fs)1712 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1713 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1714 }
1715
Cvtsl(FRegister fd,FRegister fs)1716 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1717 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1718 }
1719
Cvtdl(FRegister fd,FRegister fs)1720 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1721 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1722 }
1723
FloorWS(FRegister fd,FRegister fs)1724 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1725 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
1726 }
1727
FloorWD(FRegister fd,FRegister fs)1728 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1729 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
1730 }
1731
Mfc1(Register rt,FRegister fs)1732 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
1733 DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1734 rt,
1735 fs);
1736 }
1737
Mtc1(Register rt,FRegister fs)1738 void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1739 DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1740 fs,
1741 rt);
1742 }
1743
Mfhc1(Register rt,FRegister fs)1744 void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1745 DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1746 rt,
1747 fs);
1748 }
1749
Mthc1(Register rt,FRegister fs)1750 void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1751 DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1752 fs,
1753 rt);
1754 }
1755
MoveFromFpuHigh(Register rt,FRegister fs)1756 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1757 if (Is32BitFPU()) {
1758 CHECK_EQ(fs % 2, 0) << fs;
1759 Mfc1(rt, static_cast<FRegister>(fs + 1));
1760 } else {
1761 Mfhc1(rt, fs);
1762 }
1763 }
1764
MoveToFpuHigh(Register rt,FRegister fs)1765 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1766 if (Is32BitFPU()) {
1767 CHECK_EQ(fs % 2, 0) << fs;
1768 Mtc1(rt, static_cast<FRegister>(fs + 1));
1769 } else {
1770 Mthc1(rt, fs);
1771 }
1772 }
1773
Lwc1(FRegister ft,Register rs,uint16_t imm16)1774 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
1775 DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs);
1776 }
1777
Ldc1(FRegister ft,Register rs,uint16_t imm16)1778 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1779 DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs);
1780 }
1781
Swc1(FRegister ft,Register rs,uint16_t imm16)1782 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
1783 DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs);
1784 }
1785
Sdc1(FRegister ft,Register rs,uint16_t imm16)1786 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1787 DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs);
1788 }
1789
Break()1790 void MipsAssembler::Break() {
1791 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD));
1792 }
1793
Nop()1794 void MipsAssembler::Nop() {
1795 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0));
1796 }
1797
NopIfNoReordering()1798 void MipsAssembler::NopIfNoReordering() {
1799 if (!reordering_) {
1800 Nop();
1801 }
1802 }
1803
Move(Register rd,Register rs)1804 void MipsAssembler::Move(Register rd, Register rs) {
1805 Or(rd, rs, ZERO);
1806 }
1807
Clear(Register rd)1808 void MipsAssembler::Clear(Register rd) {
1809 Move(rd, ZERO);
1810 }
1811
Not(Register rd,Register rs)1812 void MipsAssembler::Not(Register rd, Register rs) {
1813 Nor(rd, rs, ZERO);
1814 }
1815
Push(Register rs)1816 void MipsAssembler::Push(Register rs) {
1817 IncreaseFrameSize(kMipsWordSize);
1818 Sw(rs, SP, 0);
1819 }
1820
Pop(Register rd)1821 void MipsAssembler::Pop(Register rd) {
1822 Lw(rd, SP, 0);
1823 DecreaseFrameSize(kMipsWordSize);
1824 }
1825
PopAndReturn(Register rd,Register rt)1826 void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1827 bool reordering = SetReorder(false);
1828 Lw(rd, SP, 0);
1829 Jr(rt);
1830 DecreaseFrameSize(kMipsWordSize); // Single instruction in delay slot.
1831 SetReorder(reordering);
1832 }
1833
AndV(VectorRegister wd,VectorRegister ws,VectorRegister wt)1834 void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1835 CHECK(HasMsa());
1836 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e),
1837 static_cast<FRegister>(wd),
1838 static_cast<FRegister>(ws),
1839 static_cast<FRegister>(wt));
1840 }
1841
OrV(VectorRegister wd,VectorRegister ws,VectorRegister wt)1842 void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1843 CHECK(HasMsa());
1844 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e),
1845 static_cast<FRegister>(wd),
1846 static_cast<FRegister>(ws),
1847 static_cast<FRegister>(wt));
1848 }
1849
NorV(VectorRegister wd,VectorRegister ws,VectorRegister wt)1850 void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1851 CHECK(HasMsa());
1852 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e),
1853 static_cast<FRegister>(wd),
1854 static_cast<FRegister>(ws),
1855 static_cast<FRegister>(wt));
1856 }
1857
XorV(VectorRegister wd,VectorRegister ws,VectorRegister wt)1858 void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1859 CHECK(HasMsa());
1860 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e),
1861 static_cast<FRegister>(wd),
1862 static_cast<FRegister>(ws),
1863 static_cast<FRegister>(wt));
1864 }
1865
AddvB(VectorRegister wd,VectorRegister ws,VectorRegister wt)1866 void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1867 CHECK(HasMsa());
1868 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe),
1869 static_cast<FRegister>(wd),
1870 static_cast<FRegister>(ws),
1871 static_cast<FRegister>(wt));
1872 }
1873
AddvH(VectorRegister wd,VectorRegister ws,VectorRegister wt)1874 void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1875 CHECK(HasMsa());
1876 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe),
1877 static_cast<FRegister>(wd),
1878 static_cast<FRegister>(ws),
1879 static_cast<FRegister>(wt));
1880 }
1881
AddvW(VectorRegister wd,VectorRegister ws,VectorRegister wt)1882 void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1883 CHECK(HasMsa());
1884 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe),
1885 static_cast<FRegister>(wd),
1886 static_cast<FRegister>(ws),
1887 static_cast<FRegister>(wt));
1888 }
1889
AddvD(VectorRegister wd,VectorRegister ws,VectorRegister wt)1890 void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1891 CHECK(HasMsa());
1892 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe),
1893 static_cast<FRegister>(wd),
1894 static_cast<FRegister>(ws),
1895 static_cast<FRegister>(wt));
1896 }
1897
SubvB(VectorRegister wd,VectorRegister ws,VectorRegister wt)1898 void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1899 CHECK(HasMsa());
1900 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe),
1901 static_cast<FRegister>(wd),
1902 static_cast<FRegister>(ws),
1903 static_cast<FRegister>(wt));
1904 }
1905
SubvH(VectorRegister wd,VectorRegister ws,VectorRegister wt)1906 void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1907 CHECK(HasMsa());
1908 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe),
1909 static_cast<FRegister>(wd),
1910 static_cast<FRegister>(ws),
1911 static_cast<FRegister>(wt));
1912 }
1913
SubvW(VectorRegister wd,VectorRegister ws,VectorRegister wt)1914 void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1915 CHECK(HasMsa());
1916 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe),
1917 static_cast<FRegister>(wd),
1918 static_cast<FRegister>(ws),
1919 static_cast<FRegister>(wt));
1920 }
1921
SubvD(VectorRegister wd,VectorRegister ws,VectorRegister wt)1922 void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1923 CHECK(HasMsa());
1924 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe),
1925 static_cast<FRegister>(wd),
1926 static_cast<FRegister>(ws),
1927 static_cast<FRegister>(wt));
1928 }
1929
MulvB(VectorRegister wd,VectorRegister ws,VectorRegister wt)1930 void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1931 CHECK(HasMsa());
1932 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12),
1933 static_cast<FRegister>(wd),
1934 static_cast<FRegister>(ws),
1935 static_cast<FRegister>(wt));
1936 }
1937
MulvH(VectorRegister wd,VectorRegister ws,VectorRegister wt)1938 void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1939 CHECK(HasMsa());
1940 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12),
1941 static_cast<FRegister>(wd),
1942 static_cast<FRegister>(ws),
1943 static_cast<FRegister>(wt));
1944 }
1945
MulvW(VectorRegister wd,VectorRegister ws,VectorRegister wt)1946 void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1947 CHECK(HasMsa());
1948 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12),
1949 static_cast<FRegister>(wd),
1950 static_cast<FRegister>(ws),
1951 static_cast<FRegister>(wt));
1952 }
1953
MulvD(VectorRegister wd,VectorRegister ws,VectorRegister wt)1954 void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1955 CHECK(HasMsa());
1956 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12),
1957 static_cast<FRegister>(wd),
1958 static_cast<FRegister>(ws),
1959 static_cast<FRegister>(wt));
1960 }
1961
Div_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)1962 void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1963 CHECK(HasMsa());
1964 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12),
1965 static_cast<FRegister>(wd),
1966 static_cast<FRegister>(ws),
1967 static_cast<FRegister>(wt));
1968 }
1969
Div_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)1970 void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1971 CHECK(HasMsa());
1972 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12),
1973 static_cast<FRegister>(wd),
1974 static_cast<FRegister>(ws),
1975 static_cast<FRegister>(wt));
1976 }
1977
Div_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)1978 void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1979 CHECK(HasMsa());
1980 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12),
1981 static_cast<FRegister>(wd),
1982 static_cast<FRegister>(ws),
1983 static_cast<FRegister>(wt));
1984 }
1985
Div_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)1986 void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1987 CHECK(HasMsa());
1988 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12),
1989 static_cast<FRegister>(wd),
1990 static_cast<FRegister>(ws),
1991 static_cast<FRegister>(wt));
1992 }
1993
Div_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)1994 void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
1995 CHECK(HasMsa());
1996 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12),
1997 static_cast<FRegister>(wd),
1998 static_cast<FRegister>(ws),
1999 static_cast<FRegister>(wt));
2000 }
2001
Div_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2002 void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2003 CHECK(HasMsa());
2004 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12),
2005 static_cast<FRegister>(wd),
2006 static_cast<FRegister>(ws),
2007 static_cast<FRegister>(wt));
2008 }
2009
Div_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2010 void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2011 CHECK(HasMsa());
2012 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12),
2013 static_cast<FRegister>(wd),
2014 static_cast<FRegister>(ws),
2015 static_cast<FRegister>(wt));
2016 }
2017
Div_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2018 void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2019 CHECK(HasMsa());
2020 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12),
2021 static_cast<FRegister>(wd),
2022 static_cast<FRegister>(ws),
2023 static_cast<FRegister>(wt));
2024 }
2025
Mod_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2026 void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2027 CHECK(HasMsa());
2028 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12),
2029 static_cast<FRegister>(wd),
2030 static_cast<FRegister>(ws),
2031 static_cast<FRegister>(wt));
2032 }
2033
Mod_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2034 void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2035 CHECK(HasMsa());
2036 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12),
2037 static_cast<FRegister>(wd),
2038 static_cast<FRegister>(ws),
2039 static_cast<FRegister>(wt));
2040 }
2041
Mod_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2042 void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2043 CHECK(HasMsa());
2044 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12),
2045 static_cast<FRegister>(wd),
2046 static_cast<FRegister>(ws),
2047 static_cast<FRegister>(wt));
2048 }
2049
Mod_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2050 void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2051 CHECK(HasMsa());
2052 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12),
2053 static_cast<FRegister>(wd),
2054 static_cast<FRegister>(ws),
2055 static_cast<FRegister>(wt));
2056 }
2057
Mod_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2058 void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2059 CHECK(HasMsa());
2060 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12),
2061 static_cast<FRegister>(wd),
2062 static_cast<FRegister>(ws),
2063 static_cast<FRegister>(wt));
2064 }
2065
Mod_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2066 void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2067 CHECK(HasMsa());
2068 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12),
2069 static_cast<FRegister>(wd),
2070 static_cast<FRegister>(ws),
2071 static_cast<FRegister>(wt));
2072 }
2073
Mod_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2074 void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2075 CHECK(HasMsa());
2076 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12),
2077 static_cast<FRegister>(wd),
2078 static_cast<FRegister>(ws),
2079 static_cast<FRegister>(wt));
2080 }
2081
Mod_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2082 void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2083 CHECK(HasMsa());
2084 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12),
2085 static_cast<FRegister>(wd),
2086 static_cast<FRegister>(ws),
2087 static_cast<FRegister>(wt));
2088 }
2089
Add_aB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2090 void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2091 CHECK(HasMsa());
2092 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10),
2093 static_cast<FRegister>(wd),
2094 static_cast<FRegister>(ws),
2095 static_cast<FRegister>(wt));
2096 }
2097
Add_aH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2098 void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2099 CHECK(HasMsa());
2100 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10),
2101 static_cast<FRegister>(wd),
2102 static_cast<FRegister>(ws),
2103 static_cast<FRegister>(wt));
2104 }
2105
Add_aW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2106 void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2107 CHECK(HasMsa());
2108 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10),
2109 static_cast<FRegister>(wd),
2110 static_cast<FRegister>(ws),
2111 static_cast<FRegister>(wt));
2112 }
2113
Add_aD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2114 void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2115 CHECK(HasMsa());
2116 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10),
2117 static_cast<FRegister>(wd),
2118 static_cast<FRegister>(ws),
2119 static_cast<FRegister>(wt));
2120 }
2121
Ave_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2122 void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2123 CHECK(HasMsa());
2124 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10),
2125 static_cast<FRegister>(wd),
2126 static_cast<FRegister>(ws),
2127 static_cast<FRegister>(wt));
2128 }
2129
Ave_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2130 void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2131 CHECK(HasMsa());
2132 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10),
2133 static_cast<FRegister>(wd),
2134 static_cast<FRegister>(ws),
2135 static_cast<FRegister>(wt));
2136 }
2137
Ave_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2138 void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2139 CHECK(HasMsa());
2140 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10),
2141 static_cast<FRegister>(wd),
2142 static_cast<FRegister>(ws),
2143 static_cast<FRegister>(wt));
2144 }
2145
Ave_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2146 void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2147 CHECK(HasMsa());
2148 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10),
2149 static_cast<FRegister>(wd),
2150 static_cast<FRegister>(ws),
2151 static_cast<FRegister>(wt));
2152 }
2153
Ave_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2154 void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2155 CHECK(HasMsa());
2156 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10),
2157 static_cast<FRegister>(wd),
2158 static_cast<FRegister>(ws),
2159 static_cast<FRegister>(wt));
2160 }
2161
Ave_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2162 void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2163 CHECK(HasMsa());
2164 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10),
2165 static_cast<FRegister>(wd),
2166 static_cast<FRegister>(ws),
2167 static_cast<FRegister>(wt));
2168 }
2169
Ave_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2170 void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2171 CHECK(HasMsa());
2172 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10),
2173 static_cast<FRegister>(wd),
2174 static_cast<FRegister>(ws),
2175 static_cast<FRegister>(wt));
2176 }
2177
Ave_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2178 void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2179 CHECK(HasMsa());
2180 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10),
2181 static_cast<FRegister>(wd),
2182 static_cast<FRegister>(ws),
2183 static_cast<FRegister>(wt));
2184 }
2185
Aver_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2186 void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2187 CHECK(HasMsa());
2188 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10),
2189 static_cast<FRegister>(wd),
2190 static_cast<FRegister>(ws),
2191 static_cast<FRegister>(wt));
2192 }
2193
Aver_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2194 void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2195 CHECK(HasMsa());
2196 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10),
2197 static_cast<FRegister>(wd),
2198 static_cast<FRegister>(ws),
2199 static_cast<FRegister>(wt));
2200 }
2201
Aver_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2202 void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2203 CHECK(HasMsa());
2204 DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10),
2205 static_cast<FRegister>(wd),
2206 static_cast<FRegister>(ws),
2207 static_cast<FRegister>(wt));
2208 }
2209
Aver_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2210 void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2211 CHECK(HasMsa());
2212 DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10),
2213 static_cast<FRegister>(wd),
2214 static_cast<FRegister>(ws),
2215 static_cast<FRegister>(wt));
2216 }
2217
Aver_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2218 void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2219 CHECK(HasMsa());
2220 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10),
2221 static_cast<FRegister>(wd),
2222 static_cast<FRegister>(ws),
2223 static_cast<FRegister>(wt));
2224 }
2225
Aver_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2226 void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2227 CHECK(HasMsa());
2228 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10),
2229 static_cast<FRegister>(wd),
2230 static_cast<FRegister>(ws),
2231 static_cast<FRegister>(wt));
2232 }
2233
Aver_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2234 void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2235 CHECK(HasMsa());
2236 DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10),
2237 static_cast<FRegister>(wd),
2238 static_cast<FRegister>(ws),
2239 static_cast<FRegister>(wt));
2240 }
2241
Aver_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2242 void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2243 CHECK(HasMsa());
2244 DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10),
2245 static_cast<FRegister>(wd),
2246 static_cast<FRegister>(ws),
2247 static_cast<FRegister>(wt));
2248 }
2249
Max_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2250 void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2251 CHECK(HasMsa());
2252 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe),
2253 static_cast<FRegister>(wd),
2254 static_cast<FRegister>(ws),
2255 static_cast<FRegister>(wt));
2256 }
2257
Max_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2258 void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2259 CHECK(HasMsa());
2260 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe),
2261 static_cast<FRegister>(wd),
2262 static_cast<FRegister>(ws),
2263 static_cast<FRegister>(wt));
2264 }
2265
Max_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2266 void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2267 CHECK(HasMsa());
2268 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe),
2269 static_cast<FRegister>(wd),
2270 static_cast<FRegister>(ws),
2271 static_cast<FRegister>(wt));
2272 }
2273
Max_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2274 void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2275 CHECK(HasMsa());
2276 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe),
2277 static_cast<FRegister>(wd),
2278 static_cast<FRegister>(ws),
2279 static_cast<FRegister>(wt));
2280 }
2281
Max_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2282 void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2283 CHECK(HasMsa());
2284 DsFsmInstrFff(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe),
2285 static_cast<FRegister>(wd),
2286 static_cast<FRegister>(ws),
2287 static_cast<FRegister>(wt));
2288 }
2289
Max_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2290 void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2291 CHECK(HasMsa());
2292 DsFsmInstrFff(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe),
2293 static_cast<FRegister>(wd),
2294 static_cast<FRegister>(ws),
2295 static_cast<FRegister>(wt));
2296 }
2297
Max_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2298 void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2299 CHECK(HasMsa());
2300 DsFsmInstrFff(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe),
2301 static_cast<FRegister>(wd),
2302 static_cast<FRegister>(ws),
2303 static_cast<FRegister>(wt));
2304 }
2305
Max_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2306 void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2307 CHECK(HasMsa());
2308 DsFsmInstrFff(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe),
2309 static_cast<FRegister>(wd),
2310 static_cast<FRegister>(ws),
2311 static_cast<FRegister>(wt));
2312 }
2313
Min_sB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2314 void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2315 CHECK(HasMsa());
2316 DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe),
2317 static_cast<FRegister>(wd),
2318 static_cast<FRegister>(ws),
2319 static_cast<FRegister>(wt));
2320 }
2321
Min_sH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2322 void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2323 CHECK(HasMsa());
2324 DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe),
2325 static_cast<FRegister>(wd),
2326 static_cast<FRegister>(ws),
2327 static_cast<FRegister>(wt));
2328 }
2329
Min_sW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2330 void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2331 CHECK(HasMsa());
2332 DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe),
2333 static_cast<FRegister>(wd),
2334 static_cast<FRegister>(ws),
2335 static_cast<FRegister>(wt));
2336 }
2337
Min_sD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2338 void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2339 CHECK(HasMsa());
2340 DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe),
2341 static_cast<FRegister>(wd),
2342 static_cast<FRegister>(ws),
2343 static_cast<FRegister>(wt));
2344 }
2345
Min_uB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2346 void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2347 CHECK(HasMsa());
2348 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe),
2349 static_cast<FRegister>(wd),
2350 static_cast<FRegister>(ws),
2351 static_cast<FRegister>(wt));
2352 }
2353
Min_uH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2354 void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2355 CHECK(HasMsa());
2356 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe),
2357 static_cast<FRegister>(wd),
2358 static_cast<FRegister>(ws),
2359 static_cast<FRegister>(wt));
2360 }
2361
Min_uW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2362 void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2363 CHECK(HasMsa());
2364 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe),
2365 static_cast<FRegister>(wd),
2366 static_cast<FRegister>(ws),
2367 static_cast<FRegister>(wt));
2368 }
2369
Min_uD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2370 void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2371 CHECK(HasMsa());
2372 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe),
2373 static_cast<FRegister>(wd),
2374 static_cast<FRegister>(ws),
2375 static_cast<FRegister>(wt));
2376 }
2377
FaddW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2378 void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2379 CHECK(HasMsa());
2380 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b),
2381 static_cast<FRegister>(wd),
2382 static_cast<FRegister>(ws),
2383 static_cast<FRegister>(wt));
2384 }
2385
FaddD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2386 void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2387 CHECK(HasMsa());
2388 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b),
2389 static_cast<FRegister>(wd),
2390 static_cast<FRegister>(ws),
2391 static_cast<FRegister>(wt));
2392 }
2393
FsubW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2394 void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2395 CHECK(HasMsa());
2396 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b),
2397 static_cast<FRegister>(wd),
2398 static_cast<FRegister>(ws),
2399 static_cast<FRegister>(wt));
2400 }
2401
FsubD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2402 void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2403 CHECK(HasMsa());
2404 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b),
2405 static_cast<FRegister>(wd),
2406 static_cast<FRegister>(ws),
2407 static_cast<FRegister>(wt));
2408 }
2409
FmulW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2410 void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2411 CHECK(HasMsa());
2412 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b),
2413 static_cast<FRegister>(wd),
2414 static_cast<FRegister>(ws),
2415 static_cast<FRegister>(wt));
2416 }
2417
FmulD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2418 void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2419 CHECK(HasMsa());
2420 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b),
2421 static_cast<FRegister>(wd),
2422 static_cast<FRegister>(ws),
2423 static_cast<FRegister>(wt));
2424 }
2425
FdivW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2426 void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2427 CHECK(HasMsa());
2428 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b),
2429 static_cast<FRegister>(wd),
2430 static_cast<FRegister>(ws),
2431 static_cast<FRegister>(wt));
2432 }
2433
FdivD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2434 void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2435 CHECK(HasMsa());
2436 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b),
2437 static_cast<FRegister>(wd),
2438 static_cast<FRegister>(ws),
2439 static_cast<FRegister>(wt));
2440 }
2441
FmaxW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2442 void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2443 CHECK(HasMsa());
2444 DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b),
2445 static_cast<FRegister>(wd),
2446 static_cast<FRegister>(ws),
2447 static_cast<FRegister>(wt));
2448 }
2449
FmaxD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2450 void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2451 CHECK(HasMsa());
2452 DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b),
2453 static_cast<FRegister>(wd),
2454 static_cast<FRegister>(ws),
2455 static_cast<FRegister>(wt));
2456 }
2457
FminW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2458 void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2459 CHECK(HasMsa());
2460 DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b),
2461 static_cast<FRegister>(wd),
2462 static_cast<FRegister>(ws),
2463 static_cast<FRegister>(wt));
2464 }
2465
FminD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2466 void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2467 CHECK(HasMsa());
2468 DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b),
2469 static_cast<FRegister>(wd),
2470 static_cast<FRegister>(ws),
2471 static_cast<FRegister>(wt));
2472 }
2473
Ffint_sW(VectorRegister wd,VectorRegister ws)2474 void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
2475 CHECK(HasMsa());
2476 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e),
2477 static_cast<FRegister>(wd),
2478 static_cast<FRegister>(ws),
2479 static_cast<FRegister>(ws));
2480 }
2481
Ffint_sD(VectorRegister wd,VectorRegister ws)2482 void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
2483 CHECK(HasMsa());
2484 DsFsmInstrFff(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e),
2485 static_cast<FRegister>(wd),
2486 static_cast<FRegister>(ws),
2487 static_cast<FRegister>(ws));
2488 }
2489
Ftint_sW(VectorRegister wd,VectorRegister ws)2490 void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
2491 CHECK(HasMsa());
2492 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e),
2493 static_cast<FRegister>(wd),
2494 static_cast<FRegister>(ws),
2495 static_cast<FRegister>(ws));
2496 }
2497
Ftint_sD(VectorRegister wd,VectorRegister ws)2498 void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
2499 CHECK(HasMsa());
2500 DsFsmInstrFff(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e),
2501 static_cast<FRegister>(wd),
2502 static_cast<FRegister>(ws),
2503 static_cast<FRegister>(ws));
2504 }
2505
SllB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2506 void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2507 CHECK(HasMsa());
2508 DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd),
2509 static_cast<FRegister>(wd),
2510 static_cast<FRegister>(ws),
2511 static_cast<FRegister>(wt));
2512 }
2513
SllH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2514 void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2515 CHECK(HasMsa());
2516 DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd),
2517 static_cast<FRegister>(wd),
2518 static_cast<FRegister>(ws),
2519 static_cast<FRegister>(wt));
2520 }
2521
SllW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2522 void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2523 CHECK(HasMsa());
2524 DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd),
2525 static_cast<FRegister>(wd),
2526 static_cast<FRegister>(ws),
2527 static_cast<FRegister>(wt));
2528 }
2529
SllD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2530 void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2531 CHECK(HasMsa());
2532 DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd),
2533 static_cast<FRegister>(wd),
2534 static_cast<FRegister>(ws),
2535 static_cast<FRegister>(wt));
2536 }
2537
SraB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2538 void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2539 CHECK(HasMsa());
2540 DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd),
2541 static_cast<FRegister>(wd),
2542 static_cast<FRegister>(ws),
2543 static_cast<FRegister>(wt));
2544 }
2545
SraH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2546 void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2547 CHECK(HasMsa());
2548 DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd),
2549 static_cast<FRegister>(wd),
2550 static_cast<FRegister>(ws),
2551 static_cast<FRegister>(wt));
2552 }
2553
SraW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2554 void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2555 CHECK(HasMsa());
2556 DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd),
2557 static_cast<FRegister>(wd),
2558 static_cast<FRegister>(ws),
2559 static_cast<FRegister>(wt));
2560 }
2561
SraD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2562 void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2563 CHECK(HasMsa());
2564 DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd),
2565 static_cast<FRegister>(wd),
2566 static_cast<FRegister>(ws),
2567 static_cast<FRegister>(wt));
2568 }
2569
SrlB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2570 void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2571 CHECK(HasMsa());
2572 DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd),
2573 static_cast<FRegister>(wd),
2574 static_cast<FRegister>(ws),
2575 static_cast<FRegister>(wt));
2576 }
2577
SrlH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2578 void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2579 CHECK(HasMsa());
2580 DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd),
2581 static_cast<FRegister>(wd),
2582 static_cast<FRegister>(ws),
2583 static_cast<FRegister>(wt));
2584 }
2585
SrlW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2586 void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2587 CHECK(HasMsa());
2588 DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd),
2589 static_cast<FRegister>(wd),
2590 static_cast<FRegister>(ws),
2591 static_cast<FRegister>(wt));
2592 }
2593
SrlD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2594 void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2595 CHECK(HasMsa());
2596 DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd),
2597 static_cast<FRegister>(wd),
2598 static_cast<FRegister>(ws),
2599 static_cast<FRegister>(wt));
2600 }
2601
SlliB(VectorRegister wd,VectorRegister ws,int shamt3)2602 void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2603 CHECK(HasMsa());
2604 CHECK(IsUint<3>(shamt3)) << shamt3;
2605 DsFsmInstrFff(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2606 static_cast<FRegister>(wd),
2607 static_cast<FRegister>(ws),
2608 static_cast<FRegister>(ws));
2609 }
2610
SlliH(VectorRegister wd,VectorRegister ws,int shamt4)2611 void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2612 CHECK(HasMsa());
2613 CHECK(IsUint<4>(shamt4)) << shamt4;
2614 DsFsmInstrFff(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2615 static_cast<FRegister>(wd),
2616 static_cast<FRegister>(ws),
2617 static_cast<FRegister>(ws));
2618 }
2619
SlliW(VectorRegister wd,VectorRegister ws,int shamt5)2620 void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2621 CHECK(HasMsa());
2622 CHECK(IsUint<5>(shamt5)) << shamt5;
2623 DsFsmInstrFff(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2624 static_cast<FRegister>(wd),
2625 static_cast<FRegister>(ws),
2626 static_cast<FRegister>(ws));
2627 }
2628
SlliD(VectorRegister wd,VectorRegister ws,int shamt6)2629 void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2630 CHECK(HasMsa());
2631 CHECK(IsUint<6>(shamt6)) << shamt6;
2632 DsFsmInstrFff(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2633 static_cast<FRegister>(wd),
2634 static_cast<FRegister>(ws),
2635 static_cast<FRegister>(ws));
2636 }
2637
SraiB(VectorRegister wd,VectorRegister ws,int shamt3)2638 void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
2639 CHECK(HasMsa());
2640 CHECK(IsUint<3>(shamt3)) << shamt3;
2641 DsFsmInstrFff(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2642 static_cast<FRegister>(wd),
2643 static_cast<FRegister>(ws),
2644 static_cast<FRegister>(ws));
2645 }
2646
SraiH(VectorRegister wd,VectorRegister ws,int shamt4)2647 void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
2648 CHECK(HasMsa());
2649 CHECK(IsUint<4>(shamt4)) << shamt4;
2650 DsFsmInstrFff(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2651 static_cast<FRegister>(wd),
2652 static_cast<FRegister>(ws),
2653 static_cast<FRegister>(ws));
2654 }
2655
SraiW(VectorRegister wd,VectorRegister ws,int shamt5)2656 void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
2657 CHECK(HasMsa());
2658 CHECK(IsUint<5>(shamt5)) << shamt5;
2659 DsFsmInstrFff(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2660 static_cast<FRegister>(wd),
2661 static_cast<FRegister>(ws),
2662 static_cast<FRegister>(ws));
2663 }
2664
SraiD(VectorRegister wd,VectorRegister ws,int shamt6)2665 void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
2666 CHECK(HasMsa());
2667 CHECK(IsUint<6>(shamt6)) << shamt6;
2668 DsFsmInstrFff(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2669 static_cast<FRegister>(wd),
2670 static_cast<FRegister>(ws),
2671 static_cast<FRegister>(ws));
2672 }
2673
SrliB(VectorRegister wd,VectorRegister ws,int shamt3)2674 void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
2675 CHECK(HasMsa());
2676 CHECK(IsUint<3>(shamt3)) << shamt3;
2677 DsFsmInstrFff(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
2678 static_cast<FRegister>(wd),
2679 static_cast<FRegister>(ws),
2680 static_cast<FRegister>(ws));
2681 }
2682
SrliH(VectorRegister wd,VectorRegister ws,int shamt4)2683 void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
2684 CHECK(HasMsa());
2685 CHECK(IsUint<4>(shamt4)) << shamt4;
2686 DsFsmInstrFff(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
2687 static_cast<FRegister>(wd),
2688 static_cast<FRegister>(ws),
2689 static_cast<FRegister>(ws));
2690 }
2691
SrliW(VectorRegister wd,VectorRegister ws,int shamt5)2692 void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
2693 CHECK(HasMsa());
2694 CHECK(IsUint<5>(shamt5)) << shamt5;
2695 DsFsmInstrFff(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
2696 static_cast<FRegister>(wd),
2697 static_cast<FRegister>(ws),
2698 static_cast<FRegister>(ws));
2699 }
2700
SrliD(VectorRegister wd,VectorRegister ws,int shamt6)2701 void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
2702 CHECK(HasMsa());
2703 CHECK(IsUint<6>(shamt6)) << shamt6;
2704 DsFsmInstrFff(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
2705 static_cast<FRegister>(wd),
2706 static_cast<FRegister>(ws),
2707 static_cast<FRegister>(ws));
2708 }
2709
MoveV(VectorRegister wd,VectorRegister ws)2710 void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) {
2711 CHECK(HasMsa());
2712 DsFsmInstrFff(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19),
2713 static_cast<FRegister>(wd),
2714 static_cast<FRegister>(ws),
2715 static_cast<FRegister>(ws));
2716 }
2717
SplatiB(VectorRegister wd,VectorRegister ws,int n4)2718 void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
2719 CHECK(HasMsa());
2720 CHECK(IsUint<4>(n4)) << n4;
2721 DsFsmInstrFff(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19),
2722 static_cast<FRegister>(wd),
2723 static_cast<FRegister>(ws),
2724 static_cast<FRegister>(ws));
2725 }
2726
SplatiH(VectorRegister wd,VectorRegister ws,int n3)2727 void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
2728 CHECK(HasMsa());
2729 CHECK(IsUint<3>(n3)) << n3;
2730 DsFsmInstrFff(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19),
2731 static_cast<FRegister>(wd),
2732 static_cast<FRegister>(ws),
2733 static_cast<FRegister>(ws));
2734 }
2735
SplatiW(VectorRegister wd,VectorRegister ws,int n2)2736 void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
2737 CHECK(HasMsa());
2738 CHECK(IsUint<2>(n2)) << n2;
2739 DsFsmInstrFff(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19),
2740 static_cast<FRegister>(wd),
2741 static_cast<FRegister>(ws),
2742 static_cast<FRegister>(ws));
2743 }
2744
SplatiD(VectorRegister wd,VectorRegister ws,int n1)2745 void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
2746 CHECK(HasMsa());
2747 CHECK(IsUint<1>(n1)) << n1;
2748 DsFsmInstrFff(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19),
2749 static_cast<FRegister>(wd),
2750 static_cast<FRegister>(ws),
2751 static_cast<FRegister>(ws));
2752 }
2753
FillB(VectorRegister wd,Register rs)2754 void MipsAssembler::FillB(VectorRegister wd, Register rs) {
2755 CHECK(HasMsa());
2756 DsFsmInstrFr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e),
2757 static_cast<FRegister>(wd),
2758 rs);
2759 }
2760
FillH(VectorRegister wd,Register rs)2761 void MipsAssembler::FillH(VectorRegister wd, Register rs) {
2762 CHECK(HasMsa());
2763 DsFsmInstrFr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e),
2764 static_cast<FRegister>(wd),
2765 rs);
2766 }
2767
FillW(VectorRegister wd,Register rs)2768 void MipsAssembler::FillW(VectorRegister wd, Register rs) {
2769 CHECK(HasMsa());
2770 DsFsmInstrFr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e),
2771 static_cast<FRegister>(wd),
2772 rs);
2773 }
2774
LdiB(VectorRegister wd,int imm8)2775 void MipsAssembler::LdiB(VectorRegister wd, int imm8) {
2776 CHECK(HasMsa());
2777 CHECK(IsInt<8>(imm8)) << imm8;
2778 DsFsmInstrFr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7),
2779 static_cast<FRegister>(wd),
2780 ZERO);
2781 }
2782
LdiH(VectorRegister wd,int imm10)2783 void MipsAssembler::LdiH(VectorRegister wd, int imm10) {
2784 CHECK(HasMsa());
2785 CHECK(IsInt<10>(imm10)) << imm10;
2786 DsFsmInstrFr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7),
2787 static_cast<FRegister>(wd),
2788 ZERO);
2789 }
2790
LdiW(VectorRegister wd,int imm10)2791 void MipsAssembler::LdiW(VectorRegister wd, int imm10) {
2792 CHECK(HasMsa());
2793 CHECK(IsInt<10>(imm10)) << imm10;
2794 DsFsmInstrFr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7),
2795 static_cast<FRegister>(wd),
2796 ZERO);
2797 }
2798
LdiD(VectorRegister wd,int imm10)2799 void MipsAssembler::LdiD(VectorRegister wd, int imm10) {
2800 CHECK(HasMsa());
2801 CHECK(IsInt<10>(imm10)) << imm10;
2802 DsFsmInstrFr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7),
2803 static_cast<FRegister>(wd),
2804 ZERO);
2805 }
2806
LdB(VectorRegister wd,Register rs,int offset)2807 void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) {
2808 CHECK(HasMsa());
2809 CHECK(IsInt<10>(offset)) << offset;
2810 DsFsmInstrFr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0),
2811 static_cast<FRegister>(wd),
2812 rs);
2813 }
2814
LdH(VectorRegister wd,Register rs,int offset)2815 void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) {
2816 CHECK(HasMsa());
2817 CHECK(IsInt<11>(offset)) << offset;
2818 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2819 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1),
2820 static_cast<FRegister>(wd),
2821 rs);
2822 }
2823
LdW(VectorRegister wd,Register rs,int offset)2824 void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) {
2825 CHECK(HasMsa());
2826 CHECK(IsInt<12>(offset)) << offset;
2827 CHECK_ALIGNED(offset, kMipsWordSize);
2828 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2),
2829 static_cast<FRegister>(wd),
2830 rs);
2831 }
2832
LdD(VectorRegister wd,Register rs,int offset)2833 void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) {
2834 CHECK(HasMsa());
2835 CHECK(IsInt<13>(offset)) << offset;
2836 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2837 DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3),
2838 static_cast<FRegister>(wd),
2839 rs);
2840 }
2841
StB(VectorRegister wd,Register rs,int offset)2842 void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) {
2843 CHECK(HasMsa());
2844 CHECK(IsInt<10>(offset)) << offset;
2845 DsFsmInstrFR(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0), static_cast<FRegister>(wd), rs);
2846 }
2847
StH(VectorRegister wd,Register rs,int offset)2848 void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) {
2849 CHECK(HasMsa());
2850 CHECK(IsInt<11>(offset)) << offset;
2851 CHECK_ALIGNED(offset, kMipsHalfwordSize);
2852 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1),
2853 static_cast<FRegister>(wd),
2854 rs);
2855 }
2856
StW(VectorRegister wd,Register rs,int offset)2857 void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) {
2858 CHECK(HasMsa());
2859 CHECK(IsInt<12>(offset)) << offset;
2860 CHECK_ALIGNED(offset, kMipsWordSize);
2861 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2),
2862 static_cast<FRegister>(wd),
2863 rs);
2864 }
2865
StD(VectorRegister wd,Register rs,int offset)2866 void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
2867 CHECK(HasMsa());
2868 CHECK(IsInt<13>(offset)) << offset;
2869 CHECK_ALIGNED(offset, kMipsDoublewordSize);
2870 DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3),
2871 static_cast<FRegister>(wd),
2872 rs);
2873 }
2874
IlvrB(VectorRegister wd,VectorRegister ws,VectorRegister wt)2875 void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2876 CHECK(HasMsa());
2877 DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14),
2878 static_cast<FRegister>(wd),
2879 static_cast<FRegister>(ws),
2880 static_cast<FRegister>(wt));
2881 }
2882
IlvrH(VectorRegister wd,VectorRegister ws,VectorRegister wt)2883 void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2884 CHECK(HasMsa());
2885 DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14),
2886 static_cast<FRegister>(wd),
2887 static_cast<FRegister>(ws),
2888 static_cast<FRegister>(wt));
2889 }
2890
IlvrW(VectorRegister wd,VectorRegister ws,VectorRegister wt)2891 void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2892 CHECK(HasMsa());
2893 DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14),
2894 static_cast<FRegister>(wd),
2895 static_cast<FRegister>(ws),
2896 static_cast<FRegister>(wt));
2897 }
2898
IlvrD(VectorRegister wd,VectorRegister ws,VectorRegister wt)2899 void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
2900 CHECK(HasMsa());
2901 DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14),
2902 static_cast<FRegister>(wd),
2903 static_cast<FRegister>(ws),
2904 static_cast<FRegister>(wt));
2905 }
2906
ReplicateFPToVectorRegister(VectorRegister dst,FRegister src,bool is_double)2907 void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
2908 FRegister src,
2909 bool is_double) {
2910 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
2911 if (is_double) {
2912 SplatiD(dst, static_cast<VectorRegister>(src), 0);
2913 } else {
2914 SplatiW(dst, static_cast<VectorRegister>(src), 0);
2915 }
2916 }
2917
LoadConst32(Register rd,int32_t value)2918 void MipsAssembler::LoadConst32(Register rd, int32_t value) {
2919 if (IsUint<16>(value)) {
2920 // Use OR with (unsigned) immediate to encode 16b unsigned int.
2921 Ori(rd, ZERO, value);
2922 } else if (IsInt<16>(value)) {
2923 // Use ADD with (signed) immediate to encode 16b signed int.
2924 Addiu(rd, ZERO, value);
2925 } else {
2926 Lui(rd, High16Bits(value));
2927 if (value & 0xFFFF)
2928 Ori(rd, rd, Low16Bits(value));
2929 }
2930 }
2931
LoadConst64(Register reg_hi,Register reg_lo,int64_t value)2932 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
2933 uint32_t low = Low32Bits(value);
2934 uint32_t high = High32Bits(value);
2935 LoadConst32(reg_lo, low);
2936 if (high != low) {
2937 LoadConst32(reg_hi, high);
2938 } else {
2939 Move(reg_hi, reg_lo);
2940 }
2941 }
2942
LoadSConst32(FRegister r,int32_t value,Register temp)2943 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
2944 if (value == 0) {
2945 temp = ZERO;
2946 } else {
2947 LoadConst32(temp, value);
2948 }
2949 Mtc1(temp, r);
2950 }
2951
LoadDConst64(FRegister rd,int64_t value,Register temp)2952 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
2953 uint32_t low = Low32Bits(value);
2954 uint32_t high = High32Bits(value);
2955 if (low == 0) {
2956 Mtc1(ZERO, rd);
2957 } else {
2958 LoadConst32(temp, low);
2959 Mtc1(temp, rd);
2960 }
2961 if (high == 0) {
2962 MoveToFpuHigh(ZERO, rd);
2963 } else {
2964 LoadConst32(temp, high);
2965 MoveToFpuHigh(temp, rd);
2966 }
2967 }
2968
Addiu32(Register rt,Register rs,int32_t value,Register temp)2969 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
2970 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`.
2971 if (IsInt<16>(value)) {
2972 Addiu(rt, rs, value);
2973 } else if (IsR6()) {
2974 int16_t high = High16Bits(value);
2975 int16_t low = Low16Bits(value);
2976 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu.
2977 if (low != 0) {
2978 Aui(temp, rs, high);
2979 Addiu(rt, temp, low);
2980 } else {
2981 Aui(rt, rs, high);
2982 }
2983 } else {
2984 // Do not load the whole 32-bit `value` if it can be represented as
2985 // a sum of two 16-bit signed values. This can save an instruction.
2986 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
2987 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
2988 if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
2989 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
2990 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
2991 } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
2992 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
2993 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
2994 } else {
2995 // Now that all shorter options have been exhausted, load the full 32-bit value.
2996 LoadConst32(temp, value);
2997 Addu(rt, rs, temp);
2998 }
2999 }
3000 }
3001
InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,MipsAssembler::Branch::Type short_type,MipsAssembler::Branch::Type long_type)3002 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
3003 MipsAssembler::Branch::Type short_type,
3004 MipsAssembler::Branch::Type long_type) {
3005 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
3006 }
3007
InitializeType(Type initial_type,bool is_r6)3008 void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
3009 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
3010 if (is_r6) {
3011 // R6
3012 switch (initial_type) {
3013 case kLabel:
3014 CHECK(!IsResolved());
3015 type_ = kR6Label;
3016 break;
3017 case kLiteral:
3018 CHECK(!IsResolved());
3019 type_ = kR6Literal;
3020 break;
3021 case kCall:
3022 InitShortOrLong(offset_size, kR6Call, kR6LongCall);
3023 break;
3024 case kCondBranch:
3025 switch (condition_) {
3026 case kUncond:
3027 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
3028 break;
3029 case kCondEQZ:
3030 case kCondNEZ:
3031 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
3032 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
3033 break;
3034 default:
3035 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
3036 break;
3037 }
3038 break;
3039 default:
3040 LOG(FATAL) << "Unexpected branch type " << initial_type;
3041 UNREACHABLE();
3042 }
3043 } else {
3044 // R2
3045 switch (initial_type) {
3046 case kLabel:
3047 CHECK(!IsResolved());
3048 type_ = kLabel;
3049 break;
3050 case kLiteral:
3051 CHECK(!IsResolved());
3052 type_ = kLiteral;
3053 break;
3054 case kCall:
3055 InitShortOrLong(offset_size, kCall, kLongCall);
3056 break;
3057 case kCondBranch:
3058 switch (condition_) {
3059 case kUncond:
3060 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
3061 break;
3062 default:
3063 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
3064 break;
3065 }
3066 break;
3067 default:
3068 LOG(FATAL) << "Unexpected branch type " << initial_type;
3069 UNREACHABLE();
3070 }
3071 }
3072 old_type_ = type_;
3073 }
3074
IsNop(BranchCondition condition,Register lhs,Register rhs)3075 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
3076 switch (condition) {
3077 case kCondLT:
3078 case kCondGT:
3079 case kCondNE:
3080 case kCondLTU:
3081 return lhs == rhs;
3082 default:
3083 return false;
3084 }
3085 }
3086
IsUncond(BranchCondition condition,Register lhs,Register rhs)3087 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
3088 switch (condition) {
3089 case kUncond:
3090 return true;
3091 case kCondGE:
3092 case kCondLE:
3093 case kCondEQ:
3094 case kCondGEU:
3095 return lhs == rhs;
3096 default:
3097 return false;
3098 }
3099 }
3100
Branch(bool is_r6,uint32_t location,uint32_t target,bool is_call)3101 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call)
3102 : old_location_(location),
3103 location_(location),
3104 target_(target),
3105 lhs_reg_(0),
3106 rhs_reg_(0),
3107 condition_(kUncond),
3108 delayed_instruction_(kUnfilledDelaySlot) {
3109 InitializeType((is_call ? kCall : kCondBranch), is_r6);
3110 }
3111
Branch(bool is_r6,uint32_t location,uint32_t target,MipsAssembler::BranchCondition condition,Register lhs_reg,Register rhs_reg)3112 MipsAssembler::Branch::Branch(bool is_r6,
3113 uint32_t location,
3114 uint32_t target,
3115 MipsAssembler::BranchCondition condition,
3116 Register lhs_reg,
3117 Register rhs_reg)
3118 : old_location_(location),
3119 location_(location),
3120 target_(target),
3121 lhs_reg_(lhs_reg),
3122 rhs_reg_(rhs_reg),
3123 condition_(condition),
3124 delayed_instruction_(kUnfilledDelaySlot) {
3125 CHECK_NE(condition, kUncond);
3126 switch (condition) {
3127 case kCondLT:
3128 case kCondGE:
3129 case kCondLE:
3130 case kCondGT:
3131 case kCondLTU:
3132 case kCondGEU:
3133 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3134 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3135 // We leave this up to the caller.
3136 CHECK(is_r6);
3137 FALLTHROUGH_INTENDED;
3138 case kCondEQ:
3139 case kCondNE:
3140 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3141 // To compare with 0, use dedicated kCond*Z conditions.
3142 CHECK_NE(lhs_reg, ZERO);
3143 CHECK_NE(rhs_reg, ZERO);
3144 break;
3145 case kCondLTZ:
3146 case kCondGEZ:
3147 case kCondLEZ:
3148 case kCondGTZ:
3149 case kCondEQZ:
3150 case kCondNEZ:
3151 // Require registers other than 0 not only for R6, but also for R2 to catch errors.
3152 CHECK_NE(lhs_reg, ZERO);
3153 CHECK_EQ(rhs_reg, ZERO);
3154 break;
3155 case kCondF:
3156 case kCondT:
3157 CHECK_EQ(rhs_reg, ZERO);
3158 break;
3159 case kUncond:
3160 UNREACHABLE();
3161 }
3162 CHECK(!IsNop(condition, lhs_reg, rhs_reg));
3163 if (IsUncond(condition, lhs_reg, rhs_reg)) {
3164 // Branch condition is always true, make the branch unconditional.
3165 condition_ = kUncond;
3166 }
3167 InitializeType(kCondBranch, is_r6);
3168 }
3169
Branch(bool is_r6,uint32_t location,Register dest_reg,Register base_reg,Type label_or_literal_type)3170 MipsAssembler::Branch::Branch(bool is_r6,
3171 uint32_t location,
3172 Register dest_reg,
3173 Register base_reg,
3174 Type label_or_literal_type)
3175 : old_location_(location),
3176 location_(location),
3177 target_(kUnresolved),
3178 lhs_reg_(dest_reg),
3179 rhs_reg_(base_reg),
3180 condition_(kUncond),
3181 delayed_instruction_(kUnfilledDelaySlot) {
3182 CHECK_NE(dest_reg, ZERO);
3183 if (is_r6) {
3184 CHECK_EQ(base_reg, ZERO);
3185 } else {
3186 CHECK_NE(base_reg, ZERO);
3187 }
3188 InitializeType(label_or_literal_type, is_r6);
3189 }
3190
OppositeCondition(MipsAssembler::BranchCondition cond)3191 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
3192 MipsAssembler::BranchCondition cond) {
3193 switch (cond) {
3194 case kCondLT:
3195 return kCondGE;
3196 case kCondGE:
3197 return kCondLT;
3198 case kCondLE:
3199 return kCondGT;
3200 case kCondGT:
3201 return kCondLE;
3202 case kCondLTZ:
3203 return kCondGEZ;
3204 case kCondGEZ:
3205 return kCondLTZ;
3206 case kCondLEZ:
3207 return kCondGTZ;
3208 case kCondGTZ:
3209 return kCondLEZ;
3210 case kCondEQ:
3211 return kCondNE;
3212 case kCondNE:
3213 return kCondEQ;
3214 case kCondEQZ:
3215 return kCondNEZ;
3216 case kCondNEZ:
3217 return kCondEQZ;
3218 case kCondLTU:
3219 return kCondGEU;
3220 case kCondGEU:
3221 return kCondLTU;
3222 case kCondF:
3223 return kCondT;
3224 case kCondT:
3225 return kCondF;
3226 case kUncond:
3227 LOG(FATAL) << "Unexpected branch condition " << cond;
3228 }
3229 UNREACHABLE();
3230 }
3231
GetType() const3232 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
3233 return type_;
3234 }
3235
GetCondition() const3236 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
3237 return condition_;
3238 }
3239
GetLeftRegister() const3240 Register MipsAssembler::Branch::GetLeftRegister() const {
3241 return static_cast<Register>(lhs_reg_);
3242 }
3243
GetRightRegister() const3244 Register MipsAssembler::Branch::GetRightRegister() const {
3245 return static_cast<Register>(rhs_reg_);
3246 }
3247
GetTarget() const3248 uint32_t MipsAssembler::Branch::GetTarget() const {
3249 return target_;
3250 }
3251
GetLocation() const3252 uint32_t MipsAssembler::Branch::GetLocation() const {
3253 return location_;
3254 }
3255
GetOldLocation() const3256 uint32_t MipsAssembler::Branch::GetOldLocation() const {
3257 return old_location_;
3258 }
3259
GetPrecedingInstructionLength(Type type) const3260 uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const {
3261 // Short branches with delay slots always consist of two instructions, the branch
3262 // and the delay slot, irrespective of whether the delay slot is filled with a
3263 // useful instruction or not.
3264 // Long composite branches may have a length longer by one instruction than
3265 // specified in branch_info_[].length. This happens when an instruction is taken
3266 // to fill the short branch delay slot, but the branch eventually becomes long
3267 // and formally has no delay slot to fill. This instruction is placed at the
3268 // beginning of the long composite branch and this needs to be accounted for in
3269 // the branch length and the location of the offset encoded in the branch.
3270 switch (type) {
3271 case kLongUncondBranch:
3272 case kLongCondBranch:
3273 case kLongCall:
3274 case kR6LongCondBranch:
3275 return (delayed_instruction_ != kUnfilledDelaySlot &&
3276 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0;
3277 default:
3278 return 0;
3279 }
3280 }
3281
GetPrecedingInstructionSize(Type type) const3282 uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const {
3283 return GetPrecedingInstructionLength(type) * sizeof(uint32_t);
3284 }
3285
GetLength() const3286 uint32_t MipsAssembler::Branch::GetLength() const {
3287 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length;
3288 }
3289
GetOldLength() const3290 uint32_t MipsAssembler::Branch::GetOldLength() const {
3291 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length;
3292 }
3293
GetSize() const3294 uint32_t MipsAssembler::Branch::GetSize() const {
3295 return GetLength() * sizeof(uint32_t);
3296 }
3297
GetOldSize() const3298 uint32_t MipsAssembler::Branch::GetOldSize() const {
3299 return GetOldLength() * sizeof(uint32_t);
3300 }
3301
GetEndLocation() const3302 uint32_t MipsAssembler::Branch::GetEndLocation() const {
3303 return GetLocation() + GetSize();
3304 }
3305
GetOldEndLocation() const3306 uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
3307 return GetOldLocation() + GetOldSize();
3308 }
3309
IsLong() const3310 bool MipsAssembler::Branch::IsLong() const {
3311 switch (type_) {
3312 // R2 short branches.
3313 case kUncondBranch:
3314 case kCondBranch:
3315 case kCall:
3316 // R2 near label.
3317 case kLabel:
3318 // R2 near literal.
3319 case kLiteral:
3320 // R6 short branches.
3321 case kR6UncondBranch:
3322 case kR6CondBranch:
3323 case kR6Call:
3324 // R6 near label.
3325 case kR6Label:
3326 // R6 near literal.
3327 case kR6Literal:
3328 return false;
3329 // R2 long branches.
3330 case kLongUncondBranch:
3331 case kLongCondBranch:
3332 case kLongCall:
3333 // R2 far label.
3334 case kFarLabel:
3335 // R2 far literal.
3336 case kFarLiteral:
3337 // R6 long branches.
3338 case kR6LongUncondBranch:
3339 case kR6LongCondBranch:
3340 case kR6LongCall:
3341 // R6 far label.
3342 case kR6FarLabel:
3343 // R6 far literal.
3344 case kR6FarLiteral:
3345 return true;
3346 }
3347 UNREACHABLE();
3348 }
3349
IsResolved() const3350 bool MipsAssembler::Branch::IsResolved() const {
3351 return target_ != kUnresolved;
3352 }
3353
GetOffsetSize() const3354 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
3355 OffsetBits offset_size =
3356 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
3357 ? kOffset23
3358 : branch_info_[type_].offset_size;
3359 return offset_size;
3360 }
3361
GetOffsetSizeNeeded(uint32_t location,uint32_t target)3362 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
3363 uint32_t target) {
3364 // For unresolved targets assume the shortest encoding
3365 // (later it will be made longer if needed).
3366 if (target == kUnresolved)
3367 return kOffset16;
3368 int64_t distance = static_cast<int64_t>(target) - location;
3369 // To simplify calculations in composite branches consisting of multiple instructions
3370 // bump up the distance by a value larger than the max byte size of a composite branch.
3371 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
3372 if (IsInt<kOffset16>(distance))
3373 return kOffset16;
3374 else if (IsInt<kOffset18>(distance))
3375 return kOffset18;
3376 else if (IsInt<kOffset21>(distance))
3377 return kOffset21;
3378 else if (IsInt<kOffset23>(distance))
3379 return kOffset23;
3380 else if (IsInt<kOffset28>(distance))
3381 return kOffset28;
3382 return kOffset32;
3383 }
3384
Resolve(uint32_t target)3385 void MipsAssembler::Branch::Resolve(uint32_t target) {
3386 target_ = target;
3387 }
3388
Relocate(uint32_t expand_location,uint32_t delta)3389 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
3390 if (location_ > expand_location) {
3391 location_ += delta;
3392 }
3393 if (!IsResolved()) {
3394 return; // Don't know the target yet.
3395 }
3396 if (target_ > expand_location) {
3397 target_ += delta;
3398 }
3399 }
3400
PromoteToLong()3401 void MipsAssembler::Branch::PromoteToLong() {
3402 switch (type_) {
3403 // R2 short branches.
3404 case kUncondBranch:
3405 type_ = kLongUncondBranch;
3406 break;
3407 case kCondBranch:
3408 type_ = kLongCondBranch;
3409 break;
3410 case kCall:
3411 type_ = kLongCall;
3412 break;
3413 // R2 near label.
3414 case kLabel:
3415 type_ = kFarLabel;
3416 break;
3417 // R2 near literal.
3418 case kLiteral:
3419 type_ = kFarLiteral;
3420 break;
3421 // R6 short branches.
3422 case kR6UncondBranch:
3423 type_ = kR6LongUncondBranch;
3424 break;
3425 case kR6CondBranch:
3426 type_ = kR6LongCondBranch;
3427 break;
3428 case kR6Call:
3429 type_ = kR6LongCall;
3430 break;
3431 // R6 near label.
3432 case kR6Label:
3433 type_ = kR6FarLabel;
3434 break;
3435 // R6 near literal.
3436 case kR6Literal:
3437 type_ = kR6FarLiteral;
3438 break;
3439 default:
3440 // Note: 'type_' is already long.
3441 break;
3442 }
3443 CHECK(IsLong());
3444 }
3445
GetBranchLocationOrPcRelBase(const MipsAssembler::Branch * branch) const3446 uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
3447 switch (branch->GetType()) {
3448 case Branch::kLabel:
3449 case Branch::kFarLabel:
3450 case Branch::kLiteral:
3451 case Branch::kFarLiteral:
3452 return GetLabelLocation(&pc_rel_base_label_);
3453 default:
3454 return branch->GetLocation();
3455 }
3456 }
3457
PromoteIfNeeded(uint32_t location,uint32_t max_short_distance)3458 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
3459 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
3460 // `this->GetLocation()` for everything else.
3461 // If the branch is still unresolved or already long, nothing to do.
3462 if (IsLong() || !IsResolved()) {
3463 return 0;
3464 }
3465 // Promote the short branch to long if the offset size is too small
3466 // to hold the distance between location and target_.
3467 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) {
3468 PromoteToLong();
3469 uint32_t old_size = GetOldSize();
3470 uint32_t new_size = GetSize();
3471 CHECK_GT(new_size, old_size);
3472 return new_size - old_size;
3473 }
3474 // The following logic is for debugging/testing purposes.
3475 // Promote some short branches to long when it's not really required.
3476 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
3477 int64_t distance = static_cast<int64_t>(target_) - location;
3478 distance = (distance >= 0) ? distance : -distance;
3479 if (distance >= max_short_distance) {
3480 PromoteToLong();
3481 uint32_t old_size = GetOldSize();
3482 uint32_t new_size = GetSize();
3483 CHECK_GT(new_size, old_size);
3484 return new_size - old_size;
3485 }
3486 }
3487 return 0;
3488 }
3489
GetOffsetLocation() const3490 uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
3491 return location_ + GetPrecedingInstructionSize(type_) +
3492 branch_info_[type_].instr_offset * sizeof(uint32_t);
3493 }
3494
GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch * branch) const3495 uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
3496 switch (branch->GetType()) {
3497 case Branch::kLabel:
3498 case Branch::kFarLabel:
3499 case Branch::kLiteral:
3500 case Branch::kFarLiteral:
3501 return GetLabelLocation(&pc_rel_base_label_);
3502 default:
3503 return branch->GetOffsetLocation() +
3504 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
3505 }
3506 }
3507
GetOffset(uint32_t location) const3508 uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
3509 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
3510 // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)`
3511 // for everything else.
3512 CHECK(IsResolved());
3513 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
3514 // Calculate the byte distance between instructions and also account for
3515 // different PC-relative origins.
3516 uint32_t offset = target_ - location;
3517 // Prepare the offset for encoding into the instruction(s).
3518 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
3519 return offset;
3520 }
3521
GetBranch(uint32_t branch_id)3522 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
3523 CHECK_LT(branch_id, branches_.size());
3524 return &branches_[branch_id];
3525 }
3526
GetBranch(uint32_t branch_id) const3527 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
3528 CHECK_LT(branch_id, branches_.size());
3529 return &branches_[branch_id];
3530 }
3531
Bind(MipsLabel * label)3532 void MipsAssembler::Bind(MipsLabel* label) {
3533 CHECK(!label->IsBound());
3534 uint32_t bound_pc = buffer_.Size();
3535
3536 // Make the delay slot FSM aware of the new label.
3537 DsFsmLabel();
3538
3539 // Walk the list of branches referring to and preceding this label.
3540 // Store the previously unknown target addresses in them.
3541 while (label->IsLinked()) {
3542 uint32_t branch_id = label->Position();
3543 Branch* branch = GetBranch(branch_id);
3544 branch->Resolve(bound_pc);
3545
3546 uint32_t branch_location = branch->GetLocation();
3547 // Extract the location of the previous branch in the list (walking the list backwards;
3548 // the previous branch ID was stored in the space reserved for this branch).
3549 uint32_t prev = buffer_.Load<uint32_t>(branch_location);
3550
3551 // On to the previous branch in the list...
3552 label->position_ = prev;
3553 }
3554
3555 // Now make the label object contain its own location (relative to the end of the preceding
3556 // branch, if any; it will be used by the branches referring to and following this label).
3557 label->prev_branch_id_plus_one_ = branches_.size();
3558 if (label->prev_branch_id_plus_one_) {
3559 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
3560 const Branch* branch = GetBranch(branch_id);
3561 bound_pc -= branch->GetEndLocation();
3562 }
3563 label->BindTo(bound_pc);
3564 }
3565
GetLabelLocation(const MipsLabel * label) const3566 uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const {
3567 CHECK(label->IsBound());
3568 uint32_t target = label->Position();
3569 if (label->prev_branch_id_plus_one_) {
3570 // Get label location based on the branch preceding it.
3571 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
3572 const Branch* branch = GetBranch(branch_id);
3573 target += branch->GetEndLocation();
3574 }
3575 return target;
3576 }
3577
GetAdjustedPosition(uint32_t old_position)3578 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
3579 // We can reconstruct the adjustment by going through all the branches from the beginning
3580 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
3581 // with increasing old_position, we can use the data from last AdjustedPosition() to
3582 // continue where we left off and the whole loop should be O(m+n) where m is the number
3583 // of positions to adjust and n is the number of branches.
3584 if (old_position < last_old_position_) {
3585 last_position_adjustment_ = 0;
3586 last_old_position_ = 0;
3587 last_branch_id_ = 0;
3588 }
3589 while (last_branch_id_ != branches_.size()) {
3590 const Branch* branch = GetBranch(last_branch_id_);
3591 if (branch->GetLocation() >= old_position + last_position_adjustment_) {
3592 break;
3593 }
3594 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
3595 ++last_branch_id_;
3596 }
3597 last_old_position_ = old_position;
3598 return old_position + last_position_adjustment_;
3599 }
3600
BindPcRelBaseLabel()3601 void MipsAssembler::BindPcRelBaseLabel() {
3602 Bind(&pc_rel_base_label_);
3603 }
3604
GetPcRelBaseLabelLocation() const3605 uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const {
3606 return GetLabelLocation(&pc_rel_base_label_);
3607 }
3608
FinalizeLabeledBranch(MipsLabel * label)3609 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
3610 uint32_t length = branches_.back().GetLength();
3611 // Commit the last branch target label (if any).
3612 DsFsmCommitLabel();
3613 if (!label->IsBound()) {
3614 // Branch forward (to a following label), distance is unknown.
3615 // The first branch forward will contain 0, serving as the terminator of
3616 // the list of forward-reaching branches.
3617 Emit(label->position_);
3618 // Nothing for the delay slot (yet).
3619 DsFsmInstrNop(0);
3620 length--;
3621 // Now make the label object point to this branch
3622 // (this forms a linked list of branches preceding this label).
3623 uint32_t branch_id = branches_.size() - 1;
3624 label->LinkTo(branch_id);
3625 }
3626 // Reserve space for the branch.
3627 while (length--) {
3628 Nop();
3629 }
3630 }
3631
CanHaveDelayedInstruction(const DelaySlot & delay_slot) const3632 bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const {
3633 if (delay_slot.instruction_ == 0) {
3634 // NOP or no instruction for the delay slot.
3635 return false;
3636 }
3637 switch (type_) {
3638 // R2 unconditional branches.
3639 case kUncondBranch:
3640 case kLongUncondBranch:
3641 // There are no register interdependencies.
3642 return true;
3643
3644 // R2 calls.
3645 case kCall:
3646 case kLongCall:
3647 // Instructions depending on or modifying RA should not be moved into delay slots
3648 // of branches modifying RA.
3649 return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0;
3650
3651 // R2 conditional branches.
3652 case kCondBranch:
3653 case kLongCondBranch:
3654 switch (condition_) {
3655 // Branches with one GPR source.
3656 case kCondLTZ:
3657 case kCondGEZ:
3658 case kCondLEZ:
3659 case kCondGTZ:
3660 case kCondEQZ:
3661 case kCondNEZ:
3662 return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0;
3663
3664 // Branches with two GPR sources.
3665 case kCondEQ:
3666 case kCondNE:
3667 return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
3668
3669 // Branches with one FPU condition code source.
3670 case kCondF:
3671 case kCondT:
3672 return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0;
3673
3674 default:
3675 // We don't support synthetic R2 branches (preceded with slt[u]) at this level
3676 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
3677 LOG(FATAL) << "Unexpected branch condition " << condition_;
3678 UNREACHABLE();
3679 }
3680
3681 // R6 unconditional branches.
3682 case kR6UncondBranch:
3683 case kR6LongUncondBranch:
3684 // R6 calls.
3685 case kR6Call:
3686 case kR6LongCall:
3687 // There are no delay slots.
3688 return false;
3689
3690 // R6 conditional branches.
3691 case kR6CondBranch:
3692 case kR6LongCondBranch:
3693 switch (condition_) {
3694 // Branches with one FPU register source.
3695 case kCondF:
3696 case kCondT:
3697 return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0;
3698 // Others have a forbidden slot instead of a delay slot.
3699 default:
3700 return false;
3701 }
3702
3703 // Literals.
3704 default:
3705 LOG(FATAL) << "Unexpected branch type " << type_;
3706 UNREACHABLE();
3707 }
3708 }
3709
GetDelayedInstruction() const3710 uint32_t MipsAssembler::Branch::GetDelayedInstruction() const {
3711 return delayed_instruction_;
3712 }
3713
SetDelayedInstruction(uint32_t instruction)3714 void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction) {
3715 CHECK_NE(instruction, kUnfilledDelaySlot);
3716 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot);
3717 delayed_instruction_ = instruction;
3718 }
3719
DecrementLocations()3720 void MipsAssembler::Branch::DecrementLocations() {
3721 // We first create a branch object, which gets its type and locations initialized,
3722 // and then we check if the branch can actually have the preceding instruction moved
3723 // into its delay slot. If it can, the branch locations need to be decremented.
3724 //
3725 // We could make the check before creating the branch object and avoid the location
3726 // adjustment, but the check is cleaner when performed on an initialized branch
3727 // object.
3728 //
3729 // If the branch is backwards (to a previously bound label), reducing the locations
3730 // cannot cause a short branch to exceed its offset range because the offset reduces.
3731 // And this is not at all a problem for a long branch backwards.
3732 //
3733 // If the branch is forward (not linked to any label yet), reducing the locations
3734 // is harmless. The branch will be promoted to long if needed when the target is known.
3735 CHECK_EQ(location_, old_location_);
3736 CHECK_GE(old_location_, sizeof(uint32_t));
3737 old_location_ -= sizeof(uint32_t);
3738 location_ = old_location_;
3739 }
3740
MoveInstructionToDelaySlot(Branch & branch)3741 void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
3742 if (branch.CanHaveDelayedInstruction(delay_slot_)) {
3743 // The last instruction cannot be used in a different delay slot,
3744 // do not commit the label before it (if any).
3745 DsFsmDropLabel();
3746 // Remove the last emitted instruction.
3747 size_t size = buffer_.Size();
3748 CHECK_GE(size, sizeof(uint32_t));
3749 size -= sizeof(uint32_t);
3750 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_);
3751 buffer_.Resize(size);
3752 // Attach it to the branch and adjust the branch locations.
3753 branch.DecrementLocations();
3754 branch.SetDelayedInstruction(delay_slot_.instruction_);
3755 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) {
3756 // If reordefing is disabled, prevent absorption of the target instruction.
3757 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot);
3758 }
3759 }
3760
Buncond(MipsLabel * label)3761 void MipsAssembler::Buncond(MipsLabel* label) {
3762 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
3763 branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ false);
3764 MoveInstructionToDelaySlot(branches_.back());
3765 FinalizeLabeledBranch(label);
3766 }
3767
Bcond(MipsLabel * label,BranchCondition condition,Register lhs,Register rhs)3768 void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
3769 // If lhs = rhs, this can be a NOP.
3770 if (Branch::IsNop(condition, lhs, rhs)) {
3771 return;
3772 }
3773 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
3774 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
3775 MoveInstructionToDelaySlot(branches_.back());
3776 FinalizeLabeledBranch(label);
3777 }
3778
Call(MipsLabel * label)3779 void MipsAssembler::Call(MipsLabel* label) {
3780 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
3781 branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ true);
3782 MoveInstructionToDelaySlot(branches_.back());
3783 FinalizeLabeledBranch(label);
3784 }
3785
LoadLabelAddress(Register dest_reg,Register base_reg,MipsLabel * label)3786 void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
3787 // Label address loads are treated as pseudo branches since they require very similar handling.
3788 DCHECK(!label->IsBound());
3789 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
3790 FinalizeLabeledBranch(label);
3791 }
3792
NewLiteral(size_t size,const uint8_t * data)3793 Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
3794 DCHECK(size == 4u || size == 8u) << size;
3795 literals_.emplace_back(size, data);
3796 return &literals_.back();
3797 }
3798
LoadLiteral(Register dest_reg,Register base_reg,Literal * literal)3799 void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) {
3800 // Literal loads are treated as pseudo branches since they require very similar handling.
3801 DCHECK_EQ(literal->GetSize(), 4u);
3802 MipsLabel* label = literal->GetLabel();
3803 DCHECK(!label->IsBound());
3804 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
3805 FinalizeLabeledBranch(label);
3806 }
3807
CreateJumpTable(std::vector<MipsLabel * > && labels)3808 JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
3809 jump_tables_.emplace_back(std::move(labels));
3810 JumpTable* table = &jump_tables_.back();
3811 DCHECK(!table->GetLabel()->IsBound());
3812 return table;
3813 }
3814
EmitLiterals()3815 void MipsAssembler::EmitLiterals() {
3816 if (!literals_.empty()) {
3817 // We don't support byte and half-word literals.
3818 // TODO: proper alignment for 64-bit literals when they're implemented.
3819 for (Literal& literal : literals_) {
3820 MipsLabel* label = literal.GetLabel();
3821 Bind(label);
3822 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
3823 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
3824 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
3825 buffer_.Emit<uint8_t>(literal.GetData()[i]);
3826 }
3827 }
3828 }
3829 }
3830
ReserveJumpTableSpace()3831 void MipsAssembler::ReserveJumpTableSpace() {
3832 if (!jump_tables_.empty()) {
3833 for (JumpTable& table : jump_tables_) {
3834 MipsLabel* label = table.GetLabel();
3835 Bind(label);
3836
3837 // Bulk ensure capacity, as this may be large.
3838 size_t orig_size = buffer_.Size();
3839 size_t required_capacity = orig_size + table.GetSize();
3840 if (required_capacity > buffer_.Capacity()) {
3841 buffer_.ExtendCapacity(required_capacity);
3842 }
3843 #ifndef NDEBUG
3844 buffer_.has_ensured_capacity_ = true;
3845 #endif
3846
3847 // Fill the space with dummy data as the data is not final
3848 // until the branches have been promoted. And we shouldn't
3849 // be moving uninitialized data during branch promotion.
3850 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
3851 buffer_.Emit<uint32_t>(0x1abe1234u);
3852 }
3853
3854 #ifndef NDEBUG
3855 buffer_.has_ensured_capacity_ = false;
3856 #endif
3857 }
3858 }
3859 }
3860
EmitJumpTables()3861 void MipsAssembler::EmitJumpTables() {
3862 if (!jump_tables_.empty()) {
3863 CHECK(!overwriting_);
3864 // Switch from appending instructions at the end of the buffer to overwriting
3865 // existing instructions (here, jump tables) in the buffer.
3866 overwriting_ = true;
3867
3868 for (JumpTable& table : jump_tables_) {
3869 MipsLabel* table_label = table.GetLabel();
3870 uint32_t start = GetLabelLocation(table_label);
3871 overwrite_location_ = start;
3872
3873 for (MipsLabel* target : table.GetData()) {
3874 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
3875 // The table will contain target addresses relative to the table start.
3876 uint32_t offset = GetLabelLocation(target) - start;
3877 Emit(offset);
3878 }
3879 }
3880
3881 overwriting_ = false;
3882 }
3883 }
3884
PromoteBranches()3885 void MipsAssembler::PromoteBranches() {
3886 // Promote short branches to long as necessary.
3887 bool changed;
3888 do {
3889 changed = false;
3890 for (auto& branch : branches_) {
3891 CHECK(branch.IsResolved());
3892 uint32_t base = GetBranchLocationOrPcRelBase(&branch);
3893 uint32_t delta = branch.PromoteIfNeeded(base);
3894 // If this branch has been promoted and needs to expand in size,
3895 // relocate all branches by the expansion size.
3896 if (delta) {
3897 changed = true;
3898 uint32_t expand_location = branch.GetLocation();
3899 for (auto& branch2 : branches_) {
3900 branch2.Relocate(expand_location, delta);
3901 }
3902 }
3903 }
3904 } while (changed);
3905
3906 // Account for branch expansion by resizing the code buffer
3907 // and moving the code in it to its final location.
3908 size_t branch_count = branches_.size();
3909 if (branch_count > 0) {
3910 // Resize.
3911 Branch& last_branch = branches_[branch_count - 1];
3912 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
3913 uint32_t old_size = buffer_.Size();
3914 buffer_.Resize(old_size + size_delta);
3915 // Move the code residing between branch placeholders.
3916 uint32_t end = old_size;
3917 for (size_t i = branch_count; i > 0; ) {
3918 Branch& branch = branches_[--i];
3919 CHECK_GE(end, branch.GetOldEndLocation());
3920 uint32_t size = end - branch.GetOldEndLocation();
3921 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
3922 end = branch.GetOldLocation();
3923 }
3924 }
3925 }
3926
3927 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
3928 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
3929 // R2 short branches.
3930 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
3931 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
3932 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall
3933 // R2 near label.
3934 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel
3935 // R2 near literal.
3936 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral
3937 // R2 long branches.
3938 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch
3939 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch
3940 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall
3941 // R2 far label.
3942 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel
3943 // R2 far literal.
3944 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral
3945 // R6 short branches.
3946 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
3947 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
3948 // Exception: kOffset23 for beqzc/bnezc.
3949 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call
3950 // R6 near label.
3951 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label
3952 // R6 near literal.
3953 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal
3954 // R6 long branches.
3955 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch
3956 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch
3957 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall
3958 // R6 far label.
3959 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel
3960 // R6 far literal.
3961 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral
3962 };
3963
3964 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
EmitBranch(MipsAssembler::Branch * branch)3965 void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
3966 CHECK_EQ(overwriting_, true);
3967 overwrite_location_ = branch->GetLocation();
3968 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch));
3969 BranchCondition condition = branch->GetCondition();
3970 Register lhs = branch->GetLeftRegister();
3971 Register rhs = branch->GetRightRegister();
3972 uint32_t delayed_instruction = branch->GetDelayedInstruction();
3973 switch (branch->GetType()) {
3974 // R2 short branches.
3975 case Branch::kUncondBranch:
3976 if (delayed_instruction == Branch::kUnfillableDelaySlot) {
3977 // The branch was created when reordering was disabled, do not absorb the target
3978 // instruction.
3979 delayed_instruction = 0; // NOP.
3980 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) {
3981 // Try to absorb the target instruction into the delay slot.
3982 delayed_instruction = 0; // NOP.
3983 // Incrementing the signed 16-bit offset past the target instruction must not
3984 // cause overflow into the negative subrange, check for the max offset.
3985 if (offset != 0x7FFF) {
3986 uint32_t target = branch->GetTarget();
3987 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) {
3988 delayed_instruction = buffer_.Load<uint32_t>(target);
3989 offset++;
3990 }
3991 }
3992 }
3993 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
3994 B(offset);
3995 Emit(delayed_instruction);
3996 break;
3997 case Branch::kCondBranch:
3998 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
3999 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4000 delayed_instruction = 0; // NOP.
4001 }
4002 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4003 EmitBcondR2(condition, lhs, rhs, offset);
4004 Emit(delayed_instruction);
4005 break;
4006 case Branch::kCall:
4007 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4008 if (delayed_instruction == Branch::kUnfilledDelaySlot) {
4009 delayed_instruction = 0; // NOP.
4010 }
4011 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4012 Bal(offset);
4013 Emit(delayed_instruction);
4014 break;
4015
4016 // R2 near label.
4017 case Branch::kLabel:
4018 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4019 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4020 Addiu(lhs, rhs, offset);
4021 break;
4022 // R2 near literal.
4023 case Branch::kLiteral:
4024 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4025 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4026 Lw(lhs, rhs, offset);
4027 break;
4028
4029 // R2 long branches.
4030 case Branch::kLongUncondBranch:
4031 // To get the value of the PC register we need to use the NAL instruction.
4032 // NAL clobbers the RA register. However, RA must be preserved if the
4033 // method is compiled without the entry/exit sequences that would take care
4034 // of preserving RA (typically, leaf methods don't preserve RA explicitly).
4035 // So, we need to preserve RA in some temporary storage ourselves. The AT
4036 // register can't be used for this because we need it to load a constant
4037 // which will be added to the value that NAL stores in RA. And we can't
4038 // use T9 for this in the context of the JNI compiler, which uses it
4039 // as a scratch register (see InterproceduralScratchRegister()).
4040 // If we were to add a 32-bit constant to RA using two ADDIU instructions,
4041 // we'd also need to use the ROTR instruction, which requires no less than
4042 // MIPSR2.
4043 // Perhaps, we could use T8 or one of R2's multiplier/divider registers
4044 // (LO or HI) or even a floating-point register, but that doesn't seem
4045 // like a nice solution. We may want this to work on both R6 and pre-R6.
4046 // For now simply use the stack for RA. This should be OK since for the
4047 // vast majority of code a short PC-relative branch is sufficient.
4048 // TODO: can this be improved?
4049 // TODO: consider generation of a shorter sequence when we know that RA
4050 // is explicitly preserved by the method entry/exit code.
4051 if (delayed_instruction != Branch::kUnfilledDelaySlot &&
4052 delayed_instruction != Branch::kUnfillableDelaySlot) {
4053 Emit(delayed_instruction);
4054 }
4055 Push(RA);
4056 Nal();
4057 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4058 Lui(AT, High16Bits(offset));
4059 Ori(AT, AT, Low16Bits(offset));
4060 Addu(AT, AT, RA);
4061 Lw(RA, SP, 0);
4062 Jr(AT);
4063 DecreaseFrameSize(kMipsWordSize);
4064 break;
4065 case Branch::kLongCondBranch:
4066 // The comment on case 'Branch::kLongUncondBranch' applies here as well.
4067 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4068 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4069 Emit(delayed_instruction);
4070 }
4071 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
4072 // number of instructions skipped:
4073 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
4074 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
4075 Push(RA);
4076 Nal();
4077 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4078 Lui(AT, High16Bits(offset));
4079 Ori(AT, AT, Low16Bits(offset));
4080 Addu(AT, AT, RA);
4081 Lw(RA, SP, 0);
4082 Jr(AT);
4083 DecreaseFrameSize(kMipsWordSize);
4084 break;
4085 case Branch::kLongCall:
4086 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4087 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4088 Emit(delayed_instruction);
4089 }
4090 Nal();
4091 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4092 Lui(AT, High16Bits(offset));
4093 Ori(AT, AT, Low16Bits(offset));
4094 Addu(AT, AT, RA);
4095 Jalr(AT);
4096 Nop();
4097 break;
4098
4099 // R2 far label.
4100 case Branch::kFarLabel:
4101 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4102 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4103 Lui(AT, High16Bits(offset));
4104 Ori(AT, AT, Low16Bits(offset));
4105 Addu(lhs, AT, rhs);
4106 break;
4107 // R2 far literal.
4108 case Branch::kFarLiteral:
4109 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4110 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4111 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4112 Lui(AT, High16Bits(offset));
4113 Addu(AT, AT, rhs);
4114 Lw(lhs, AT, Low16Bits(offset));
4115 break;
4116
4117 // R6 short branches.
4118 case Branch::kR6UncondBranch:
4119 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4120 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4121 Bc(offset);
4122 break;
4123 case Branch::kR6CondBranch:
4124 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4125 EmitBcondR6(condition, lhs, rhs, offset);
4126 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4127 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4128 Emit(delayed_instruction);
4129 } else {
4130 // TODO: improve by filling the forbidden slot (IFF this is
4131 // a forbidden and not a delay slot).
4132 Nop();
4133 }
4134 break;
4135 case Branch::kR6Call:
4136 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4137 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4138 Balc(offset);
4139 break;
4140
4141 // R6 near label.
4142 case Branch::kR6Label:
4143 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4144 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4145 Addiupc(lhs, offset);
4146 break;
4147 // R6 near literal.
4148 case Branch::kR6Literal:
4149 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4150 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4151 Lwpc(lhs, offset);
4152 break;
4153
4154 // R6 long branches.
4155 case Branch::kR6LongUncondBranch:
4156 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4157 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4158 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4159 Auipc(AT, High16Bits(offset));
4160 Jic(AT, Low16Bits(offset));
4161 break;
4162 case Branch::kR6LongCondBranch:
4163 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
4164 if (delayed_instruction != Branch::kUnfilledDelaySlot) {
4165 Emit(delayed_instruction);
4166 }
4167 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
4168 offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
4169 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4170 Auipc(AT, High16Bits(offset));
4171 Jic(AT, Low16Bits(offset));
4172 break;
4173 case Branch::kR6LongCall:
4174 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4175 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc.
4176 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4177 Auipc(AT, High16Bits(offset));
4178 Jialc(AT, Low16Bits(offset));
4179 break;
4180
4181 // R6 far label.
4182 case Branch::kR6FarLabel:
4183 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4184 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu.
4185 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4186 Auipc(AT, High16Bits(offset));
4187 Addiu(lhs, AT, Low16Bits(offset));
4188 break;
4189 // R6 far literal.
4190 case Branch::kR6FarLiteral:
4191 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
4192 offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
4193 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
4194 Auipc(AT, High16Bits(offset));
4195 Lw(lhs, AT, Low16Bits(offset));
4196 break;
4197 }
4198 CHECK_EQ(overwrite_location_, branch->GetEndLocation());
4199 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
4200 }
4201
B(MipsLabel * label)4202 void MipsAssembler::B(MipsLabel* label) {
4203 Buncond(label);
4204 }
4205
Bal(MipsLabel * label)4206 void MipsAssembler::Bal(MipsLabel* label) {
4207 Call(label);
4208 }
4209
Beq(Register rs,Register rt,MipsLabel * label)4210 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
4211 Bcond(label, kCondEQ, rs, rt);
4212 }
4213
Bne(Register rs,Register rt,MipsLabel * label)4214 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
4215 Bcond(label, kCondNE, rs, rt);
4216 }
4217
Beqz(Register rt,MipsLabel * label)4218 void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
4219 Bcond(label, kCondEQZ, rt);
4220 }
4221
Bnez(Register rt,MipsLabel * label)4222 void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
4223 Bcond(label, kCondNEZ, rt);
4224 }
4225
Bltz(Register rt,MipsLabel * label)4226 void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
4227 Bcond(label, kCondLTZ, rt);
4228 }
4229
Bgez(Register rt,MipsLabel * label)4230 void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
4231 Bcond(label, kCondGEZ, rt);
4232 }
4233
Blez(Register rt,MipsLabel * label)4234 void MipsAssembler::Blez(Register rt, MipsLabel* label) {
4235 Bcond(label, kCondLEZ, rt);
4236 }
4237
Bgtz(Register rt,MipsLabel * label)4238 void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
4239 Bcond(label, kCondGTZ, rt);
4240 }
4241
CanExchangeWithSlt(Register rs,Register rt) const4242 bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
4243 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u]
4244 // instruction because either slt[u] depends on `rs` or `rt` or the following
4245 // conditional branch depends on AT set by slt[u].
4246 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
4247 // because slt[u] changes AT.
4248 return (delay_slot_.instruction_ != 0 &&
4249 (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
4250 (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0);
4251 }
4252
ExchangeWithSlt(const DelaySlot & forwarded_slot)4253 void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
4254 // Exchange the last two instructions in the assembler buffer.
4255 size_t size = buffer_.Size();
4256 CHECK_GE(size, 2 * sizeof(uint32_t));
4257 size_t pos1 = size - 2 * sizeof(uint32_t);
4258 size_t pos2 = size - sizeof(uint32_t);
4259 uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
4260 uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
4261 CHECK_EQ(instr1, forwarded_slot.instruction_);
4262 CHECK_EQ(instr2, delay_slot_.instruction_);
4263 buffer_.Store<uint32_t>(pos1, instr2);
4264 buffer_.Store<uint32_t>(pos2, instr1);
4265 // Set the current delay slot information to that of the last instruction
4266 // in the buffer.
4267 delay_slot_ = forwarded_slot;
4268 }
4269
GenerateSltForCondBranch(bool unsigned_slt,Register rs,Register rt)4270 void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) {
4271 // If possible, exchange the slt[u] instruction with the preceding instruction,
4272 // so it can fill the delay slot.
4273 DelaySlot forwarded_slot = delay_slot_;
4274 bool exchange = CanExchangeWithSlt(rs, rt);
4275 if (exchange) {
4276 // The last instruction cannot be used in a different delay slot,
4277 // do not commit the label before it (if any).
4278 DsFsmDropLabel();
4279 }
4280 if (unsigned_slt) {
4281 Sltu(AT, rs, rt);
4282 } else {
4283 Slt(AT, rs, rt);
4284 }
4285 if (exchange) {
4286 ExchangeWithSlt(forwarded_slot);
4287 }
4288 }
4289
Blt(Register rs,Register rt,MipsLabel * label)4290 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
4291 if (IsR6()) {
4292 Bcond(label, kCondLT, rs, rt);
4293 } else if (!Branch::IsNop(kCondLT, rs, rt)) {
4294 // Synthesize the instruction (not available on R2).
4295 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
4296 Bnez(AT, label);
4297 }
4298 }
4299
Bge(Register rs,Register rt,MipsLabel * label)4300 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
4301 if (IsR6()) {
4302 Bcond(label, kCondGE, rs, rt);
4303 } else if (Branch::IsUncond(kCondGE, rs, rt)) {
4304 B(label);
4305 } else {
4306 // Synthesize the instruction (not available on R2).
4307 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
4308 Beqz(AT, label);
4309 }
4310 }
4311
Bltu(Register rs,Register rt,MipsLabel * label)4312 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
4313 if (IsR6()) {
4314 Bcond(label, kCondLTU, rs, rt);
4315 } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
4316 // Synthesize the instruction (not available on R2).
4317 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
4318 Bnez(AT, label);
4319 }
4320 }
4321
Bgeu(Register rs,Register rt,MipsLabel * label)4322 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
4323 if (IsR6()) {
4324 Bcond(label, kCondGEU, rs, rt);
4325 } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
4326 B(label);
4327 } else {
4328 // Synthesize the instruction (not available on R2).
4329 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
4330 Beqz(AT, label);
4331 }
4332 }
4333
Bc1f(MipsLabel * label)4334 void MipsAssembler::Bc1f(MipsLabel* label) {
4335 Bc1f(0, label);
4336 }
4337
Bc1f(int cc,MipsLabel * label)4338 void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
4339 CHECK(IsUint<3>(cc)) << cc;
4340 Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
4341 }
4342
Bc1t(MipsLabel * label)4343 void MipsAssembler::Bc1t(MipsLabel* label) {
4344 Bc1t(0, label);
4345 }
4346
Bc1t(int cc,MipsLabel * label)4347 void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
4348 CHECK(IsUint<3>(cc)) << cc;
4349 Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
4350 }
4351
Bc1eqz(FRegister ft,MipsLabel * label)4352 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
4353 Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
4354 }
4355
Bc1nez(FRegister ft,MipsLabel * label)4356 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
4357 Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
4358 }
4359
AdjustBaseAndOffset(Register & base,int32_t & offset,bool is_doubleword,bool is_float)4360 void MipsAssembler::AdjustBaseAndOffset(Register& base,
4361 int32_t& offset,
4362 bool is_doubleword,
4363 bool is_float) {
4364 // This method is used to adjust the base register and offset pair
4365 // for a load/store when the offset doesn't fit into int16_t.
4366 // It is assumed that `base + offset` is sufficiently aligned for memory
4367 // operands that are machine word in size or smaller. For doubleword-sized
4368 // operands it's assumed that `base` is a multiple of 8, while `offset`
4369 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
4370 // and spilled variables on the stack accessed relative to the stack
4371 // pointer register).
4372 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
4373 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4374
4375 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
4376 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
4377
4378 // IsInt<16> must be passed a signed value, hence the static cast below.
4379 if (IsInt<16>(offset) &&
4380 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
4381 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
4382 return;
4383 }
4384
4385 // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
4386 uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
4387
4388 // Do not load the whole 32-bit `offset` if it can be represented as
4389 // a sum of two 16-bit signed offsets. This can save an instruction or two.
4390 // To simplify matters, only do this for a symmetric range of offsets from
4391 // about -64KB to about +64KB, allowing further addition of 4 when accessing
4392 // 64-bit variables with two 32-bit accesses.
4393 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8.
4394 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4395 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4396 Addiu(AT, base, kMinOffsetForSimpleAdjustment);
4397 offset -= kMinOffsetForSimpleAdjustment;
4398 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4399 Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
4400 offset += kMinOffsetForSimpleAdjustment;
4401 } else if (IsR6()) {
4402 // On R6 take advantage of the aui instruction, e.g.:
4403 // aui AT, base, offset_high
4404 // lw reg_lo, offset_low(AT)
4405 // lw reg_hi, (offset_low+4)(AT)
4406 // or when offset_low+4 overflows int16_t:
4407 // aui AT, base, offset_high
4408 // addiu AT, AT, 8
4409 // lw reg_lo, (offset_low-8)(AT)
4410 // lw reg_hi, (offset_low-4)(AT)
4411 int16_t offset_high = High16Bits(offset);
4412 int16_t offset_low = Low16Bits(offset);
4413 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store.
4414 Aui(AT, base, offset_high);
4415 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
4416 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
4417 Addiu(AT, AT, kMipsDoublewordSize);
4418 offset_low -= kMipsDoublewordSize;
4419 }
4420 offset = offset_low;
4421 } else {
4422 // Do not load the whole 32-bit `offset` if it can be represented as
4423 // a sum of three 16-bit signed offsets. This can save an instruction.
4424 // To simplify matters, only do this for a symmetric range of offsets from
4425 // about -96KB to about +96KB, allowing further addition of 4 when accessing
4426 // 64-bit variables with two 32-bit accesses.
4427 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
4428 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
4429 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4430 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
4431 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
4432 offset -= kMinOffsetForMediumAdjustment;
4433 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4434 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
4435 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
4436 offset += kMinOffsetForMediumAdjustment;
4437 } else {
4438 // Now that all shorter options have been exhausted, load the full 32-bit offset.
4439 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
4440 LoadConst32(AT, loaded_offset);
4441 Addu(AT, AT, base);
4442 offset -= loaded_offset;
4443 }
4444 }
4445 base = AT;
4446
4447 CHECK(IsInt<16>(offset));
4448 if (two_accesses) {
4449 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
4450 }
4451 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
4452 }
4453
AdjustBaseOffsetAndElementSizeShift(Register & base,int32_t & offset,int & element_size_shift)4454 void MipsAssembler::AdjustBaseOffsetAndElementSizeShift(Register& base,
4455 int32_t& offset,
4456 int& element_size_shift) {
4457 // This method is used to adjust the base register, offset and element_size_shift
4458 // for a vector load/store when the offset doesn't fit into allowed number of bits.
4459 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum
4460 // offset is dependant on the size of the data format df (10-bit offsets for ld.b,
4461 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d).
4462 // If element_size_shift is non-negative at entry, it won't be changed, but offset
4463 // will be checked for appropriate alignment. If negative at entry, it will be
4464 // adjusted based on offset for maximum fit.
4465 // It's assumed that `base` is a multiple of 8.
4466 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`.
4467
4468 if (element_size_shift >= 0) {
4469 CHECK_LE(element_size_shift, TIMES_8);
4470 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4471 } else if (IsAligned<kMipsDoublewordSize>(offset)) {
4472 element_size_shift = TIMES_8;
4473 } else if (IsAligned<kMipsWordSize>(offset)) {
4474 element_size_shift = TIMES_4;
4475 } else if (IsAligned<kMipsHalfwordSize>(offset)) {
4476 element_size_shift = TIMES_2;
4477 } else {
4478 element_size_shift = TIMES_1;
4479 }
4480
4481 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df
4482 // will take.
4483 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits.
4484 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits.
4485 if (low == offset) {
4486 return; // `offset` fits into ld.df/st.df.
4487 }
4488
4489 // First, see if `offset` can be represented as a sum of two or three signed offsets.
4490 // This can save an instruction or two.
4491
4492 // Max int16_t that's a multiple of element size.
4493 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift);
4494 // Max ld.df/st.df offset that's a multiple of element size.
4495 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift;
4496 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset;
4497 const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment;
4498 const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset;
4499
4500 if (IsInt<16>(offset)) {
4501 Addiu(AT, base, offset);
4502 offset = 0;
4503 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
4504 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4505 offset -= kMaxDeltaForSimpleAdjustment;
4506 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
4507 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4508 offset += kMaxDeltaForSimpleAdjustment;
4509 } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
4510 Addiu(AT, base, kMaxDeltaForSimpleAdjustment);
4511 if (offset <= kMinOffsetForMediumAdjustment) {
4512 Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment);
4513 offset = 0;
4514 } else {
4515 Addiu(AT, AT, kMaxDeltaForSimpleAdjustment);
4516 offset -= kMinOffsetForMediumAdjustment;
4517 }
4518 } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
4519 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment);
4520 if (-kMinOffsetForMediumAdjustment <= offset) {
4521 Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment);
4522 offset = 0;
4523 } else {
4524 Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment);
4525 offset += kMinOffsetForMediumAdjustment;
4526 }
4527 } else {
4528 // 16-bit or smaller parts of `offset`:
4529 // |31 hi 16|15 mid 13-10|12-9 low 0|
4530 //
4531 // Instructions that supply each part as a signed integer addend:
4532 // |aui |addiu |ld.df/st.df |
4533 uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset`
4534 // (accounts for sign of `low`).
4535 tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu.
4536 int16_t mid = Low16Bits(tmp);
4537 int16_t hi = High16Bits(tmp);
4538 if (IsR6()) {
4539 Aui(AT, base, hi);
4540 } else {
4541 Lui(AT, hi);
4542 Addu(AT, AT, base);
4543 }
4544 if (mid != 0) {
4545 Addiu(AT, AT, mid);
4546 }
4547 offset = low;
4548 }
4549 base = AT;
4550 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift);
4551 CHECK(IsInt<10>(offset >> element_size_shift));
4552 }
4553
LoadFromOffset(LoadOperandType type,Register reg,Register base,int32_t offset)4554 void MipsAssembler::LoadFromOffset(LoadOperandType type,
4555 Register reg,
4556 Register base,
4557 int32_t offset) {
4558 LoadFromOffset<>(type, reg, base, offset);
4559 }
4560
LoadSFromOffset(FRegister reg,Register base,int32_t offset)4561 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
4562 LoadSFromOffset<>(reg, base, offset);
4563 }
4564
LoadDFromOffset(FRegister reg,Register base,int32_t offset)4565 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
4566 LoadDFromOffset<>(reg, base, offset);
4567 }
4568
LoadQFromOffset(FRegister reg,Register base,int32_t offset)4569 void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) {
4570 LoadQFromOffset<>(reg, base, offset);
4571 }
4572
EmitLoad(ManagedRegister m_dst,Register src_register,int32_t src_offset,size_t size)4573 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
4574 size_t size) {
4575 MipsManagedRegister dst = m_dst.AsMips();
4576 if (dst.IsNoRegister()) {
4577 CHECK_EQ(0u, size) << dst;
4578 } else if (dst.IsCoreRegister()) {
4579 CHECK_EQ(kMipsWordSize, size) << dst;
4580 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
4581 } else if (dst.IsRegisterPair()) {
4582 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4583 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
4584 } else if (dst.IsFRegister()) {
4585 if (size == kMipsWordSize) {
4586 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
4587 } else {
4588 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4589 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
4590 }
4591 } else if (dst.IsDRegister()) {
4592 CHECK_EQ(kMipsDoublewordSize, size) << dst;
4593 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset);
4594 }
4595 }
4596
StoreToOffset(StoreOperandType type,Register reg,Register base,int32_t offset)4597 void MipsAssembler::StoreToOffset(StoreOperandType type,
4598 Register reg,
4599 Register base,
4600 int32_t offset) {
4601 StoreToOffset<>(type, reg, base, offset);
4602 }
4603
StoreSToOffset(FRegister reg,Register base,int32_t offset)4604 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
4605 StoreSToOffset<>(reg, base, offset);
4606 }
4607
StoreDToOffset(FRegister reg,Register base,int32_t offset)4608 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
4609 StoreDToOffset<>(reg, base, offset);
4610 }
4611
StoreQToOffset(FRegister reg,Register base,int32_t offset)4612 void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) {
4613 StoreQToOffset<>(reg, base, offset);
4614 }
4615
DWARFReg(Register reg)4616 static dwarf::Reg DWARFReg(Register reg) {
4617 return dwarf::Reg::MipsCore(static_cast<int>(reg));
4618 }
4619
4620 constexpr size_t kFramePointerSize = 4;
4621
BuildFrame(size_t frame_size,ManagedRegister method_reg,ArrayRef<const ManagedRegister> callee_save_regs,const ManagedRegisterEntrySpills & entry_spills)4622 void MipsAssembler::BuildFrame(size_t frame_size,
4623 ManagedRegister method_reg,
4624 ArrayRef<const ManagedRegister> callee_save_regs,
4625 const ManagedRegisterEntrySpills& entry_spills) {
4626 CHECK_ALIGNED(frame_size, kStackAlignment);
4627 DCHECK(!overwriting_);
4628
4629 // Increase frame to required size.
4630 IncreaseFrameSize(frame_size);
4631
4632 // Push callee saves and return address.
4633 int stack_offset = frame_size - kFramePointerSize;
4634 StoreToOffset(kStoreWord, RA, SP, stack_offset);
4635 cfi_.RelOffset(DWARFReg(RA), stack_offset);
4636 for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
4637 stack_offset -= kFramePointerSize;
4638 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
4639 StoreToOffset(kStoreWord, reg, SP, stack_offset);
4640 cfi_.RelOffset(DWARFReg(reg), stack_offset);
4641 }
4642
4643 // Write out Method*.
4644 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
4645
4646 // Write out entry spills.
4647 int32_t offset = frame_size + kFramePointerSize;
4648 for (size_t i = 0; i < entry_spills.size(); ++i) {
4649 MipsManagedRegister reg = entry_spills.at(i).AsMips();
4650 if (reg.IsNoRegister()) {
4651 ManagedRegisterSpill spill = entry_spills.at(i);
4652 offset += spill.getSize();
4653 } else if (reg.IsCoreRegister()) {
4654 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
4655 offset += kMipsWordSize;
4656 } else if (reg.IsFRegister()) {
4657 StoreSToOffset(reg.AsFRegister(), SP, offset);
4658 offset += kMipsWordSize;
4659 } else if (reg.IsDRegister()) {
4660 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
4661 offset += kMipsDoublewordSize;
4662 }
4663 }
4664 }
4665
RemoveFrame(size_t frame_size,ArrayRef<const ManagedRegister> callee_save_regs)4666 void MipsAssembler::RemoveFrame(size_t frame_size,
4667 ArrayRef<const ManagedRegister> callee_save_regs) {
4668 CHECK_ALIGNED(frame_size, kStackAlignment);
4669 DCHECK(!overwriting_);
4670 cfi_.RememberState();
4671
4672 // Pop callee saves and return address.
4673 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
4674 for (size_t i = 0; i < callee_save_regs.size(); ++i) {
4675 Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
4676 LoadFromOffset(kLoadWord, reg, SP, stack_offset);
4677 cfi_.Restore(DWARFReg(reg));
4678 stack_offset += kFramePointerSize;
4679 }
4680 LoadFromOffset(kLoadWord, RA, SP, stack_offset);
4681 cfi_.Restore(DWARFReg(RA));
4682
4683 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
4684 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
4685 bool reordering = SetReorder(false);
4686 if (exchange) {
4687 // Jump to the return address.
4688 Jr(RA);
4689 // Decrease frame to required size.
4690 DecreaseFrameSize(frame_size); // Single instruction in delay slot.
4691 } else {
4692 // Decrease frame to required size.
4693 DecreaseFrameSize(frame_size);
4694 // Jump to the return address.
4695 Jr(RA);
4696 Nop(); // In delay slot.
4697 }
4698 SetReorder(reordering);
4699
4700 // The CFI should be restored for any code that follows the exit block.
4701 cfi_.RestoreState();
4702 cfi_.DefCFAOffset(frame_size);
4703 }
4704
IncreaseFrameSize(size_t adjust)4705 void MipsAssembler::IncreaseFrameSize(size_t adjust) {
4706 CHECK_ALIGNED(adjust, kFramePointerSize);
4707 Addiu32(SP, SP, -adjust);
4708 cfi_.AdjustCFAOffset(adjust);
4709 if (overwriting_) {
4710 cfi_.OverrideDelayedPC(overwrite_location_);
4711 }
4712 }
4713
DecreaseFrameSize(size_t adjust)4714 void MipsAssembler::DecreaseFrameSize(size_t adjust) {
4715 CHECK_ALIGNED(adjust, kFramePointerSize);
4716 Addiu32(SP, SP, adjust);
4717 cfi_.AdjustCFAOffset(-adjust);
4718 if (overwriting_) {
4719 cfi_.OverrideDelayedPC(overwrite_location_);
4720 }
4721 }
4722
Store(FrameOffset dest,ManagedRegister msrc,size_t size)4723 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
4724 MipsManagedRegister src = msrc.AsMips();
4725 if (src.IsNoRegister()) {
4726 CHECK_EQ(0u, size);
4727 } else if (src.IsCoreRegister()) {
4728 CHECK_EQ(kMipsWordSize, size);
4729 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4730 } else if (src.IsRegisterPair()) {
4731 CHECK_EQ(kMipsDoublewordSize, size);
4732 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
4733 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
4734 SP, dest.Int32Value() + kMipsWordSize);
4735 } else if (src.IsFRegister()) {
4736 if (size == kMipsWordSize) {
4737 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
4738 } else {
4739 CHECK_EQ(kMipsDoublewordSize, size);
4740 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
4741 }
4742 } else if (src.IsDRegister()) {
4743 CHECK_EQ(kMipsDoublewordSize, size);
4744 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value());
4745 }
4746 }
4747
StoreRef(FrameOffset dest,ManagedRegister msrc)4748 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
4749 MipsManagedRegister src = msrc.AsMips();
4750 CHECK(src.IsCoreRegister());
4751 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4752 }
4753
StoreRawPtr(FrameOffset dest,ManagedRegister msrc)4754 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
4755 MipsManagedRegister src = msrc.AsMips();
4756 CHECK(src.IsCoreRegister());
4757 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4758 }
4759
StoreImmediateToFrame(FrameOffset dest,uint32_t imm,ManagedRegister mscratch)4760 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
4761 ManagedRegister mscratch) {
4762 MipsManagedRegister scratch = mscratch.AsMips();
4763 CHECK(scratch.IsCoreRegister()) << scratch;
4764 LoadConst32(scratch.AsCoreRegister(), imm);
4765 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
4766 }
4767
StoreStackOffsetToThread(ThreadOffset32 thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)4768 void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
4769 FrameOffset fr_offs,
4770 ManagedRegister mscratch) {
4771 MipsManagedRegister scratch = mscratch.AsMips();
4772 CHECK(scratch.IsCoreRegister()) << scratch;
4773 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
4774 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
4775 S1, thr_offs.Int32Value());
4776 }
4777
StoreStackPointerToThread(ThreadOffset32 thr_offs)4778 void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
4779 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
4780 }
4781
StoreSpanning(FrameOffset dest,ManagedRegister msrc,FrameOffset in_off,ManagedRegister mscratch)4782 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
4783 FrameOffset in_off, ManagedRegister mscratch) {
4784 MipsManagedRegister src = msrc.AsMips();
4785 MipsManagedRegister scratch = mscratch.AsMips();
4786 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
4787 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
4788 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
4789 }
4790
Load(ManagedRegister mdest,FrameOffset src,size_t size)4791 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
4792 return EmitLoad(mdest, SP, src.Int32Value(), size);
4793 }
4794
LoadFromThread(ManagedRegister mdest,ThreadOffset32 src,size_t size)4795 void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
4796 return EmitLoad(mdest, S1, src.Int32Value(), size);
4797 }
4798
LoadRef(ManagedRegister mdest,FrameOffset src)4799 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
4800 MipsManagedRegister dest = mdest.AsMips();
4801 CHECK(dest.IsCoreRegister());
4802 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
4803 }
4804
LoadRef(ManagedRegister mdest,ManagedRegister base,MemberOffset offs,bool unpoison_reference)4805 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
4806 bool unpoison_reference) {
4807 MipsManagedRegister dest = mdest.AsMips();
4808 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
4809 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
4810 base.AsMips().AsCoreRegister(), offs.Int32Value());
4811 if (unpoison_reference) {
4812 MaybeUnpoisonHeapReference(dest.AsCoreRegister());
4813 }
4814 }
4815
LoadRawPtr(ManagedRegister mdest,ManagedRegister base,Offset offs)4816 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
4817 MipsManagedRegister dest = mdest.AsMips();
4818 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
4819 LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
4820 base.AsMips().AsCoreRegister(), offs.Int32Value());
4821 }
4822
LoadRawPtrFromThread(ManagedRegister mdest,ThreadOffset32 offs)4823 void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
4824 MipsManagedRegister dest = mdest.AsMips();
4825 CHECK(dest.IsCoreRegister());
4826 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
4827 }
4828
SignExtend(ManagedRegister,size_t)4829 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
4830 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
4831 }
4832
ZeroExtend(ManagedRegister,size_t)4833 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
4834 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
4835 }
4836
Move(ManagedRegister mdest,ManagedRegister msrc,size_t size)4837 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
4838 MipsManagedRegister dest = mdest.AsMips();
4839 MipsManagedRegister src = msrc.AsMips();
4840 if (!dest.Equals(src)) {
4841 if (dest.IsCoreRegister()) {
4842 CHECK(src.IsCoreRegister()) << src;
4843 Move(dest.AsCoreRegister(), src.AsCoreRegister());
4844 } else if (dest.IsFRegister()) {
4845 CHECK(src.IsFRegister()) << src;
4846 if (size == kMipsWordSize) {
4847 MovS(dest.AsFRegister(), src.AsFRegister());
4848 } else {
4849 CHECK_EQ(kMipsDoublewordSize, size);
4850 MovD(dest.AsFRegister(), src.AsFRegister());
4851 }
4852 } else if (dest.IsDRegister()) {
4853 CHECK(src.IsDRegister()) << src;
4854 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
4855 } else {
4856 CHECK(dest.IsRegisterPair()) << dest;
4857 CHECK(src.IsRegisterPair()) << src;
4858 // Ensure that the first move doesn't clobber the input of the second.
4859 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
4860 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
4861 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
4862 } else {
4863 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
4864 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
4865 }
4866 }
4867 }
4868 }
4869
CopyRef(FrameOffset dest,FrameOffset src,ManagedRegister mscratch)4870 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
4871 MipsManagedRegister scratch = mscratch.AsMips();
4872 CHECK(scratch.IsCoreRegister()) << scratch;
4873 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
4874 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
4875 }
4876
CopyRawPtrFromThread(FrameOffset fr_offs,ThreadOffset32 thr_offs,ManagedRegister mscratch)4877 void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
4878 ThreadOffset32 thr_offs,
4879 ManagedRegister mscratch) {
4880 MipsManagedRegister scratch = mscratch.AsMips();
4881 CHECK(scratch.IsCoreRegister()) << scratch;
4882 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
4883 S1, thr_offs.Int32Value());
4884 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
4885 SP, fr_offs.Int32Value());
4886 }
4887
CopyRawPtrToThread(ThreadOffset32 thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)4888 void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
4889 FrameOffset fr_offs,
4890 ManagedRegister mscratch) {
4891 MipsManagedRegister scratch = mscratch.AsMips();
4892 CHECK(scratch.IsCoreRegister()) << scratch;
4893 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
4894 SP, fr_offs.Int32Value());
4895 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
4896 S1, thr_offs.Int32Value());
4897 }
4898
Copy(FrameOffset dest,FrameOffset src,ManagedRegister mscratch,size_t size)4899 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
4900 MipsManagedRegister scratch = mscratch.AsMips();
4901 CHECK(scratch.IsCoreRegister()) << scratch;
4902 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
4903 if (size == kMipsWordSize) {
4904 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
4905 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
4906 } else if (size == kMipsDoublewordSize) {
4907 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
4908 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
4909 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
4910 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
4911 }
4912 }
4913
Copy(FrameOffset dest,ManagedRegister src_base,Offset src_offset,ManagedRegister mscratch,size_t size)4914 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
4915 ManagedRegister mscratch, size_t size) {
4916 Register scratch = mscratch.AsMips().AsCoreRegister();
4917 CHECK_EQ(size, kMipsWordSize);
4918 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
4919 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
4920 }
4921
Copy(ManagedRegister dest_base,Offset dest_offset,FrameOffset src,ManagedRegister mscratch,size_t size)4922 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
4923 ManagedRegister mscratch, size_t size) {
4924 Register scratch = mscratch.AsMips().AsCoreRegister();
4925 CHECK_EQ(size, kMipsWordSize);
4926 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
4927 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
4928 }
4929
Copy(FrameOffset dest ATTRIBUTE_UNUSED,FrameOffset src_base ATTRIBUTE_UNUSED,Offset src_offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)4930 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
4931 FrameOffset src_base ATTRIBUTE_UNUSED,
4932 Offset src_offset ATTRIBUTE_UNUSED,
4933 ManagedRegister mscratch ATTRIBUTE_UNUSED,
4934 size_t size ATTRIBUTE_UNUSED) {
4935 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
4936 }
4937
Copy(ManagedRegister dest,Offset dest_offset,ManagedRegister src,Offset src_offset,ManagedRegister mscratch,size_t size)4938 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
4939 ManagedRegister src, Offset src_offset,
4940 ManagedRegister mscratch, size_t size) {
4941 CHECK_EQ(size, kMipsWordSize);
4942 Register scratch = mscratch.AsMips().AsCoreRegister();
4943 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
4944 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
4945 }
4946
Copy(FrameOffset dest ATTRIBUTE_UNUSED,Offset dest_offset ATTRIBUTE_UNUSED,FrameOffset src ATTRIBUTE_UNUSED,Offset src_offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)4947 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
4948 Offset dest_offset ATTRIBUTE_UNUSED,
4949 FrameOffset src ATTRIBUTE_UNUSED,
4950 Offset src_offset ATTRIBUTE_UNUSED,
4951 ManagedRegister mscratch ATTRIBUTE_UNUSED,
4952 size_t size ATTRIBUTE_UNUSED) {
4953 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
4954 }
4955
MemoryBarrier(ManagedRegister)4956 void MipsAssembler::MemoryBarrier(ManagedRegister) {
4957 // TODO: sync?
4958 UNIMPLEMENTED(FATAL) << "no MIPS implementation";
4959 }
4960
CreateHandleScopeEntry(ManagedRegister mout_reg,FrameOffset handle_scope_offset,ManagedRegister min_reg,bool null_allowed)4961 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
4962 FrameOffset handle_scope_offset,
4963 ManagedRegister min_reg,
4964 bool null_allowed) {
4965 MipsManagedRegister out_reg = mout_reg.AsMips();
4966 MipsManagedRegister in_reg = min_reg.AsMips();
4967 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
4968 CHECK(out_reg.IsCoreRegister()) << out_reg;
4969 if (null_allowed) {
4970 MipsLabel null_arg;
4971 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
4972 // the address in the handle scope holding the reference.
4973 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
4974 if (in_reg.IsNoRegister()) {
4975 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
4976 SP, handle_scope_offset.Int32Value());
4977 in_reg = out_reg;
4978 }
4979 if (!out_reg.Equals(in_reg)) {
4980 LoadConst32(out_reg.AsCoreRegister(), 0);
4981 }
4982 Beqz(in_reg.AsCoreRegister(), &null_arg);
4983 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
4984 Bind(&null_arg);
4985 } else {
4986 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
4987 }
4988 }
4989
CreateHandleScopeEntry(FrameOffset out_off,FrameOffset handle_scope_offset,ManagedRegister mscratch,bool null_allowed)4990 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
4991 FrameOffset handle_scope_offset,
4992 ManagedRegister mscratch,
4993 bool null_allowed) {
4994 MipsManagedRegister scratch = mscratch.AsMips();
4995 CHECK(scratch.IsCoreRegister()) << scratch;
4996 if (null_allowed) {
4997 MipsLabel null_arg;
4998 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
4999 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
5000 // the address in the handle scope holding the reference.
5001 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
5002 Beqz(scratch.AsCoreRegister(), &null_arg);
5003 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5004 Bind(&null_arg);
5005 } else {
5006 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
5007 }
5008 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
5009 }
5010
5011 // Given a handle scope entry, load the associated reference.
LoadReferenceFromHandleScope(ManagedRegister mout_reg,ManagedRegister min_reg)5012 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
5013 ManagedRegister min_reg) {
5014 MipsManagedRegister out_reg = mout_reg.AsMips();
5015 MipsManagedRegister in_reg = min_reg.AsMips();
5016 CHECK(out_reg.IsCoreRegister()) << out_reg;
5017 CHECK(in_reg.IsCoreRegister()) << in_reg;
5018 MipsLabel null_arg;
5019 if (!out_reg.Equals(in_reg)) {
5020 LoadConst32(out_reg.AsCoreRegister(), 0);
5021 }
5022 Beqz(in_reg.AsCoreRegister(), &null_arg);
5023 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
5024 in_reg.AsCoreRegister(), 0);
5025 Bind(&null_arg);
5026 }
5027
VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)5028 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
5029 bool could_be_null ATTRIBUTE_UNUSED) {
5030 // TODO: not validating references.
5031 }
5032
VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)5033 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
5034 bool could_be_null ATTRIBUTE_UNUSED) {
5035 // TODO: not validating references.
5036 }
5037
Call(ManagedRegister mbase,Offset offset,ManagedRegister mscratch)5038 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
5039 MipsManagedRegister base = mbase.AsMips();
5040 MipsManagedRegister scratch = mscratch.AsMips();
5041 CHECK(base.IsCoreRegister()) << base;
5042 CHECK(scratch.IsCoreRegister()) << scratch;
5043 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5044 base.AsCoreRegister(), offset.Int32Value());
5045 Jalr(scratch.AsCoreRegister());
5046 NopIfNoReordering();
5047 // TODO: place reference map on call.
5048 }
5049
Call(FrameOffset base,Offset offset,ManagedRegister mscratch)5050 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
5051 MipsManagedRegister scratch = mscratch.AsMips();
5052 CHECK(scratch.IsCoreRegister()) << scratch;
5053 // Call *(*(SP + base) + offset)
5054 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
5055 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5056 scratch.AsCoreRegister(), offset.Int32Value());
5057 Jalr(scratch.AsCoreRegister());
5058 NopIfNoReordering();
5059 // TODO: place reference map on call.
5060 }
5061
CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED)5062 void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
5063 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
5064 UNIMPLEMENTED(FATAL) << "no mips implementation";
5065 }
5066
GetCurrentThread(ManagedRegister tr)5067 void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
5068 Move(tr.AsMips().AsCoreRegister(), S1);
5069 }
5070
GetCurrentThread(FrameOffset offset,ManagedRegister mscratch ATTRIBUTE_UNUSED)5071 void MipsAssembler::GetCurrentThread(FrameOffset offset,
5072 ManagedRegister mscratch ATTRIBUTE_UNUSED) {
5073 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
5074 }
5075
ExceptionPoll(ManagedRegister mscratch,size_t stack_adjust)5076 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
5077 MipsManagedRegister scratch = mscratch.AsMips();
5078 exception_blocks_.emplace_back(scratch, stack_adjust);
5079 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
5080 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value());
5081 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
5082 }
5083
EmitExceptionPoll(MipsExceptionSlowPath * exception)5084 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
5085 Bind(exception->Entry());
5086 if (exception->stack_adjust_ != 0) { // Fix up the frame.
5087 DecreaseFrameSize(exception->stack_adjust_);
5088 }
5089 // Pass exception object as argument.
5090 // Don't care about preserving A0 as this call won't return.
5091 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5092 Move(A0, exception->scratch_.AsCoreRegister());
5093 // Set up call to Thread::Current()->pDeliverException.
5094 LoadFromOffset(kLoadWord, T9, S1,
5095 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value());
5096 Jr(T9);
5097 NopIfNoReordering();
5098
5099 // Call never returns.
5100 Break();
5101 }
5102
5103 } // namespace mips
5104 } // namespace art
5105