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