1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "assembler_mips.h"
18 
19 #include "base/bit_utils.h"
20 #include "base/casts.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "entrypoints/quick/quick_entrypoints_enum.h"
23 #include "memory_region.h"
24 #include "thread.h"
25 
26 namespace art {
27 namespace mips {
28 
29 static_assert(static_cast<size_t>(kMipsPointerSize) == kMipsWordSize,
30               "Unexpected Mips pointer size.");
31 static_assert(kMipsPointerSize == PointerSize::k32, "Unexpected Mips pointer size.");
32 
33 
operator <<(std::ostream & os,const DRegister & rhs)34 std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
35   if (rhs >= D0 && rhs < kNumberOfDRegisters) {
36     os << "d" << static_cast<int>(rhs);
37   } else {
38     os << "DRegister[" << static_cast<int>(rhs) << "]";
39   }
40   return os;
41 }
42 
DelaySlot()43 MipsAssembler::DelaySlot::DelaySlot()
44     : instruction_(0),
45       gpr_outs_mask_(0),
46       gpr_ins_mask_(0),
47       fpr_outs_mask_(0),
48       fpr_ins_mask_(0),
49       cc_outs_mask_(0),
50       cc_ins_mask_(0) {}
51 
DsFsmInstr(uint32_t instruction,uint32_t gpr_outs_mask,uint32_t gpr_ins_mask,uint32_t fpr_outs_mask,uint32_t fpr_ins_mask,uint32_t cc_outs_mask,uint32_t cc_ins_mask)52 void MipsAssembler::DsFsmInstr(uint32_t instruction,
53                                uint32_t gpr_outs_mask,
54                                uint32_t gpr_ins_mask,
55                                uint32_t fpr_outs_mask,
56                                uint32_t fpr_ins_mask,
57                                uint32_t cc_outs_mask,
58                                uint32_t cc_ins_mask) {
59   if (!reordering_) {
60     CHECK_EQ(ds_fsm_state_, kExpectingLabel);
61     CHECK_EQ(delay_slot_.instruction_, 0u);
62     return;
63   }
64   switch (ds_fsm_state_) {
65     case kExpectingLabel:
66       break;
67     case kExpectingInstruction:
68       CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
69       // If the last instruction is not suitable for delay slots, drop
70       // the PC of the label preceding it so that no unconditional branch
71       // uses this instruction to fill its delay slot.
72       if (instruction == 0) {
73         DsFsmDropLabel();  // Sets ds_fsm_state_ = kExpectingLabel.
74       } else {
75         // Otherwise wait for another instruction or label before we can
76         // commit the label PC. The label PC will be dropped if instead
77         // of another instruction or label there's a call from the code
78         // generator to CodePosition() to record the buffer size.
79         // Instructions after which the buffer size is recorded cannot
80         // be moved into delay slots or anywhere else because they may
81         // trigger signals and the signal handlers expect these signals
82         // to be coming from the instructions immediately preceding the
83         // recorded buffer locations.
84         ds_fsm_state_ = kExpectingCommit;
85       }
86       break;
87     case kExpectingCommit:
88       CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size());
89       DsFsmCommitLabel();  // Sets ds_fsm_state_ = kExpectingLabel.
90       break;
91   }
92   delay_slot_.instruction_ = instruction;
93   delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u;  // Ignore register ZERO.
94   delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u;  // Ignore register ZERO.
95   delay_slot_.fpr_outs_mask_ = fpr_outs_mask;
96   delay_slot_.fpr_ins_mask_ = fpr_ins_mask;
97   delay_slot_.cc_outs_mask_ = cc_outs_mask;
98   delay_slot_.cc_ins_mask_ = cc_ins_mask;
99 }
100 
DsFsmLabel()101 void MipsAssembler::DsFsmLabel() {
102   if (!reordering_) {
103     CHECK_EQ(ds_fsm_state_, kExpectingLabel);
104     CHECK_EQ(delay_slot_.instruction_, 0u);
105     return;
106   }
107   switch (ds_fsm_state_) {
108     case kExpectingLabel:
109       ds_fsm_target_pc_ = buffer_.Size();
110       ds_fsm_state_ = kExpectingInstruction;
111       break;
112     case kExpectingInstruction:
113       // Allow consecutive labels.
114       CHECK_EQ(ds_fsm_target_pc_, buffer_.Size());
115       break;
116     case kExpectingCommit:
117       CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size());
118       DsFsmCommitLabel();
119       ds_fsm_target_pc_ = buffer_.Size();
120       ds_fsm_state_ = kExpectingInstruction;
121       break;
122   }
123   // We cannot move instructions into delay slots across labels.
124   delay_slot_.instruction_ = 0;
125 }
126 
DsFsmCommitLabel()127 void MipsAssembler::DsFsmCommitLabel() {
128   if (ds_fsm_state_ == kExpectingCommit) {
129     ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_);
130   }
131   ds_fsm_state_ = kExpectingLabel;
132 }
133 
DsFsmDropLabel()134 void MipsAssembler::DsFsmDropLabel() {
135   ds_fsm_state_ = kExpectingLabel;
136 }
137 
SetReorder(bool enable)138 bool MipsAssembler::SetReorder(bool enable) {
139   bool last_state = reordering_;
140   if (last_state != enable) {
141     DsFsmCommitLabel();
142     DsFsmInstrNop(0);
143   }
144   reordering_ = enable;
145   return last_state;
146 }
147 
CodePosition()148 size_t MipsAssembler::CodePosition() {
149   // The last instruction cannot be used in a delay slot, do not commit
150   // the label before it (if any) and clear the delay slot.
151   DsFsmDropLabel();
152   DsFsmInstrNop(0);
153   size_t size = buffer_.Size();
154   // In theory we can get the following sequence:
155   //   label1:
156   //     instr
157   //   label2: # label1 gets committed when label2 is seen
158   //     CodePosition() call
159   // and we need to uncommit label1.
160   if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) {
161     ds_fsm_target_pcs_.pop_back();
162   }
163   return size;
164 }
165 
DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED)166 void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
167   DsFsmInstr(0, 0, 0, 0, 0, 0, 0);
168 }
169 
DsFsmInstrRrr(uint32_t instruction,Register out,Register in1,Register in2)170 void MipsAssembler::DsFsmInstrRrr(uint32_t instruction, Register out, Register in1, Register in2) {
171   DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0);
172 }
173 
DsFsmInstrRrrr(uint32_t instruction,Register in1_out,Register in2,Register in3)174 void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction,
175                                    Register in1_out,
176                                    Register in2,
177                                    Register in3) {
178   DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0);
179 }
180 
DsFsmInstrFff(uint32_t instruction,FRegister out,FRegister in1,FRegister in2)181 void MipsAssembler::DsFsmInstrFff(uint32_t instruction,
182                                   FRegister out,
183                                   FRegister in1,
184                                   FRegister in2) {
185   DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0);
186 }
187 
DsFsmInstrFfff(uint32_t instruction,FRegister in1_out,FRegister in2,FRegister in3)188 void MipsAssembler::DsFsmInstrFfff(uint32_t instruction,
189                                    FRegister in1_out,
190                                    FRegister in2,
191                                    FRegister in3) {
192   DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0);
193 }
194 
DsFsmInstrFffr(uint32_t instruction,FRegister in1_out,FRegister in2,Register in3)195 void MipsAssembler::DsFsmInstrFffr(uint32_t instruction,
196                                    FRegister in1_out,
197                                    FRegister in2,
198                                    Register in3) {
199   DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0);
200 }
201 
DsFsmInstrRf(uint32_t instruction,Register out,FRegister in)202 void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) {
203   DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0);
204 }
205 
DsFsmInstrFr(uint32_t instruction,FRegister out,Register in)206 void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) {
207   DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0);
208 }
209 
DsFsmInstrFR(uint32_t instruction,FRegister in1,Register in2)210 void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) {
211   DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0);
212 }
213 
DsFsmInstrCff(uint32_t instruction,int cc_out,FRegister in1,FRegister in2)214 void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) {
215   DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0);
216 }
217 
DsFsmInstrRrrc(uint32_t instruction,Register in1_out,Register in2,int cc_in)218 void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction,
219                                    Register in1_out,
220                                    Register in2,
221                                    int cc_in) {
222   DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in));
223 }
224 
DsFsmInstrFffc(uint32_t instruction,FRegister in1_out,FRegister in2,int cc_in)225 void MipsAssembler::DsFsmInstrFffc(uint32_t instruction,
226                                    FRegister in1_out,
227                                    FRegister in2,
228                                    int cc_in) {
229   DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in));
230 }
231 
FinalizeCode()232 void MipsAssembler::FinalizeCode() {
233   for (auto& exception_block : exception_blocks_) {
234     EmitExceptionPoll(&exception_block);
235   }
236   // Commit the last branch target label (if any) and disable instruction reordering.
237   DsFsmCommitLabel();
238   SetReorder(false);
239   EmitLiterals();
240   ReserveJumpTableSpace();
241   PromoteBranches();
242 }
243 
FinalizeInstructions(const MemoryRegion & region)244 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
245   size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
246   EmitBranches();
247   EmitJumpTables();
248   Assembler::FinalizeInstructions(region);
249   PatchCFI(number_of_delayed_adjust_pcs);
250 }
251 
PatchCFI(size_t number_of_delayed_adjust_pcs)252 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) {
253   if (cfi().NumberOfDelayedAdvancePCs() == 0u) {
254     DCHECK_EQ(number_of_delayed_adjust_pcs, 0u);
255     return;
256   }
257 
258   typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC;
259   const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC();
260   const std::vector<uint8_t>& old_stream = data.first;
261   const std::vector<DelayedAdvancePC>& advances = data.second;
262 
263   // PCs recorded before EmitBranches() need to be adjusted.
264   // PCs recorded during EmitBranches() are already adjusted.
265   // Both ranges are separately sorted but they may overlap.
266   if (kIsDebugBuild) {
267     auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) {
268       return lhs.pc < rhs.pc;
269     };
270     CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp));
271     CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp));
272   }
273 
274   // Append initial CFI data if any.
275   size_t size = advances.size();
276   DCHECK_NE(size, 0u);
277   cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos);
278   // Emit PC adjustments interleaved with the old CFI stream.
279   size_t adjust_pos = 0u;
280   size_t late_emit_pos = number_of_delayed_adjust_pcs;
281   while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) {
282     size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs)
283         ? GetAdjustedPosition(advances[adjust_pos].pc)
284         : static_cast<size_t>(-1);
285     size_t late_emit_pc = (late_emit_pos != size)
286         ? advances[late_emit_pos].pc
287         : static_cast<size_t>(-1);
288     size_t advance_pc = std::min(adjusted_pc, late_emit_pc);
289     DCHECK_NE(advance_pc, static_cast<size_t>(-1));
290     size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos;
291     if (adjusted_pc <= late_emit_pc) {
292       ++adjust_pos;
293     } else {
294       ++late_emit_pos;
295     }
296     cfi().AdvancePC(advance_pc);
297     size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos;
298     cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos);
299   }
300 }
301 
EmitBranches()302 void MipsAssembler::EmitBranches() {
303   CHECK(!overwriting_);
304   CHECK(!reordering_);
305   // Now that everything has its final position in the buffer (the branches have
306   // been promoted), adjust the target label PCs.
307   for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) {
308     ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]);
309   }
310   // Switch from appending instructions at the end of the buffer to overwriting
311   // existing instructions (branch placeholders) in the buffer.
312   overwriting_ = true;
313   for (auto& branch : branches_) {
314     EmitBranch(&branch);
315   }
316   overwriting_ = false;
317 }
318 
Emit(uint32_t value)319 void MipsAssembler::Emit(uint32_t value) {
320   if (overwriting_) {
321     // Branches to labels are emitted into their placeholders here.
322     buffer_.Store<uint32_t>(overwrite_location_, value);
323     overwrite_location_ += sizeof(uint32_t);
324   } else {
325     // Other instructions are simply appended at the end here.
326     AssemblerBuffer::EnsureCapacity ensured(&buffer_);
327     buffer_.Emit<uint32_t>(value);
328   }
329 }
330 
EmitR(int opcode,Register rs,Register rt,Register rd,int shamt,int funct)331 uint32_t MipsAssembler::EmitR(int opcode,
332                               Register rs,
333                               Register rt,
334                               Register rd,
335                               int shamt,
336                               int funct) {
337   CHECK_NE(rs, kNoRegister);
338   CHECK_NE(rt, kNoRegister);
339   CHECK_NE(rd, kNoRegister);
340   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
341                       static_cast<uint32_t>(rs) << kRsShift |
342                       static_cast<uint32_t>(rt) << kRtShift |
343                       static_cast<uint32_t>(rd) << kRdShift |
344                       shamt << kShamtShift |
345                       funct;
346   Emit(encoding);
347   return encoding;
348 }
349 
EmitI(int opcode,Register rs,Register rt,uint16_t imm)350 uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
351   CHECK_NE(rs, kNoRegister);
352   CHECK_NE(rt, kNoRegister);
353   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
354                       static_cast<uint32_t>(rs) << kRsShift |
355                       static_cast<uint32_t>(rt) << kRtShift |
356                       imm;
357   Emit(encoding);
358   return encoding;
359 }
360 
EmitI21(int opcode,Register rs,uint32_t imm21)361 uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) {
362   CHECK_NE(rs, kNoRegister);
363   CHECK(IsUint<21>(imm21)) << imm21;
364   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
365                       static_cast<uint32_t>(rs) << kRsShift |
366                       imm21;
367   Emit(encoding);
368   return encoding;
369 }
370 
EmitI26(int opcode,uint32_t imm26)371 uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) {
372   CHECK(IsUint<26>(imm26)) << imm26;
373   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26;
374   Emit(encoding);
375   return encoding;
376 }
377 
EmitFR(int opcode,int fmt,FRegister ft,FRegister fs,FRegister fd,int funct)378 uint32_t MipsAssembler::EmitFR(int opcode,
379                                int fmt,
380                                FRegister ft,
381                                FRegister fs,
382                                FRegister fd,
383                                int funct) {
384   CHECK_NE(ft, kNoFRegister);
385   CHECK_NE(fs, kNoFRegister);
386   CHECK_NE(fd, kNoFRegister);
387   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
388                       fmt << kFmtShift |
389                       static_cast<uint32_t>(ft) << kFtShift |
390                       static_cast<uint32_t>(fs) << kFsShift |
391                       static_cast<uint32_t>(fd) << kFdShift |
392                       funct;
393   Emit(encoding);
394   return encoding;
395 }
396 
EmitFI(int opcode,int fmt,FRegister ft,uint16_t imm)397 uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) {
398   CHECK_NE(ft, kNoFRegister);
399   uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
400                       fmt << kFmtShift |
401                       static_cast<uint32_t>(ft) << kFtShift |
402                       imm;
403   Emit(encoding);
404   return encoding;
405 }
406 
Addu(Register rd,Register rs,Register rt)407 void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
408   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt);
409 }
410 
Addiu(Register rt,Register rs,uint16_t imm16)411 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
412   DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs);
413 }
414 
Subu(Register rd,Register rs,Register rt)415 void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
416   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt);
417 }
418 
MultR2(Register rs,Register rt)419 void MipsAssembler::MultR2(Register rs, Register rt) {
420   CHECK(!IsR6());
421   DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt);
422 }
423 
MultuR2(Register rs,Register rt)424 void MipsAssembler::MultuR2(Register rs, Register rt) {
425   CHECK(!IsR6());
426   DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt);
427 }
428 
DivR2(Register rs,Register rt)429 void MipsAssembler::DivR2(Register rs, Register rt) {
430   CHECK(!IsR6());
431   DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt);
432 }
433 
DivuR2(Register rs,Register rt)434 void MipsAssembler::DivuR2(Register rs, Register rt) {
435   CHECK(!IsR6());
436   DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt);
437 }
438 
MulR2(Register rd,Register rs,Register rt)439 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
440   CHECK(!IsR6());
441   DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt);
442 }
443 
DivR2(Register rd,Register rs,Register rt)444 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
445   CHECK(!IsR6());
446   DivR2(rs, rt);
447   Mflo(rd);
448 }
449 
ModR2(Register rd,Register rs,Register rt)450 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) {
451   CHECK(!IsR6());
452   DivR2(rs, rt);
453   Mfhi(rd);
454 }
455 
DivuR2(Register rd,Register rs,Register rt)456 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) {
457   CHECK(!IsR6());
458   DivuR2(rs, rt);
459   Mflo(rd);
460 }
461 
ModuR2(Register rd,Register rs,Register rt)462 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
463   CHECK(!IsR6());
464   DivuR2(rs, rt);
465   Mfhi(rd);
466 }
467 
MulR6(Register rd,Register rs,Register rt)468 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
469   CHECK(IsR6());
470   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt);
471 }
472 
MuhR6(Register rd,Register rs,Register rt)473 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
474   CHECK(IsR6());
475   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt);
476 }
477 
MuhuR6(Register rd,Register rs,Register rt)478 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
479   CHECK(IsR6());
480   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt);
481 }
482 
DivR6(Register rd,Register rs,Register rt)483 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
484   CHECK(IsR6());
485   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt);
486 }
487 
ModR6(Register rd,Register rs,Register rt)488 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
489   CHECK(IsR6());
490   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt);
491 }
492 
DivuR6(Register rd,Register rs,Register rt)493 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
494   CHECK(IsR6());
495   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt);
496 }
497 
ModuR6(Register rd,Register rs,Register rt)498 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
499   CHECK(IsR6());
500   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt);
501 }
502 
And(Register rd,Register rs,Register rt)503 void MipsAssembler::And(Register rd, Register rs, Register rt) {
504   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt);
505 }
506 
Andi(Register rt,Register rs,uint16_t imm16)507 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
508   DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs);
509 }
510 
Or(Register rd,Register rs,Register rt)511 void MipsAssembler::Or(Register rd, Register rs, Register rt) {
512   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt);
513 }
514 
Ori(Register rt,Register rs,uint16_t imm16)515 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
516   DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs);
517 }
518 
Xor(Register rd,Register rs,Register rt)519 void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
520   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt);
521 }
522 
Xori(Register rt,Register rs,uint16_t imm16)523 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
524   DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs);
525 }
526 
Nor(Register rd,Register rs,Register rt)527 void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
528   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt);
529 }
530 
Movz(Register rd,Register rs,Register rt)531 void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
532   CHECK(!IsR6());
533   DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt);
534 }
535 
Movn(Register rd,Register rs,Register rt)536 void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
537   CHECK(!IsR6());
538   DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt);
539 }
540 
Seleqz(Register rd,Register rs,Register rt)541 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
542   CHECK(IsR6());
543   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt);
544 }
545 
Selnez(Register rd,Register rs,Register rt)546 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
547   CHECK(IsR6());
548   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt);
549 }
550 
ClzR6(Register rd,Register rs)551 void MipsAssembler::ClzR6(Register rd, Register rs) {
552   CHECK(IsR6());
553   DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs);
554 }
555 
ClzR2(Register rd,Register rs)556 void MipsAssembler::ClzR2(Register rd, Register rs) {
557   CHECK(!IsR6());
558   DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs);
559 }
560 
CloR6(Register rd,Register rs)561 void MipsAssembler::CloR6(Register rd, Register rs) {
562   CHECK(IsR6());
563   DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs);
564 }
565 
CloR2(Register rd,Register rs)566 void MipsAssembler::CloR2(Register rd, Register rs) {
567   CHECK(!IsR6());
568   DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs);
569 }
570 
Seb(Register rd,Register rt)571 void MipsAssembler::Seb(Register rd, Register rt) {
572   DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt);
573 }
574 
Seh(Register rd,Register rt)575 void MipsAssembler::Seh(Register rd, Register rt) {
576   DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt);
577 }
578 
Wsbh(Register rd,Register rt)579 void MipsAssembler::Wsbh(Register rd, Register rt) {
580   DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt);
581 }
582 
Bitswap(Register rd,Register rt)583 void MipsAssembler::Bitswap(Register rd, Register rt) {
584   CHECK(IsR6());
585   DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt);
586 }
587 
Sll(Register rd,Register rt,int shamt)588 void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
589   CHECK(IsUint<5>(shamt)) << shamt;
590   DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt);
591 }
592 
Srl(Register rd,Register rt,int shamt)593 void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
594   CHECK(IsUint<5>(shamt)) << shamt;
595   DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt);
596 }
597 
Rotr(Register rd,Register rt,int shamt)598 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
599   CHECK(IsUint<5>(shamt)) << shamt;
600   DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt);
601 }
602 
Sra(Register rd,Register rt,int shamt)603 void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
604   CHECK(IsUint<5>(shamt)) << shamt;
605   DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt);
606 }
607 
Sllv(Register rd,Register rt,Register rs)608 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
609   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt);
610 }
611 
Srlv(Register rd,Register rt,Register rs)612 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
613   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt);
614 }
615 
Rotrv(Register rd,Register rt,Register rs)616 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
617   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt);
618 }
619 
Srav(Register rd,Register rt,Register rs)620 void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
621   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt);
622 }
623 
Ext(Register rd,Register rt,int pos,int size)624 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
625   CHECK(IsUint<5>(pos)) << pos;
626   CHECK(0 < size && size <= 32) << size;
627   CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
628   DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt);
629 }
630 
Ins(Register rd,Register rt,int pos,int size)631 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
632   CHECK(IsUint<5>(pos)) << pos;
633   CHECK(0 < size && size <= 32) << size;
634   CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
635   DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
636 }
637 
638 // TODO: This instruction is available in both R6 and MSA and it should be used when available.
Lsa(Register rd,Register rs,Register rt,int saPlusOne)639 void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
640   CHECK(IsR6());
641   CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
642   int sa = saPlusOne - 1;
643   DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
644 }
645 
ShiftAndAdd(Register dst,Register src_idx,Register src_base,int shamt,Register tmp)646 void MipsAssembler::ShiftAndAdd(Register dst,
647                                 Register src_idx,
648                                 Register src_base,
649                                 int shamt,
650                                 Register tmp) {
651   CHECK(0 <= shamt && shamt <= 4) << shamt;
652   CHECK_NE(src_base, tmp);
653   if (shamt == TIMES_1) {
654     // Catch the special case where the shift amount is zero (0).
655     Addu(dst, src_base, src_idx);
656   } else if (IsR6()) {
657     Lsa(dst, src_idx, src_base, shamt);
658   } else {
659     Sll(tmp, src_idx, shamt);
660     Addu(dst, src_base, tmp);
661   }
662 }
663 
Lb(Register rt,Register rs,uint16_t imm16)664 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
665   DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
666 }
667 
Lh(Register rt,Register rs,uint16_t imm16)668 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
669   DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs);
670 }
671 
Lw(Register rt,Register rs,uint16_t imm16)672 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
673   DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs);
674 }
675 
Lwl(Register rt,Register rs,uint16_t imm16)676 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
677   CHECK(!IsR6());
678   DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs);
679 }
680 
Lwr(Register rt,Register rs,uint16_t imm16)681 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
682   CHECK(!IsR6());
683   DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs);
684 }
685 
Lbu(Register rt,Register rs,uint16_t imm16)686 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
687   DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs);
688 }
689 
Lhu(Register rt,Register rs,uint16_t imm16)690 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
691   DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs);
692 }
693 
Lwpc(Register rs,uint32_t imm19)694 void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
695   CHECK(IsR6());
696   CHECK(IsUint<19>(imm19)) << imm19;
697   DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19));
698 }
699 
Lui(Register rt,uint16_t imm16)700 void MipsAssembler::Lui(Register rt, uint16_t imm16) {
701   DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO);
702 }
703 
Aui(Register rt,Register rs,uint16_t imm16)704 void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
705   CHECK(IsR6());
706   DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs);
707 }
708 
Sync(uint32_t stype)709 void MipsAssembler::Sync(uint32_t stype) {
710   DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf));
711 }
712 
Mfhi(Register rd)713 void MipsAssembler::Mfhi(Register rd) {
714   CHECK(!IsR6());
715   DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO);
716 }
717 
Mflo(Register rd)718 void MipsAssembler::Mflo(Register rd) {
719   CHECK(!IsR6());
720   DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO);
721 }
722 
Sb(Register rt,Register rs,uint16_t imm16)723 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
724   DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs);
725 }
726 
Sh(Register rt,Register rs,uint16_t imm16)727 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
728   DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs);
729 }
730 
Sw(Register rt,Register rs,uint16_t imm16)731 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
732   DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs);
733 }
734 
Swl(Register rt,Register rs,uint16_t imm16)735 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
736   CHECK(!IsR6());
737   DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs);
738 }
739 
Swr(Register rt,Register rs,uint16_t imm16)740 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
741   CHECK(!IsR6());
742   DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs);
743 }
744 
LlR2(Register rt,Register base,int16_t imm16)745 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
746   CHECK(!IsR6());
747   DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base);
748 }
749 
ScR2(Register rt,Register base,int16_t imm16)750 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
751   CHECK(!IsR6());
752   DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base);
753 }
754 
LlR6(Register rt,Register base,int16_t imm9)755 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
756   CHECK(IsR6());
757   CHECK(IsInt<9>(imm9));
758   DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base);
759 }
760 
ScR6(Register rt,Register base,int16_t imm9)761 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
762   CHECK(IsR6());
763   CHECK(IsInt<9>(imm9));
764   DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base);
765 }
766 
Slt(Register rd,Register rs,Register rt)767 void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
768   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt);
769 }
770 
Sltu(Register rd,Register rs,Register rt)771 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
772   DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt);
773 }
774 
Slti(Register rt,Register rs,uint16_t imm16)775 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
776   DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs);
777 }
778 
Sltiu(Register rt,Register rs,uint16_t imm16)779 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
780   DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs);
781 }
782 
B(uint16_t imm16)783 void MipsAssembler::B(uint16_t imm16) {
784   DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16));
785 }
786 
Bal(uint16_t imm16)787 void MipsAssembler::Bal(uint16_t imm16) {
788   DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16));
789 }
790 
Beq(Register rs,Register rt,uint16_t imm16)791 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) {
792   DsFsmInstrNop(EmitI(0x4, rs, rt, imm16));
793 }
794 
Bne(Register rs,Register rt,uint16_t imm16)795 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
796   DsFsmInstrNop(EmitI(0x5, rs, rt, imm16));
797 }
798 
Beqz(Register rt,uint16_t imm16)799 void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
800   Beq(ZERO, rt, imm16);
801 }
802 
Bnez(Register rt,uint16_t imm16)803 void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
804   Bne(ZERO, rt, imm16);
805 }
806 
Bltz(Register rt,uint16_t imm16)807 void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
808   DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16));
809 }
810 
Bgez(Register rt,uint16_t imm16)811 void MipsAssembler::Bgez(Register rt, uint16_t imm16) {
812   DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16));
813 }
814 
Blez(Register rt,uint16_t imm16)815 void MipsAssembler::Blez(Register rt, uint16_t imm16) {
816   DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16));
817 }
818 
Bgtz(Register rt,uint16_t imm16)819 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) {
820   DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16));
821 }
822 
Bc1f(uint16_t imm16)823 void MipsAssembler::Bc1f(uint16_t imm16) {
824   Bc1f(0, imm16);
825 }
826 
Bc1f(int cc,uint16_t imm16)827 void MipsAssembler::Bc1f(int cc, uint16_t imm16) {
828   CHECK(!IsR6());
829   CHECK(IsUint<3>(cc)) << cc;
830   DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16));
831 }
832 
Bc1t(uint16_t imm16)833 void MipsAssembler::Bc1t(uint16_t imm16) {
834   Bc1t(0, imm16);
835 }
836 
Bc1t(int cc,uint16_t imm16)837 void MipsAssembler::Bc1t(int cc, uint16_t imm16) {
838   CHECK(!IsR6());
839   CHECK(IsUint<3>(cc)) << cc;
840   DsFsmInstrNop(EmitI(0x11,
841                       static_cast<Register>(0x8),
842                       static_cast<Register>((cc << 2) | 1),
843                       imm16));
844 }
845 
J(uint32_t addr26)846 void MipsAssembler::J(uint32_t addr26) {
847   DsFsmInstrNop(EmitI26(0x2, addr26));
848 }
849 
Jal(uint32_t addr26)850 void MipsAssembler::Jal(uint32_t addr26) {
851   DsFsmInstrNop(EmitI26(0x3, addr26));
852 }
853 
Jalr(Register rd,Register rs)854 void MipsAssembler::Jalr(Register rd, Register rs) {
855   uint32_t last_instruction = delay_slot_.instruction_;
856   bool exchange = (last_instruction != 0 &&
857       (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 &&
858       ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0);
859   if (exchange) {
860     // The last instruction cannot be used in a different delay slot,
861     // do not commit the label before it (if any).
862     DsFsmDropLabel();
863   }
864   DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09));
865   if (exchange) {
866     // Exchange the last two instructions in the assembler buffer.
867     size_t size = buffer_.Size();
868     CHECK_GE(size, 2 * sizeof(uint32_t));
869     size_t pos1 = size - 2 * sizeof(uint32_t);
870     size_t pos2 = size - sizeof(uint32_t);
871     uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
872     uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
873     CHECK_EQ(instr1, last_instruction);
874     buffer_.Store<uint32_t>(pos1, instr2);
875     buffer_.Store<uint32_t>(pos2, instr1);
876   } else if (reordering_) {
877     Nop();
878   }
879 }
880 
Jalr(Register rs)881 void MipsAssembler::Jalr(Register rs) {
882   Jalr(RA, rs);
883 }
884 
Jr(Register rs)885 void MipsAssembler::Jr(Register rs) {
886   Jalr(ZERO, rs);
887 }
888 
Nal()889 void MipsAssembler::Nal() {
890   DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0));
891 }
892 
Auipc(Register rs,uint16_t imm16)893 void MipsAssembler::Auipc(Register rs, uint16_t imm16) {
894   CHECK(IsR6());
895   DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16));
896 }
897 
Addiupc(Register rs,uint32_t imm19)898 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) {
899   CHECK(IsR6());
900   CHECK(IsUint<19>(imm19)) << imm19;
901   DsFsmInstrNop(EmitI21(0x3B, rs, imm19));
902 }
903 
Bc(uint32_t imm26)904 void MipsAssembler::Bc(uint32_t imm26) {
905   CHECK(IsR6());
906   DsFsmInstrNop(EmitI26(0x32, imm26));
907 }
908 
Balc(uint32_t imm26)909 void MipsAssembler::Balc(uint32_t imm26) {
910   CHECK(IsR6());
911   DsFsmInstrNop(EmitI26(0x3A, imm26));
912 }
913 
Jic(Register rt,uint16_t imm16)914 void MipsAssembler::Jic(Register rt, uint16_t imm16) {
915   CHECK(IsR6());
916   DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16));
917 }
918 
Jialc(Register rt,uint16_t imm16)919 void MipsAssembler::Jialc(Register rt, uint16_t imm16) {
920   CHECK(IsR6());
921   DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16));
922 }
923 
Bltc(Register rs,Register rt,uint16_t imm16)924 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) {
925   CHECK(IsR6());
926   CHECK_NE(rs, ZERO);
927   CHECK_NE(rt, ZERO);
928   CHECK_NE(rs, rt);
929   DsFsmInstrNop(EmitI(0x17, rs, rt, imm16));
930 }
931 
Bltzc(Register rt,uint16_t imm16)932 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) {
933   CHECK(IsR6());
934   CHECK_NE(rt, ZERO);
935   DsFsmInstrNop(EmitI(0x17, rt, rt, imm16));
936 }
937 
Bgtzc(Register rt,uint16_t imm16)938 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) {
939   CHECK(IsR6());
940   CHECK_NE(rt, ZERO);
941   DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16));
942 }
943 
Bgec(Register rs,Register rt,uint16_t imm16)944 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) {
945   CHECK(IsR6());
946   CHECK_NE(rs, ZERO);
947   CHECK_NE(rt, ZERO);
948   CHECK_NE(rs, rt);
949   DsFsmInstrNop(EmitI(0x16, rs, rt, imm16));
950 }
951 
Bgezc(Register rt,uint16_t imm16)952 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) {
953   CHECK(IsR6());
954   CHECK_NE(rt, ZERO);
955   DsFsmInstrNop(EmitI(0x16, rt, rt, imm16));
956 }
957 
Blezc(Register rt,uint16_t imm16)958 void MipsAssembler::Blezc(Register rt, uint16_t imm16) {
959   CHECK(IsR6());
960   CHECK_NE(rt, ZERO);
961   DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16));
962 }
963 
Bltuc(Register rs,Register rt,uint16_t imm16)964 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) {
965   CHECK(IsR6());
966   CHECK_NE(rs, ZERO);
967   CHECK_NE(rt, ZERO);
968   CHECK_NE(rs, rt);
969   DsFsmInstrNop(EmitI(0x7, rs, rt, imm16));
970 }
971 
Bgeuc(Register rs,Register rt,uint16_t imm16)972 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) {
973   CHECK(IsR6());
974   CHECK_NE(rs, ZERO);
975   CHECK_NE(rt, ZERO);
976   CHECK_NE(rs, rt);
977   DsFsmInstrNop(EmitI(0x6, rs, rt, imm16));
978 }
979 
Beqc(Register rs,Register rt,uint16_t imm16)980 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) {
981   CHECK(IsR6());
982   CHECK_NE(rs, ZERO);
983   CHECK_NE(rt, ZERO);
984   CHECK_NE(rs, rt);
985   DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16));
986 }
987 
Bnec(Register rs,Register rt,uint16_t imm16)988 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) {
989   CHECK(IsR6());
990   CHECK_NE(rs, ZERO);
991   CHECK_NE(rt, ZERO);
992   CHECK_NE(rs, rt);
993   DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16));
994 }
995 
Beqzc(Register rs,uint32_t imm21)996 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) {
997   CHECK(IsR6());
998   CHECK_NE(rs, ZERO);
999   DsFsmInstrNop(EmitI21(0x36, rs, imm21));
1000 }
1001 
Bnezc(Register rs,uint32_t imm21)1002 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) {
1003   CHECK(IsR6());
1004   CHECK_NE(rs, ZERO);
1005   DsFsmInstrNop(EmitI21(0x3E, rs, imm21));
1006 }
1007 
Bc1eqz(FRegister ft,uint16_t imm16)1008 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) {
1009   CHECK(IsR6());
1010   DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16));
1011 }
1012 
Bc1nez(FRegister ft,uint16_t imm16)1013 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) {
1014   CHECK(IsR6());
1015   DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16));
1016 }
1017 
EmitBcondR2(BranchCondition cond,Register rs,Register rt,uint16_t imm16)1018 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) {
1019   switch (cond) {
1020     case kCondLTZ:
1021       CHECK_EQ(rt, ZERO);
1022       Bltz(rs, imm16);
1023       break;
1024     case kCondGEZ:
1025       CHECK_EQ(rt, ZERO);
1026       Bgez(rs, imm16);
1027       break;
1028     case kCondLEZ:
1029       CHECK_EQ(rt, ZERO);
1030       Blez(rs, imm16);
1031       break;
1032     case kCondGTZ:
1033       CHECK_EQ(rt, ZERO);
1034       Bgtz(rs, imm16);
1035       break;
1036     case kCondEQ:
1037       Beq(rs, rt, imm16);
1038       break;
1039     case kCondNE:
1040       Bne(rs, rt, imm16);
1041       break;
1042     case kCondEQZ:
1043       CHECK_EQ(rt, ZERO);
1044       Beqz(rs, imm16);
1045       break;
1046     case kCondNEZ:
1047       CHECK_EQ(rt, ZERO);
1048       Bnez(rs, imm16);
1049       break;
1050     case kCondF:
1051       CHECK_EQ(rt, ZERO);
1052       Bc1f(static_cast<int>(rs), imm16);
1053       break;
1054     case kCondT:
1055       CHECK_EQ(rt, ZERO);
1056       Bc1t(static_cast<int>(rs), imm16);
1057       break;
1058     case kCondLT:
1059     case kCondGE:
1060     case kCondLE:
1061     case kCondGT:
1062     case kCondLTU:
1063     case kCondGEU:
1064     case kUncond:
1065       // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1066       // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1067       LOG(FATAL) << "Unexpected branch condition " << cond;
1068       UNREACHABLE();
1069   }
1070 }
1071 
EmitBcondR6(BranchCondition cond,Register rs,Register rt,uint32_t imm16_21)1072 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) {
1073   switch (cond) {
1074     case kCondLT:
1075       Bltc(rs, rt, imm16_21);
1076       break;
1077     case kCondGE:
1078       Bgec(rs, rt, imm16_21);
1079       break;
1080     case kCondLE:
1081       Bgec(rt, rs, imm16_21);
1082       break;
1083     case kCondGT:
1084       Bltc(rt, rs, imm16_21);
1085       break;
1086     case kCondLTZ:
1087       CHECK_EQ(rt, ZERO);
1088       Bltzc(rs, imm16_21);
1089       break;
1090     case kCondGEZ:
1091       CHECK_EQ(rt, ZERO);
1092       Bgezc(rs, imm16_21);
1093       break;
1094     case kCondLEZ:
1095       CHECK_EQ(rt, ZERO);
1096       Blezc(rs, imm16_21);
1097       break;
1098     case kCondGTZ:
1099       CHECK_EQ(rt, ZERO);
1100       Bgtzc(rs, imm16_21);
1101       break;
1102     case kCondEQ:
1103       Beqc(rs, rt, imm16_21);
1104       break;
1105     case kCondNE:
1106       Bnec(rs, rt, imm16_21);
1107       break;
1108     case kCondEQZ:
1109       CHECK_EQ(rt, ZERO);
1110       Beqzc(rs, imm16_21);
1111       break;
1112     case kCondNEZ:
1113       CHECK_EQ(rt, ZERO);
1114       Bnezc(rs, imm16_21);
1115       break;
1116     case kCondLTU:
1117       Bltuc(rs, rt, imm16_21);
1118       break;
1119     case kCondGEU:
1120       Bgeuc(rs, rt, imm16_21);
1121       break;
1122     case kCondF:
1123       CHECK_EQ(rt, ZERO);
1124       Bc1eqz(static_cast<FRegister>(rs), imm16_21);
1125       break;
1126     case kCondT:
1127       CHECK_EQ(rt, ZERO);
1128       Bc1nez(static_cast<FRegister>(rs), imm16_21);
1129       break;
1130     case kUncond:
1131       LOG(FATAL) << "Unexpected branch condition " << cond;
1132       UNREACHABLE();
1133   }
1134 }
1135 
AddS(FRegister fd,FRegister fs,FRegister ft)1136 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
1137   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft);
1138 }
1139 
SubS(FRegister fd,FRegister fs,FRegister ft)1140 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
1141   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft);
1142 }
1143 
MulS(FRegister fd,FRegister fs,FRegister ft)1144 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
1145   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft);
1146 }
1147 
DivS(FRegister fd,FRegister fs,FRegister ft)1148 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
1149   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft);
1150 }
1151 
AddD(FRegister fd,FRegister fs,FRegister ft)1152 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
1153   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft);
1154 }
1155 
SubD(FRegister fd,FRegister fs,FRegister ft)1156 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
1157   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft);
1158 }
1159 
MulD(FRegister fd,FRegister fs,FRegister ft)1160 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
1161   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft);
1162 }
1163 
DivD(FRegister fd,FRegister fs,FRegister ft)1164 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
1165   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft);
1166 }
1167 
SqrtS(FRegister fd,FRegister fs)1168 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
1169   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
1170 }
1171 
SqrtD(FRegister fd,FRegister fs)1172 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
1173   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
1174 }
1175 
AbsS(FRegister fd,FRegister fs)1176 void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
1177   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
1178 }
1179 
AbsD(FRegister fd,FRegister fs)1180 void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
1181   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
1182 }
1183 
MovS(FRegister fd,FRegister fs)1184 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
1185   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
1186 }
1187 
MovD(FRegister fd,FRegister fs)1188 void MipsAssembler::MovD(FRegister fd, FRegister fs) {
1189   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
1190 }
1191 
NegS(FRegister fd,FRegister fs)1192 void MipsAssembler::NegS(FRegister fd, FRegister fs) {
1193   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
1194 }
1195 
NegD(FRegister fd,FRegister fs)1196 void MipsAssembler::NegD(FRegister fd, FRegister fs) {
1197   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
1198 }
1199 
CunS(FRegister fs,FRegister ft)1200 void MipsAssembler::CunS(FRegister fs, FRegister ft) {
1201   CunS(0, fs, ft);
1202 }
1203 
CunS(int cc,FRegister fs,FRegister ft)1204 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
1205   CHECK(!IsR6());
1206   CHECK(IsUint<3>(cc)) << cc;
1207   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
1208 }
1209 
CeqS(FRegister fs,FRegister ft)1210 void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
1211   CeqS(0, fs, ft);
1212 }
1213 
CeqS(int cc,FRegister fs,FRegister ft)1214 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
1215   CHECK(!IsR6());
1216   CHECK(IsUint<3>(cc)) << cc;
1217   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
1218 }
1219 
CueqS(FRegister fs,FRegister ft)1220 void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
1221   CueqS(0, fs, ft);
1222 }
1223 
CueqS(int cc,FRegister fs,FRegister ft)1224 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
1225   CHECK(!IsR6());
1226   CHECK(IsUint<3>(cc)) << cc;
1227   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
1228 }
1229 
ColtS(FRegister fs,FRegister ft)1230 void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
1231   ColtS(0, fs, ft);
1232 }
1233 
ColtS(int cc,FRegister fs,FRegister ft)1234 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
1235   CHECK(!IsR6());
1236   CHECK(IsUint<3>(cc)) << cc;
1237   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
1238 }
1239 
CultS(FRegister fs,FRegister ft)1240 void MipsAssembler::CultS(FRegister fs, FRegister ft) {
1241   CultS(0, fs, ft);
1242 }
1243 
CultS(int cc,FRegister fs,FRegister ft)1244 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
1245   CHECK(!IsR6());
1246   CHECK(IsUint<3>(cc)) << cc;
1247   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
1248 }
1249 
ColeS(FRegister fs,FRegister ft)1250 void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
1251   ColeS(0, fs, ft);
1252 }
1253 
ColeS(int cc,FRegister fs,FRegister ft)1254 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
1255   CHECK(!IsR6());
1256   CHECK(IsUint<3>(cc)) << cc;
1257   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
1258 }
1259 
CuleS(FRegister fs,FRegister ft)1260 void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
1261   CuleS(0, fs, ft);
1262 }
1263 
CuleS(int cc,FRegister fs,FRegister ft)1264 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
1265   CHECK(!IsR6());
1266   CHECK(IsUint<3>(cc)) << cc;
1267   DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
1268 }
1269 
CunD(FRegister fs,FRegister ft)1270 void MipsAssembler::CunD(FRegister fs, FRegister ft) {
1271   CunD(0, fs, ft);
1272 }
1273 
CunD(int cc,FRegister fs,FRegister ft)1274 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
1275   CHECK(!IsR6());
1276   CHECK(IsUint<3>(cc)) << cc;
1277   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
1278 }
1279 
CeqD(FRegister fs,FRegister ft)1280 void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
1281   CeqD(0, fs, ft);
1282 }
1283 
CeqD(int cc,FRegister fs,FRegister ft)1284 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
1285   CHECK(!IsR6());
1286   CHECK(IsUint<3>(cc)) << cc;
1287   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
1288 }
1289 
CueqD(FRegister fs,FRegister ft)1290 void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
1291   CueqD(0, fs, ft);
1292 }
1293 
CueqD(int cc,FRegister fs,FRegister ft)1294 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
1295   CHECK(!IsR6());
1296   CHECK(IsUint<3>(cc)) << cc;
1297   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
1298 }
1299 
ColtD(FRegister fs,FRegister ft)1300 void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
1301   ColtD(0, fs, ft);
1302 }
1303 
ColtD(int cc,FRegister fs,FRegister ft)1304 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
1305   CHECK(!IsR6());
1306   CHECK(IsUint<3>(cc)) << cc;
1307   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
1308 }
1309 
CultD(FRegister fs,FRegister ft)1310 void MipsAssembler::CultD(FRegister fs, FRegister ft) {
1311   CultD(0, fs, ft);
1312 }
1313 
CultD(int cc,FRegister fs,FRegister ft)1314 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
1315   CHECK(!IsR6());
1316   CHECK(IsUint<3>(cc)) << cc;
1317   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
1318 }
1319 
ColeD(FRegister fs,FRegister ft)1320 void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
1321   ColeD(0, fs, ft);
1322 }
1323 
ColeD(int cc,FRegister fs,FRegister ft)1324 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
1325   CHECK(!IsR6());
1326   CHECK(IsUint<3>(cc)) << cc;
1327   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
1328 }
1329 
CuleD(FRegister fs,FRegister ft)1330 void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
1331   CuleD(0, fs, ft);
1332 }
1333 
CuleD(int cc,FRegister fs,FRegister ft)1334 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
1335   CHECK(!IsR6());
1336   CHECK(IsUint<3>(cc)) << cc;
1337   DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
1338 }
1339 
CmpUnS(FRegister fd,FRegister fs,FRegister ft)1340 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
1341   CHECK(IsR6());
1342   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft);
1343 }
1344 
CmpEqS(FRegister fd,FRegister fs,FRegister ft)1345 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
1346   CHECK(IsR6());
1347   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft);
1348 }
1349 
CmpUeqS(FRegister fd,FRegister fs,FRegister ft)1350 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
1351   CHECK(IsR6());
1352   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft);
1353 }
1354 
CmpLtS(FRegister fd,FRegister fs,FRegister ft)1355 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
1356   CHECK(IsR6());
1357   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft);
1358 }
1359 
CmpUltS(FRegister fd,FRegister fs,FRegister ft)1360 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
1361   CHECK(IsR6());
1362   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft);
1363 }
1364 
CmpLeS(FRegister fd,FRegister fs,FRegister ft)1365 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
1366   CHECK(IsR6());
1367   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft);
1368 }
1369 
CmpUleS(FRegister fd,FRegister fs,FRegister ft)1370 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
1371   CHECK(IsR6());
1372   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft);
1373 }
1374 
CmpOrS(FRegister fd,FRegister fs,FRegister ft)1375 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
1376   CHECK(IsR6());
1377   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft);
1378 }
1379 
CmpUneS(FRegister fd,FRegister fs,FRegister ft)1380 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
1381   CHECK(IsR6());
1382   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft);
1383 }
1384 
CmpNeS(FRegister fd,FRegister fs,FRegister ft)1385 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
1386   CHECK(IsR6());
1387   DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft);
1388 }
1389 
CmpUnD(FRegister fd,FRegister fs,FRegister ft)1390 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
1391   CHECK(IsR6());
1392   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft);
1393 }
1394 
CmpEqD(FRegister fd,FRegister fs,FRegister ft)1395 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
1396   CHECK(IsR6());
1397   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft);
1398 }
1399 
CmpUeqD(FRegister fd,FRegister fs,FRegister ft)1400 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
1401   CHECK(IsR6());
1402   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft);
1403 }
1404 
CmpLtD(FRegister fd,FRegister fs,FRegister ft)1405 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
1406   CHECK(IsR6());
1407   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft);
1408 }
1409 
CmpUltD(FRegister fd,FRegister fs,FRegister ft)1410 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
1411   CHECK(IsR6());
1412   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft);
1413 }
1414 
CmpLeD(FRegister fd,FRegister fs,FRegister ft)1415 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
1416   CHECK(IsR6());
1417   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft);
1418 }
1419 
CmpUleD(FRegister fd,FRegister fs,FRegister ft)1420 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
1421   CHECK(IsR6());
1422   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft);
1423 }
1424 
CmpOrD(FRegister fd,FRegister fs,FRegister ft)1425 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
1426   CHECK(IsR6());
1427   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft);
1428 }
1429 
CmpUneD(FRegister fd,FRegister fs,FRegister ft)1430 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
1431   CHECK(IsR6());
1432   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft);
1433 }
1434 
CmpNeD(FRegister fd,FRegister fs,FRegister ft)1435 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
1436   CHECK(IsR6());
1437   DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft);
1438 }
1439 
Movf(Register rd,Register rs,int cc)1440 void MipsAssembler::Movf(Register rd, Register rs, int cc) {
1441   CHECK(!IsR6());
1442   CHECK(IsUint<3>(cc)) << cc;
1443   DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc);
1444 }
1445 
Movt(Register rd,Register rs,int cc)1446 void MipsAssembler::Movt(Register rd, Register rs, int cc) {
1447   CHECK(!IsR6());
1448   CHECK(IsUint<3>(cc)) << cc;
1449   DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc);
1450 }
1451 
MovfS(FRegister fd,FRegister fs,int cc)1452 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
1453   CHECK(!IsR6());
1454   CHECK(IsUint<3>(cc)) << cc;
1455   DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
1456 }
1457 
MovfD(FRegister fd,FRegister fs,int cc)1458 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
1459   CHECK(!IsR6());
1460   CHECK(IsUint<3>(cc)) << cc;
1461   DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
1462 }
1463 
MovtS(FRegister fd,FRegister fs,int cc)1464 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
1465   CHECK(!IsR6());
1466   CHECK(IsUint<3>(cc)) << cc;
1467   DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1468                  fd,
1469                  fs,
1470                  cc);
1471 }
1472 
MovtD(FRegister fd,FRegister fs,int cc)1473 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
1474   CHECK(!IsR6());
1475   CHECK(IsUint<3>(cc)) << cc;
1476   DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
1477                  fd,
1478                  fs,
1479                  cc);
1480 }
1481 
MovzS(FRegister fd,FRegister fs,Register rt)1482 void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
1483   CHECK(!IsR6());
1484   DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1485 }
1486 
MovzD(FRegister fd,FRegister fs,Register rt)1487 void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
1488   CHECK(!IsR6());
1489   DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
1490 }
1491 
MovnS(FRegister fd,FRegister fs,Register rt)1492 void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
1493   CHECK(!IsR6());
1494   DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1495 }
1496 
MovnD(FRegister fd,FRegister fs,Register rt)1497 void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
1498   CHECK(!IsR6());
1499   DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
1500 }
1501 
SelS(FRegister fd,FRegister fs,FRegister ft)1502 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
1503   CHECK(IsR6());
1504   DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft);
1505 }
1506 
SelD(FRegister fd,FRegister fs,FRegister ft)1507 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
1508   CHECK(IsR6());
1509   DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft);
1510 }
1511 
SeleqzS(FRegister fd,FRegister fs,FRegister ft)1512 void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
1513   CHECK(IsR6());
1514   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft);
1515 }
1516 
SeleqzD(FRegister fd,FRegister fs,FRegister ft)1517 void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
1518   CHECK(IsR6());
1519   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft);
1520 }
1521 
SelnezS(FRegister fd,FRegister fs,FRegister ft)1522 void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
1523   CHECK(IsR6());
1524   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft);
1525 }
1526 
SelnezD(FRegister fd,FRegister fs,FRegister ft)1527 void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
1528   CHECK(IsR6());
1529   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft);
1530 }
1531 
ClassS(FRegister fd,FRegister fs)1532 void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
1533   CHECK(IsR6());
1534   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
1535 }
1536 
ClassD(FRegister fd,FRegister fs)1537 void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
1538   CHECK(IsR6());
1539   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
1540 }
1541 
MinS(FRegister fd,FRegister fs,FRegister ft)1542 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
1543   CHECK(IsR6());
1544   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft);
1545 }
1546 
MinD(FRegister fd,FRegister fs,FRegister ft)1547 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
1548   CHECK(IsR6());
1549   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft);
1550 }
1551 
MaxS(FRegister fd,FRegister fs,FRegister ft)1552 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
1553   CHECK(IsR6());
1554   DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft);
1555 }
1556 
MaxD(FRegister fd,FRegister fs,FRegister ft)1557 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
1558   CHECK(IsR6());
1559   DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft);
1560 }
1561 
TruncLS(FRegister fd,FRegister fs)1562 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
1563   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
1564 }
1565 
TruncLD(FRegister fd,FRegister fs)1566 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
1567   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
1568 }
1569 
TruncWS(FRegister fd,FRegister fs)1570 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
1571   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
1572 }
1573 
TruncWD(FRegister fd,FRegister fs)1574 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
1575   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
1576 }
1577 
Cvtsw(FRegister fd,FRegister fs)1578 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
1579   DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1580 }
1581 
Cvtdw(FRegister fd,FRegister fs)1582 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
1583   DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1584 }
1585 
Cvtsd(FRegister fd,FRegister fs)1586 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
1587   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1588 }
1589 
Cvtds(FRegister fd,FRegister fs)1590 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
1591   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1592 }
1593 
Cvtsl(FRegister fd,FRegister fs)1594 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
1595   DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
1596 }
1597 
Cvtdl(FRegister fd,FRegister fs)1598 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
1599   DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
1600 }
1601 
FloorWS(FRegister fd,FRegister fs)1602 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
1603   DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
1604 }
1605 
FloorWD(FRegister fd,FRegister fs)1606 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
1607   DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
1608 }
1609 
Mfc1(Register rt,FRegister fs)1610 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
1611   DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1612                rt,
1613                fs);
1614 }
1615 
Mtc1(Register rt,FRegister fs)1616 void MipsAssembler::Mtc1(Register rt, FRegister fs) {
1617   DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1618                fs,
1619                rt);
1620 }
1621 
Mfhc1(Register rt,FRegister fs)1622 void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
1623   DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1624                rt,
1625                fs);
1626 }
1627 
Mthc1(Register rt,FRegister fs)1628 void MipsAssembler::Mthc1(Register rt, FRegister fs) {
1629   DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
1630                fs,
1631                rt);
1632 }
1633 
MoveFromFpuHigh(Register rt,FRegister fs)1634 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
1635   if (Is32BitFPU()) {
1636     CHECK_EQ(fs % 2, 0) << fs;
1637     Mfc1(rt, static_cast<FRegister>(fs + 1));
1638   } else {
1639     Mfhc1(rt, fs);
1640   }
1641 }
1642 
MoveToFpuHigh(Register rt,FRegister fs)1643 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
1644   if (Is32BitFPU()) {
1645     CHECK_EQ(fs % 2, 0) << fs;
1646     Mtc1(rt, static_cast<FRegister>(fs + 1));
1647   } else {
1648     Mthc1(rt, fs);
1649   }
1650 }
1651 
Lwc1(FRegister ft,Register rs,uint16_t imm16)1652 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
1653   DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs);
1654 }
1655 
Ldc1(FRegister ft,Register rs,uint16_t imm16)1656 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
1657   DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs);
1658 }
1659 
Swc1(FRegister ft,Register rs,uint16_t imm16)1660 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
1661   DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs);
1662 }
1663 
Sdc1(FRegister ft,Register rs,uint16_t imm16)1664 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
1665   DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs);
1666 }
1667 
Break()1668 void MipsAssembler::Break() {
1669   DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD));
1670 }
1671 
Nop()1672 void MipsAssembler::Nop() {
1673   DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0));
1674 }
1675 
NopIfNoReordering()1676 void MipsAssembler::NopIfNoReordering() {
1677   if (!reordering_) {
1678     Nop();
1679   }
1680 }
1681 
Move(Register rd,Register rs)1682 void MipsAssembler::Move(Register rd, Register rs) {
1683   Or(rd, rs, ZERO);
1684 }
1685 
Clear(Register rd)1686 void MipsAssembler::Clear(Register rd) {
1687   Move(rd, ZERO);
1688 }
1689 
Not(Register rd,Register rs)1690 void MipsAssembler::Not(Register rd, Register rs) {
1691   Nor(rd, rs, ZERO);
1692 }
1693 
Push(Register rs)1694 void MipsAssembler::Push(Register rs) {
1695   IncreaseFrameSize(kMipsWordSize);
1696   Sw(rs, SP, 0);
1697 }
1698 
Pop(Register rd)1699 void MipsAssembler::Pop(Register rd) {
1700   Lw(rd, SP, 0);
1701   DecreaseFrameSize(kMipsWordSize);
1702 }
1703 
PopAndReturn(Register rd,Register rt)1704 void MipsAssembler::PopAndReturn(Register rd, Register rt) {
1705   bool reordering = SetReorder(false);
1706   Lw(rd, SP, 0);
1707   Jr(rt);
1708   DecreaseFrameSize(kMipsWordSize);  // Single instruction in delay slot.
1709   SetReorder(reordering);
1710 }
1711 
LoadConst32(Register rd,int32_t value)1712 void MipsAssembler::LoadConst32(Register rd, int32_t value) {
1713   if (IsUint<16>(value)) {
1714     // Use OR with (unsigned) immediate to encode 16b unsigned int.
1715     Ori(rd, ZERO, value);
1716   } else if (IsInt<16>(value)) {
1717     // Use ADD with (signed) immediate to encode 16b signed int.
1718     Addiu(rd, ZERO, value);
1719   } else {
1720     Lui(rd, High16Bits(value));
1721     if (value & 0xFFFF)
1722       Ori(rd, rd, Low16Bits(value));
1723   }
1724 }
1725 
LoadConst64(Register reg_hi,Register reg_lo,int64_t value)1726 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) {
1727   uint32_t low = Low32Bits(value);
1728   uint32_t high = High32Bits(value);
1729   LoadConst32(reg_lo, low);
1730   if (high != low) {
1731     LoadConst32(reg_hi, high);
1732   } else {
1733     Move(reg_hi, reg_lo);
1734   }
1735 }
1736 
LoadSConst32(FRegister r,int32_t value,Register temp)1737 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
1738   if (value == 0) {
1739     temp = ZERO;
1740   } else {
1741     LoadConst32(temp, value);
1742   }
1743   Mtc1(temp, r);
1744 }
1745 
LoadDConst64(FRegister rd,int64_t value,Register temp)1746 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) {
1747   uint32_t low = Low32Bits(value);
1748   uint32_t high = High32Bits(value);
1749   if (low == 0) {
1750     Mtc1(ZERO, rd);
1751   } else {
1752     LoadConst32(temp, low);
1753     Mtc1(temp, rd);
1754   }
1755   if (high == 0) {
1756     MoveToFpuHigh(ZERO, rd);
1757   } else {
1758     LoadConst32(temp, high);
1759     MoveToFpuHigh(temp, rd);
1760   }
1761 }
1762 
Addiu32(Register rt,Register rs,int32_t value,Register temp)1763 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
1764   CHECK_NE(rs, temp);  // Must not overwrite the register `rs` while loading `value`.
1765   if (IsInt<16>(value)) {
1766     Addiu(rt, rs, value);
1767   } else if (IsR6()) {
1768     int16_t high = High16Bits(value);
1769     int16_t low = Low16Bits(value);
1770     high += (low < 0) ? 1 : 0;  // Account for sign extension in addiu.
1771     if (low != 0) {
1772       Aui(temp, rs, high);
1773       Addiu(rt, temp, low);
1774     } else {
1775       Aui(rt, rs, high);
1776     }
1777   } else {
1778     // Do not load the whole 32-bit `value` if it can be represented as
1779     // a sum of two 16-bit signed values. This can save an instruction.
1780     constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
1781     constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
1782     if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
1783       Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
1784       Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
1785     } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
1786       Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
1787       Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
1788     } else {
1789       // Now that all shorter options have been exhausted, load the full 32-bit value.
1790       LoadConst32(temp, value);
1791       Addu(rt, rs, temp);
1792     }
1793   }
1794 }
1795 
InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,MipsAssembler::Branch::Type short_type,MipsAssembler::Branch::Type long_type)1796 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size,
1797                                             MipsAssembler::Branch::Type short_type,
1798                                             MipsAssembler::Branch::Type long_type) {
1799   type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
1800 }
1801 
InitializeType(Type initial_type,bool is_r6)1802 void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
1803   OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
1804   if (is_r6) {
1805     // R6
1806     switch (initial_type) {
1807       case kLabel:
1808         CHECK(!IsResolved());
1809         type_ = kR6Label;
1810         break;
1811       case kLiteral:
1812         CHECK(!IsResolved());
1813         type_ = kR6Literal;
1814         break;
1815       case kCall:
1816         InitShortOrLong(offset_size, kR6Call, kR6LongCall);
1817         break;
1818       case kCondBranch:
1819         switch (condition_) {
1820           case kUncond:
1821             InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
1822             break;
1823           case kCondEQZ:
1824           case kCondNEZ:
1825             // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
1826             type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
1827             break;
1828           default:
1829             InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
1830             break;
1831         }
1832         break;
1833       default:
1834         LOG(FATAL) << "Unexpected branch type " << initial_type;
1835         UNREACHABLE();
1836     }
1837   } else {
1838     // R2
1839     switch (initial_type) {
1840       case kLabel:
1841         CHECK(!IsResolved());
1842         type_ = kLabel;
1843         break;
1844       case kLiteral:
1845         CHECK(!IsResolved());
1846         type_ = kLiteral;
1847         break;
1848       case kCall:
1849         InitShortOrLong(offset_size, kCall, kLongCall);
1850         break;
1851       case kCondBranch:
1852         switch (condition_) {
1853           case kUncond:
1854             InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
1855             break;
1856           default:
1857             InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
1858             break;
1859         }
1860         break;
1861       default:
1862         LOG(FATAL) << "Unexpected branch type " << initial_type;
1863         UNREACHABLE();
1864     }
1865   }
1866   old_type_ = type_;
1867 }
1868 
IsNop(BranchCondition condition,Register lhs,Register rhs)1869 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) {
1870   switch (condition) {
1871     case kCondLT:
1872     case kCondGT:
1873     case kCondNE:
1874     case kCondLTU:
1875       return lhs == rhs;
1876     default:
1877       return false;
1878   }
1879 }
1880 
IsUncond(BranchCondition condition,Register lhs,Register rhs)1881 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) {
1882   switch (condition) {
1883     case kUncond:
1884       return true;
1885     case kCondGE:
1886     case kCondLE:
1887     case kCondEQ:
1888     case kCondGEU:
1889       return lhs == rhs;
1890     default:
1891       return false;
1892   }
1893 }
1894 
Branch(bool is_r6,uint32_t location,uint32_t target,bool is_call)1895 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call)
1896     : old_location_(location),
1897       location_(location),
1898       target_(target),
1899       lhs_reg_(0),
1900       rhs_reg_(0),
1901       condition_(kUncond),
1902       delayed_instruction_(kUnfilledDelaySlot) {
1903   InitializeType((is_call ? kCall : kCondBranch), is_r6);
1904 }
1905 
Branch(bool is_r6,uint32_t location,uint32_t target,MipsAssembler::BranchCondition condition,Register lhs_reg,Register rhs_reg)1906 MipsAssembler::Branch::Branch(bool is_r6,
1907                               uint32_t location,
1908                               uint32_t target,
1909                               MipsAssembler::BranchCondition condition,
1910                               Register lhs_reg,
1911                               Register rhs_reg)
1912     : old_location_(location),
1913       location_(location),
1914       target_(target),
1915       lhs_reg_(lhs_reg),
1916       rhs_reg_(rhs_reg),
1917       condition_(condition),
1918       delayed_instruction_(kUnfilledDelaySlot) {
1919   CHECK_NE(condition, kUncond);
1920   switch (condition) {
1921     case kCondLT:
1922     case kCondGE:
1923     case kCondLE:
1924     case kCondGT:
1925     case kCondLTU:
1926     case kCondGEU:
1927       // We don't support synthetic R2 branches (preceded with slt[u]) at this level
1928       // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
1929       // We leave this up to the caller.
1930       CHECK(is_r6);
1931       FALLTHROUGH_INTENDED;
1932     case kCondEQ:
1933     case kCondNE:
1934       // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1935       // To compare with 0, use dedicated kCond*Z conditions.
1936       CHECK_NE(lhs_reg, ZERO);
1937       CHECK_NE(rhs_reg, ZERO);
1938       break;
1939     case kCondLTZ:
1940     case kCondGEZ:
1941     case kCondLEZ:
1942     case kCondGTZ:
1943     case kCondEQZ:
1944     case kCondNEZ:
1945       // Require registers other than 0 not only for R6, but also for R2 to catch errors.
1946       CHECK_NE(lhs_reg, ZERO);
1947       CHECK_EQ(rhs_reg, ZERO);
1948       break;
1949     case kCondF:
1950     case kCondT:
1951       CHECK_EQ(rhs_reg, ZERO);
1952       break;
1953     case kUncond:
1954       UNREACHABLE();
1955   }
1956   CHECK(!IsNop(condition, lhs_reg, rhs_reg));
1957   if (IsUncond(condition, lhs_reg, rhs_reg)) {
1958     // Branch condition is always true, make the branch unconditional.
1959     condition_ = kUncond;
1960   }
1961   InitializeType(kCondBranch, is_r6);
1962 }
1963 
Branch(bool is_r6,uint32_t location,Register dest_reg,Register base_reg,Type label_or_literal_type)1964 MipsAssembler::Branch::Branch(bool is_r6,
1965                               uint32_t location,
1966                               Register dest_reg,
1967                               Register base_reg,
1968                               Type label_or_literal_type)
1969     : old_location_(location),
1970       location_(location),
1971       target_(kUnresolved),
1972       lhs_reg_(dest_reg),
1973       rhs_reg_(base_reg),
1974       condition_(kUncond),
1975       delayed_instruction_(kUnfilledDelaySlot) {
1976   CHECK_NE(dest_reg, ZERO);
1977   if (is_r6) {
1978     CHECK_EQ(base_reg, ZERO);
1979   } else {
1980     CHECK_NE(base_reg, ZERO);
1981   }
1982   InitializeType(label_or_literal_type, is_r6);
1983 }
1984 
OppositeCondition(MipsAssembler::BranchCondition cond)1985 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
1986     MipsAssembler::BranchCondition cond) {
1987   switch (cond) {
1988     case kCondLT:
1989       return kCondGE;
1990     case kCondGE:
1991       return kCondLT;
1992     case kCondLE:
1993       return kCondGT;
1994     case kCondGT:
1995       return kCondLE;
1996     case kCondLTZ:
1997       return kCondGEZ;
1998     case kCondGEZ:
1999       return kCondLTZ;
2000     case kCondLEZ:
2001       return kCondGTZ;
2002     case kCondGTZ:
2003       return kCondLEZ;
2004     case kCondEQ:
2005       return kCondNE;
2006     case kCondNE:
2007       return kCondEQ;
2008     case kCondEQZ:
2009       return kCondNEZ;
2010     case kCondNEZ:
2011       return kCondEQZ;
2012     case kCondLTU:
2013       return kCondGEU;
2014     case kCondGEU:
2015       return kCondLTU;
2016     case kCondF:
2017       return kCondT;
2018     case kCondT:
2019       return kCondF;
2020     case kUncond:
2021       LOG(FATAL) << "Unexpected branch condition " << cond;
2022   }
2023   UNREACHABLE();
2024 }
2025 
GetType() const2026 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const {
2027   return type_;
2028 }
2029 
GetCondition() const2030 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const {
2031   return condition_;
2032 }
2033 
GetLeftRegister() const2034 Register MipsAssembler::Branch::GetLeftRegister() const {
2035   return static_cast<Register>(lhs_reg_);
2036 }
2037 
GetRightRegister() const2038 Register MipsAssembler::Branch::GetRightRegister() const {
2039   return static_cast<Register>(rhs_reg_);
2040 }
2041 
GetTarget() const2042 uint32_t MipsAssembler::Branch::GetTarget() const {
2043   return target_;
2044 }
2045 
GetLocation() const2046 uint32_t MipsAssembler::Branch::GetLocation() const {
2047   return location_;
2048 }
2049 
GetOldLocation() const2050 uint32_t MipsAssembler::Branch::GetOldLocation() const {
2051   return old_location_;
2052 }
2053 
GetPrecedingInstructionLength(Type type) const2054 uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const {
2055   // Short branches with delay slots always consist of two instructions, the branch
2056   // and the delay slot, irrespective of whether the delay slot is filled with a
2057   // useful instruction or not.
2058   // Long composite branches may have a length longer by one instruction than
2059   // specified in branch_info_[].length. This happens when an instruction is taken
2060   // to fill the short branch delay slot, but the branch eventually becomes long
2061   // and formally has no delay slot to fill. This instruction is placed at the
2062   // beginning of the long composite branch and this needs to be accounted for in
2063   // the branch length and the location of the offset encoded in the branch.
2064   switch (type) {
2065     case kLongUncondBranch:
2066     case kLongCondBranch:
2067     case kLongCall:
2068     case kR6LongCondBranch:
2069       return (delayed_instruction_ != kUnfilledDelaySlot &&
2070           delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0;
2071     default:
2072       return 0;
2073   }
2074 }
2075 
GetPrecedingInstructionSize(Type type) const2076 uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const {
2077   return GetPrecedingInstructionLength(type) * sizeof(uint32_t);
2078 }
2079 
GetLength() const2080 uint32_t MipsAssembler::Branch::GetLength() const {
2081   return GetPrecedingInstructionLength(type_) + branch_info_[type_].length;
2082 }
2083 
GetOldLength() const2084 uint32_t MipsAssembler::Branch::GetOldLength() const {
2085   return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length;
2086 }
2087 
GetSize() const2088 uint32_t MipsAssembler::Branch::GetSize() const {
2089   return GetLength() * sizeof(uint32_t);
2090 }
2091 
GetOldSize() const2092 uint32_t MipsAssembler::Branch::GetOldSize() const {
2093   return GetOldLength() * sizeof(uint32_t);
2094 }
2095 
GetEndLocation() const2096 uint32_t MipsAssembler::Branch::GetEndLocation() const {
2097   return GetLocation() + GetSize();
2098 }
2099 
GetOldEndLocation() const2100 uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
2101   return GetOldLocation() + GetOldSize();
2102 }
2103 
IsLong() const2104 bool MipsAssembler::Branch::IsLong() const {
2105   switch (type_) {
2106     // R2 short branches.
2107     case kUncondBranch:
2108     case kCondBranch:
2109     case kCall:
2110     // R2 near label.
2111     case kLabel:
2112     // R2 near literal.
2113     case kLiteral:
2114     // R6 short branches.
2115     case kR6UncondBranch:
2116     case kR6CondBranch:
2117     case kR6Call:
2118     // R6 near label.
2119     case kR6Label:
2120     // R6 near literal.
2121     case kR6Literal:
2122       return false;
2123     // R2 long branches.
2124     case kLongUncondBranch:
2125     case kLongCondBranch:
2126     case kLongCall:
2127     // R2 far label.
2128     case kFarLabel:
2129     // R2 far literal.
2130     case kFarLiteral:
2131     // R6 long branches.
2132     case kR6LongUncondBranch:
2133     case kR6LongCondBranch:
2134     case kR6LongCall:
2135     // R6 far label.
2136     case kR6FarLabel:
2137     // R6 far literal.
2138     case kR6FarLiteral:
2139       return true;
2140   }
2141   UNREACHABLE();
2142 }
2143 
IsResolved() const2144 bool MipsAssembler::Branch::IsResolved() const {
2145   return target_ != kUnresolved;
2146 }
2147 
GetOffsetSize() const2148 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
2149   OffsetBits offset_size =
2150       (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
2151           ? kOffset23
2152           : branch_info_[type_].offset_size;
2153   return offset_size;
2154 }
2155 
GetOffsetSizeNeeded(uint32_t location,uint32_t target)2156 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location,
2157                                                                              uint32_t target) {
2158   // For unresolved targets assume the shortest encoding
2159   // (later it will be made longer if needed).
2160   if (target == kUnresolved)
2161     return kOffset16;
2162   int64_t distance = static_cast<int64_t>(target) - location;
2163   // To simplify calculations in composite branches consisting of multiple instructions
2164   // bump up the distance by a value larger than the max byte size of a composite branch.
2165   distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize;
2166   if (IsInt<kOffset16>(distance))
2167     return kOffset16;
2168   else if (IsInt<kOffset18>(distance))
2169     return kOffset18;
2170   else if (IsInt<kOffset21>(distance))
2171     return kOffset21;
2172   else if (IsInt<kOffset23>(distance))
2173     return kOffset23;
2174   else if (IsInt<kOffset28>(distance))
2175     return kOffset28;
2176   return kOffset32;
2177 }
2178 
Resolve(uint32_t target)2179 void MipsAssembler::Branch::Resolve(uint32_t target) {
2180   target_ = target;
2181 }
2182 
Relocate(uint32_t expand_location,uint32_t delta)2183 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
2184   if (location_ > expand_location) {
2185     location_ += delta;
2186   }
2187   if (!IsResolved()) {
2188     return;  // Don't know the target yet.
2189   }
2190   if (target_ > expand_location) {
2191     target_ += delta;
2192   }
2193 }
2194 
PromoteToLong()2195 void MipsAssembler::Branch::PromoteToLong() {
2196   switch (type_) {
2197     // R2 short branches.
2198     case kUncondBranch:
2199       type_ = kLongUncondBranch;
2200       break;
2201     case kCondBranch:
2202       type_ = kLongCondBranch;
2203       break;
2204     case kCall:
2205       type_ = kLongCall;
2206       break;
2207     // R2 near label.
2208     case kLabel:
2209       type_ = kFarLabel;
2210       break;
2211     // R2 near literal.
2212     case kLiteral:
2213       type_ = kFarLiteral;
2214       break;
2215     // R6 short branches.
2216     case kR6UncondBranch:
2217       type_ = kR6LongUncondBranch;
2218       break;
2219     case kR6CondBranch:
2220       type_ = kR6LongCondBranch;
2221       break;
2222     case kR6Call:
2223       type_ = kR6LongCall;
2224       break;
2225     // R6 near label.
2226     case kR6Label:
2227       type_ = kR6FarLabel;
2228       break;
2229     // R6 near literal.
2230     case kR6Literal:
2231       type_ = kR6FarLiteral;
2232       break;
2233     default:
2234       // Note: 'type_' is already long.
2235       break;
2236   }
2237   CHECK(IsLong());
2238 }
2239 
GetBranchLocationOrPcRelBase(const MipsAssembler::Branch * branch) const2240 uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
2241   switch (branch->GetType()) {
2242     case Branch::kLabel:
2243     case Branch::kFarLabel:
2244     case Branch::kLiteral:
2245     case Branch::kFarLiteral:
2246       return GetLabelLocation(&pc_rel_base_label_);
2247     default:
2248       return branch->GetLocation();
2249   }
2250 }
2251 
PromoteIfNeeded(uint32_t location,uint32_t max_short_distance)2252 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
2253   // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
2254   // `this->GetLocation()` for everything else.
2255   // If the branch is still unresolved or already long, nothing to do.
2256   if (IsLong() || !IsResolved()) {
2257     return 0;
2258   }
2259   // Promote the short branch to long if the offset size is too small
2260   // to hold the distance between location and target_.
2261   if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) {
2262     PromoteToLong();
2263     uint32_t old_size = GetOldSize();
2264     uint32_t new_size = GetSize();
2265     CHECK_GT(new_size, old_size);
2266     return new_size - old_size;
2267   }
2268   // The following logic is for debugging/testing purposes.
2269   // Promote some short branches to long when it's not really required.
2270   if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
2271     int64_t distance = static_cast<int64_t>(target_) - location;
2272     distance = (distance >= 0) ? distance : -distance;
2273     if (distance >= max_short_distance) {
2274       PromoteToLong();
2275       uint32_t old_size = GetOldSize();
2276       uint32_t new_size = GetSize();
2277       CHECK_GT(new_size, old_size);
2278       return new_size - old_size;
2279     }
2280   }
2281   return 0;
2282 }
2283 
GetOffsetLocation() const2284 uint32_t MipsAssembler::Branch::GetOffsetLocation() const {
2285   return location_ + GetPrecedingInstructionSize(type_) +
2286       branch_info_[type_].instr_offset * sizeof(uint32_t);
2287 }
2288 
GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch * branch) const2289 uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
2290   switch (branch->GetType()) {
2291     case Branch::kLabel:
2292     case Branch::kFarLabel:
2293     case Branch::kLiteral:
2294     case Branch::kFarLiteral:
2295       return GetLabelLocation(&pc_rel_base_label_);
2296     default:
2297       return branch->GetOffsetLocation() +
2298           Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
2299   }
2300 }
2301 
GetOffset(uint32_t location) const2302 uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
2303   // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
2304   // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)`
2305   // for everything else.
2306   CHECK(IsResolved());
2307   uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
2308   // Calculate the byte distance between instructions and also account for
2309   // different PC-relative origins.
2310   uint32_t offset = target_ - location;
2311   // Prepare the offset for encoding into the instruction(s).
2312   offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift;
2313   return offset;
2314 }
2315 
GetBranch(uint32_t branch_id)2316 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) {
2317   CHECK_LT(branch_id, branches_.size());
2318   return &branches_[branch_id];
2319 }
2320 
GetBranch(uint32_t branch_id) const2321 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const {
2322   CHECK_LT(branch_id, branches_.size());
2323   return &branches_[branch_id];
2324 }
2325 
Bind(MipsLabel * label)2326 void MipsAssembler::Bind(MipsLabel* label) {
2327   CHECK(!label->IsBound());
2328   uint32_t bound_pc = buffer_.Size();
2329 
2330   // Make the delay slot FSM aware of the new label.
2331   DsFsmLabel();
2332 
2333   // Walk the list of branches referring to and preceding this label.
2334   // Store the previously unknown target addresses in them.
2335   while (label->IsLinked()) {
2336     uint32_t branch_id = label->Position();
2337     Branch* branch = GetBranch(branch_id);
2338     branch->Resolve(bound_pc);
2339 
2340     uint32_t branch_location = branch->GetLocation();
2341     // Extract the location of the previous branch in the list (walking the list backwards;
2342     // the previous branch ID was stored in the space reserved for this branch).
2343     uint32_t prev = buffer_.Load<uint32_t>(branch_location);
2344 
2345     // On to the previous branch in the list...
2346     label->position_ = prev;
2347   }
2348 
2349   // Now make the label object contain its own location (relative to the end of the preceding
2350   // branch, if any; it will be used by the branches referring to and following this label).
2351   label->prev_branch_id_plus_one_ = branches_.size();
2352   if (label->prev_branch_id_plus_one_) {
2353     uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2354     const Branch* branch = GetBranch(branch_id);
2355     bound_pc -= branch->GetEndLocation();
2356   }
2357   label->BindTo(bound_pc);
2358 }
2359 
GetLabelLocation(const MipsLabel * label) const2360 uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const {
2361   CHECK(label->IsBound());
2362   uint32_t target = label->Position();
2363   if (label->prev_branch_id_plus_one_) {
2364     // Get label location based on the branch preceding it.
2365     uint32_t branch_id = label->prev_branch_id_plus_one_ - 1;
2366     const Branch* branch = GetBranch(branch_id);
2367     target += branch->GetEndLocation();
2368   }
2369   return target;
2370 }
2371 
GetAdjustedPosition(uint32_t old_position)2372 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) {
2373   // We can reconstruct the adjustment by going through all the branches from the beginning
2374   // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
2375   // with increasing old_position, we can use the data from last AdjustedPosition() to
2376   // continue where we left off and the whole loop should be O(m+n) where m is the number
2377   // of positions to adjust and n is the number of branches.
2378   if (old_position < last_old_position_) {
2379     last_position_adjustment_ = 0;
2380     last_old_position_ = 0;
2381     last_branch_id_ = 0;
2382   }
2383   while (last_branch_id_ != branches_.size()) {
2384     const Branch* branch = GetBranch(last_branch_id_);
2385     if (branch->GetLocation() >= old_position + last_position_adjustment_) {
2386       break;
2387     }
2388     last_position_adjustment_ += branch->GetSize() - branch->GetOldSize();
2389     ++last_branch_id_;
2390   }
2391   last_old_position_ = old_position;
2392   return old_position + last_position_adjustment_;
2393 }
2394 
BindPcRelBaseLabel()2395 void MipsAssembler::BindPcRelBaseLabel() {
2396   Bind(&pc_rel_base_label_);
2397 }
2398 
GetPcRelBaseLabelLocation() const2399 uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const {
2400   return GetLabelLocation(&pc_rel_base_label_);
2401 }
2402 
FinalizeLabeledBranch(MipsLabel * label)2403 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) {
2404   uint32_t length = branches_.back().GetLength();
2405   // Commit the last branch target label (if any).
2406   DsFsmCommitLabel();
2407   if (!label->IsBound()) {
2408     // Branch forward (to a following label), distance is unknown.
2409     // The first branch forward will contain 0, serving as the terminator of
2410     // the list of forward-reaching branches.
2411     Emit(label->position_);
2412     // Nothing for the delay slot (yet).
2413     DsFsmInstrNop(0);
2414     length--;
2415     // Now make the label object point to this branch
2416     // (this forms a linked list of branches preceding this label).
2417     uint32_t branch_id = branches_.size() - 1;
2418     label->LinkTo(branch_id);
2419   }
2420   // Reserve space for the branch.
2421   while (length--) {
2422     Nop();
2423   }
2424 }
2425 
CanHaveDelayedInstruction(const DelaySlot & delay_slot) const2426 bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const {
2427   if (delay_slot.instruction_ == 0) {
2428     // NOP or no instruction for the delay slot.
2429     return false;
2430   }
2431   switch (type_) {
2432     // R2 unconditional branches.
2433     case kUncondBranch:
2434     case kLongUncondBranch:
2435       // There are no register interdependencies.
2436       return true;
2437 
2438     // R2 calls.
2439     case kCall:
2440     case kLongCall:
2441       // Instructions depending on or modifying RA should not be moved into delay slots
2442       // of branches modifying RA.
2443       return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0;
2444 
2445     // R2 conditional branches.
2446     case kCondBranch:
2447     case kLongCondBranch:
2448       switch (condition_) {
2449         // Branches with one GPR source.
2450         case kCondLTZ:
2451         case kCondGEZ:
2452         case kCondLEZ:
2453         case kCondGTZ:
2454         case kCondEQZ:
2455         case kCondNEZ:
2456           return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0;
2457 
2458         // Branches with two GPR sources.
2459         case kCondEQ:
2460         case kCondNE:
2461           return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
2462 
2463         // Branches with one FPU condition code source.
2464         case kCondF:
2465         case kCondT:
2466           return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0;
2467 
2468         default:
2469           // We don't support synthetic R2 branches (preceded with slt[u]) at this level
2470           // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >).
2471           LOG(FATAL) << "Unexpected branch condition " << condition_;
2472           UNREACHABLE();
2473       }
2474 
2475     // R6 unconditional branches.
2476     case kR6UncondBranch:
2477     case kR6LongUncondBranch:
2478     // R6 calls.
2479     case kR6Call:
2480     case kR6LongCall:
2481       // There are no delay slots.
2482       return false;
2483 
2484     // R6 conditional branches.
2485     case kR6CondBranch:
2486     case kR6LongCondBranch:
2487       switch (condition_) {
2488         // Branches with one FPU register source.
2489         case kCondF:
2490         case kCondT:
2491           return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0;
2492         // Others have a forbidden slot instead of a delay slot.
2493         default:
2494           return false;
2495       }
2496 
2497     // Literals.
2498     default:
2499       LOG(FATAL) << "Unexpected branch type " << type_;
2500       UNREACHABLE();
2501   }
2502 }
2503 
GetDelayedInstruction() const2504 uint32_t MipsAssembler::Branch::GetDelayedInstruction() const {
2505   return delayed_instruction_;
2506 }
2507 
SetDelayedInstruction(uint32_t instruction)2508 void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction) {
2509   CHECK_NE(instruction, kUnfilledDelaySlot);
2510   CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot);
2511   delayed_instruction_ = instruction;
2512 }
2513 
DecrementLocations()2514 void MipsAssembler::Branch::DecrementLocations() {
2515   // We first create a branch object, which gets its type and locations initialized,
2516   // and then we check if the branch can actually have the preceding instruction moved
2517   // into its delay slot. If it can, the branch locations need to be decremented.
2518   //
2519   // We could make the check before creating the branch object and avoid the location
2520   // adjustment, but the check is cleaner when performed on an initialized branch
2521   // object.
2522   //
2523   // If the branch is backwards (to a previously bound label), reducing the locations
2524   // cannot cause a short branch to exceed its offset range because the offset reduces.
2525   // And this is not at all a problem for a long branch backwards.
2526   //
2527   // If the branch is forward (not linked to any label yet), reducing the locations
2528   // is harmless. The branch will be promoted to long if needed when the target is known.
2529   CHECK_EQ(location_, old_location_);
2530   CHECK_GE(old_location_, sizeof(uint32_t));
2531   old_location_ -= sizeof(uint32_t);
2532   location_ = old_location_;
2533 }
2534 
MoveInstructionToDelaySlot(Branch & branch)2535 void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
2536   if (branch.CanHaveDelayedInstruction(delay_slot_)) {
2537     // The last instruction cannot be used in a different delay slot,
2538     // do not commit the label before it (if any).
2539     DsFsmDropLabel();
2540     // Remove the last emitted instruction.
2541     size_t size = buffer_.Size();
2542     CHECK_GE(size, sizeof(uint32_t));
2543     size -= sizeof(uint32_t);
2544     CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_);
2545     buffer_.Resize(size);
2546     // Attach it to the branch and adjust the branch locations.
2547     branch.DecrementLocations();
2548     branch.SetDelayedInstruction(delay_slot_.instruction_);
2549   } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) {
2550     // If reordefing is disabled, prevent absorption of the target instruction.
2551     branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot);
2552   }
2553 }
2554 
Buncond(MipsLabel * label)2555 void MipsAssembler::Buncond(MipsLabel* label) {
2556   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
2557   branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ false);
2558   MoveInstructionToDelaySlot(branches_.back());
2559   FinalizeLabeledBranch(label);
2560 }
2561 
Bcond(MipsLabel * label,BranchCondition condition,Register lhs,Register rhs)2562 void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
2563   // If lhs = rhs, this can be a NOP.
2564   if (Branch::IsNop(condition, lhs, rhs)) {
2565     return;
2566   }
2567   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
2568   branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
2569   MoveInstructionToDelaySlot(branches_.back());
2570   FinalizeLabeledBranch(label);
2571 }
2572 
Call(MipsLabel * label)2573 void MipsAssembler::Call(MipsLabel* label) {
2574   uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
2575   branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ true);
2576   MoveInstructionToDelaySlot(branches_.back());
2577   FinalizeLabeledBranch(label);
2578 }
2579 
LoadLabelAddress(Register dest_reg,Register base_reg,MipsLabel * label)2580 void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
2581   // Label address loads are treated as pseudo branches since they require very similar handling.
2582   DCHECK(!label->IsBound());
2583   branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
2584   FinalizeLabeledBranch(label);
2585 }
2586 
NewLiteral(size_t size,const uint8_t * data)2587 Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
2588   DCHECK(size == 4u || size == 8u) << size;
2589   literals_.emplace_back(size, data);
2590   return &literals_.back();
2591 }
2592 
LoadLiteral(Register dest_reg,Register base_reg,Literal * literal)2593 void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) {
2594   // Literal loads are treated as pseudo branches since they require very similar handling.
2595   DCHECK_EQ(literal->GetSize(), 4u);
2596   MipsLabel* label = literal->GetLabel();
2597   DCHECK(!label->IsBound());
2598   branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
2599   FinalizeLabeledBranch(label);
2600 }
2601 
CreateJumpTable(std::vector<MipsLabel * > && labels)2602 JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
2603   jump_tables_.emplace_back(std::move(labels));
2604   JumpTable* table = &jump_tables_.back();
2605   DCHECK(!table->GetLabel()->IsBound());
2606   return table;
2607 }
2608 
EmitLiterals()2609 void MipsAssembler::EmitLiterals() {
2610   if (!literals_.empty()) {
2611     // We don't support byte and half-word literals.
2612     // TODO: proper alignment for 64-bit literals when they're implemented.
2613     for (Literal& literal : literals_) {
2614       MipsLabel* label = literal.GetLabel();
2615       Bind(label);
2616       AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2617       DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
2618       for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
2619         buffer_.Emit<uint8_t>(literal.GetData()[i]);
2620       }
2621     }
2622   }
2623 }
2624 
ReserveJumpTableSpace()2625 void MipsAssembler::ReserveJumpTableSpace() {
2626   if (!jump_tables_.empty()) {
2627     for (JumpTable& table : jump_tables_) {
2628       MipsLabel* label = table.GetLabel();
2629       Bind(label);
2630 
2631       // Bulk ensure capacity, as this may be large.
2632       size_t orig_size = buffer_.Size();
2633       size_t required_capacity = orig_size + table.GetSize();
2634       if (required_capacity > buffer_.Capacity()) {
2635         buffer_.ExtendCapacity(required_capacity);
2636       }
2637 #ifndef NDEBUG
2638       buffer_.has_ensured_capacity_ = true;
2639 #endif
2640 
2641       // Fill the space with dummy data as the data is not final
2642       // until the branches have been promoted. And we shouldn't
2643       // be moving uninitialized data during branch promotion.
2644       for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
2645         buffer_.Emit<uint32_t>(0x1abe1234u);
2646       }
2647 
2648 #ifndef NDEBUG
2649       buffer_.has_ensured_capacity_ = false;
2650 #endif
2651     }
2652   }
2653 }
2654 
EmitJumpTables()2655 void MipsAssembler::EmitJumpTables() {
2656   if (!jump_tables_.empty()) {
2657     CHECK(!overwriting_);
2658     // Switch from appending instructions at the end of the buffer to overwriting
2659     // existing instructions (here, jump tables) in the buffer.
2660     overwriting_ = true;
2661 
2662     for (JumpTable& table : jump_tables_) {
2663       MipsLabel* table_label = table.GetLabel();
2664       uint32_t start = GetLabelLocation(table_label);
2665       overwrite_location_ = start;
2666 
2667       for (MipsLabel* target : table.GetData()) {
2668         CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
2669         // The table will contain target addresses relative to the table start.
2670         uint32_t offset = GetLabelLocation(target) - start;
2671         Emit(offset);
2672       }
2673     }
2674 
2675     overwriting_ = false;
2676   }
2677 }
2678 
PromoteBranches()2679 void MipsAssembler::PromoteBranches() {
2680   // Promote short branches to long as necessary.
2681   bool changed;
2682   do {
2683     changed = false;
2684     for (auto& branch : branches_) {
2685       CHECK(branch.IsResolved());
2686       uint32_t base = GetBranchLocationOrPcRelBase(&branch);
2687       uint32_t delta = branch.PromoteIfNeeded(base);
2688       // If this branch has been promoted and needs to expand in size,
2689       // relocate all branches by the expansion size.
2690       if (delta) {
2691         changed = true;
2692         uint32_t expand_location = branch.GetLocation();
2693         for (auto& branch2 : branches_) {
2694           branch2.Relocate(expand_location, delta);
2695         }
2696       }
2697     }
2698   } while (changed);
2699 
2700   // Account for branch expansion by resizing the code buffer
2701   // and moving the code in it to its final location.
2702   size_t branch_count = branches_.size();
2703   if (branch_count > 0) {
2704     // Resize.
2705     Branch& last_branch = branches_[branch_count - 1];
2706     uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation();
2707     uint32_t old_size = buffer_.Size();
2708     buffer_.Resize(old_size + size_delta);
2709     // Move the code residing between branch placeholders.
2710     uint32_t end = old_size;
2711     for (size_t i = branch_count; i > 0; ) {
2712       Branch& branch = branches_[--i];
2713       CHECK_GE(end, branch.GetOldEndLocation());
2714       uint32_t size = end - branch.GetOldEndLocation();
2715       buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size);
2716       end = branch.GetOldLocation();
2717     }
2718   }
2719 }
2720 
2721 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
2722 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
2723   // R2 short branches.
2724   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kUncondBranch
2725   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCondBranch
2726   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCall
2727   // R2 near label.
2728   {  1, 0, 0, MipsAssembler::Branch::kOffset16, 0 },  // kLabel
2729   // R2 near literal.
2730   {  1, 0, 0, MipsAssembler::Branch::kOffset16, 0 },  // kLiteral
2731   // R2 long branches.
2732   {  9, 3, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongUncondBranch
2733   { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCondBranch
2734   {  6, 1, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCall
2735   // R2 far label.
2736   {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kFarLabel
2737   // R2 far literal.
2738   {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kFarLiteral
2739   // R6 short branches.
2740   {  1, 0, 1, MipsAssembler::Branch::kOffset28, 2 },  // kR6UncondBranch
2741   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kR6CondBranch
2742                                                       // Exception: kOffset23 for beqzc/bnezc.
2743   {  1, 0, 1, MipsAssembler::Branch::kOffset28, 2 },  // kR6Call
2744   // R6 near label.
2745   {  1, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Label
2746   // R6 near literal.
2747   {  1, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Literal
2748   // R6 long branches.
2749   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongUncondBranch
2750   {  3, 1, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCondBranch
2751   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCall
2752   // R6 far label.
2753   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6FarLabel
2754   // R6 far literal.
2755   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6FarLiteral
2756 };
2757 
2758 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
EmitBranch(MipsAssembler::Branch * branch)2759 void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
2760   CHECK_EQ(overwriting_, true);
2761   overwrite_location_ = branch->GetLocation();
2762   uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch));
2763   BranchCondition condition = branch->GetCondition();
2764   Register lhs = branch->GetLeftRegister();
2765   Register rhs = branch->GetRightRegister();
2766   uint32_t delayed_instruction = branch->GetDelayedInstruction();
2767   switch (branch->GetType()) {
2768     // R2 short branches.
2769     case Branch::kUncondBranch:
2770       if (delayed_instruction == Branch::kUnfillableDelaySlot) {
2771         // The branch was created when reordering was disabled, do not absorb the target
2772         // instruction.
2773         delayed_instruction = 0;  // NOP.
2774       } else if (delayed_instruction == Branch::kUnfilledDelaySlot) {
2775         // Try to absorb the target instruction into the delay slot.
2776         delayed_instruction = 0;  // NOP.
2777         // Incrementing the signed 16-bit offset past the target instruction must not
2778         // cause overflow into the negative subrange, check for the max offset.
2779         if (offset != 0x7FFF) {
2780           uint32_t target = branch->GetTarget();
2781           if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) {
2782             delayed_instruction = buffer_.Load<uint32_t>(target);
2783             offset++;
2784           }
2785         }
2786       }
2787       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2788       B(offset);
2789       Emit(delayed_instruction);
2790       break;
2791     case Branch::kCondBranch:
2792       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2793       if (delayed_instruction == Branch::kUnfilledDelaySlot) {
2794         delayed_instruction = 0;  // NOP.
2795       }
2796       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2797       EmitBcondR2(condition, lhs, rhs, offset);
2798       Emit(delayed_instruction);
2799       break;
2800     case Branch::kCall:
2801       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2802       if (delayed_instruction == Branch::kUnfilledDelaySlot) {
2803         delayed_instruction = 0;  // NOP.
2804       }
2805       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2806       Bal(offset);
2807       Emit(delayed_instruction);
2808       break;
2809 
2810     // R2 near label.
2811     case Branch::kLabel:
2812       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2813       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2814       Addiu(lhs, rhs, offset);
2815       break;
2816     // R2 near literal.
2817     case Branch::kLiteral:
2818       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2819       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2820       Lw(lhs, rhs, offset);
2821       break;
2822 
2823     // R2 long branches.
2824     case Branch::kLongUncondBranch:
2825       // To get the value of the PC register we need to use the NAL instruction.
2826       // NAL clobbers the RA register. However, RA must be preserved if the
2827       // method is compiled without the entry/exit sequences that would take care
2828       // of preserving RA (typically, leaf methods don't preserve RA explicitly).
2829       // So, we need to preserve RA in some temporary storage ourselves. The AT
2830       // register can't be used for this because we need it to load a constant
2831       // which will be added to the value that NAL stores in RA. And we can't
2832       // use T9 for this in the context of the JNI compiler, which uses it
2833       // as a scratch register (see InterproceduralScratchRegister()).
2834       // If we were to add a 32-bit constant to RA using two ADDIU instructions,
2835       // we'd also need to use the ROTR instruction, which requires no less than
2836       // MIPSR2.
2837       // Perhaps, we could use T8 or one of R2's multiplier/divider registers
2838       // (LO or HI) or even a floating-point register, but that doesn't seem
2839       // like a nice solution. We may want this to work on both R6 and pre-R6.
2840       // For now simply use the stack for RA. This should be OK since for the
2841       // vast majority of code a short PC-relative branch is sufficient.
2842       // TODO: can this be improved?
2843       // TODO: consider generation of a shorter sequence when we know that RA
2844       // is explicitly preserved by the method entry/exit code.
2845       if (delayed_instruction != Branch::kUnfilledDelaySlot &&
2846           delayed_instruction != Branch::kUnfillableDelaySlot) {
2847         Emit(delayed_instruction);
2848       }
2849       Push(RA);
2850       Nal();
2851       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2852       Lui(AT, High16Bits(offset));
2853       Ori(AT, AT, Low16Bits(offset));
2854       Addu(AT, AT, RA);
2855       Lw(RA, SP, 0);
2856       Jr(AT);
2857       DecreaseFrameSize(kMipsWordSize);
2858       break;
2859     case Branch::kLongCondBranch:
2860       // The comment on case 'Branch::kLongUncondBranch' applies here as well.
2861       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2862       if (delayed_instruction != Branch::kUnfilledDelaySlot) {
2863         Emit(delayed_instruction);
2864       }
2865       // Note: the opposite condition branch encodes 8 as the distance, which is equal to the
2866       // number of instructions skipped:
2867       // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR).
2868       EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8);
2869       Push(RA);
2870       Nal();
2871       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2872       Lui(AT, High16Bits(offset));
2873       Ori(AT, AT, Low16Bits(offset));
2874       Addu(AT, AT, RA);
2875       Lw(RA, SP, 0);
2876       Jr(AT);
2877       DecreaseFrameSize(kMipsWordSize);
2878       break;
2879     case Branch::kLongCall:
2880       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2881       if (delayed_instruction != Branch::kUnfilledDelaySlot) {
2882         Emit(delayed_instruction);
2883       }
2884       Nal();
2885       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2886       Lui(AT, High16Bits(offset));
2887       Ori(AT, AT, Low16Bits(offset));
2888       Addu(AT, AT, RA);
2889       Jalr(AT);
2890       Nop();
2891       break;
2892 
2893     // R2 far label.
2894     case Branch::kFarLabel:
2895       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2896       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2897       Lui(AT, High16Bits(offset));
2898       Ori(AT, AT, Low16Bits(offset));
2899       Addu(lhs, AT, rhs);
2900       break;
2901     // R2 far literal.
2902     case Branch::kFarLiteral:
2903       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2904       offset += (offset & 0x8000) << 1;  // Account for sign extension in lw.
2905       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2906       Lui(AT, High16Bits(offset));
2907       Addu(AT, AT, rhs);
2908       Lw(lhs, AT, Low16Bits(offset));
2909       break;
2910 
2911     // R6 short branches.
2912     case Branch::kR6UncondBranch:
2913       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2914       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2915       Bc(offset);
2916       break;
2917     case Branch::kR6CondBranch:
2918       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2919       EmitBcondR6(condition, lhs, rhs, offset);
2920       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2921       if (delayed_instruction != Branch::kUnfilledDelaySlot) {
2922         Emit(delayed_instruction);
2923       } else {
2924         // TODO: improve by filling the forbidden slot (IFF this is
2925         // a forbidden and not a delay slot).
2926         Nop();
2927       }
2928       break;
2929     case Branch::kR6Call:
2930       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2931       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2932       Balc(offset);
2933       break;
2934 
2935     // R6 near label.
2936     case Branch::kR6Label:
2937       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2938       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2939       Addiupc(lhs, offset);
2940       break;
2941     // R6 near literal.
2942     case Branch::kR6Literal:
2943       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2944       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2945       Lwpc(lhs, offset);
2946       break;
2947 
2948     // R6 long branches.
2949     case Branch::kR6LongUncondBranch:
2950       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2951       offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
2952       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2953       Auipc(AT, High16Bits(offset));
2954       Jic(AT, Low16Bits(offset));
2955       break;
2956     case Branch::kR6LongCondBranch:
2957       DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot);
2958       if (delayed_instruction != Branch::kUnfilledDelaySlot) {
2959         Emit(delayed_instruction);
2960       }
2961       EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
2962       offset += (offset & 0x8000) << 1;  // Account for sign extension in jic.
2963       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2964       Auipc(AT, High16Bits(offset));
2965       Jic(AT, Low16Bits(offset));
2966       break;
2967     case Branch::kR6LongCall:
2968       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2969       offset += (offset & 0x8000) << 1;  // Account for sign extension in jialc.
2970       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2971       Auipc(AT, High16Bits(offset));
2972       Jialc(AT, Low16Bits(offset));
2973       break;
2974 
2975     // R6 far label.
2976     case Branch::kR6FarLabel:
2977       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2978       offset += (offset & 0x8000) << 1;  // Account for sign extension in addiu.
2979       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2980       Auipc(AT, High16Bits(offset));
2981       Addiu(lhs, AT, Low16Bits(offset));
2982       break;
2983     // R6 far literal.
2984     case Branch::kR6FarLiteral:
2985       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
2986       offset += (offset & 0x8000) << 1;  // Account for sign extension in lw.
2987       CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
2988       Auipc(AT, High16Bits(offset));
2989       Lw(lhs, AT, Low16Bits(offset));
2990       break;
2991   }
2992   CHECK_EQ(overwrite_location_, branch->GetEndLocation());
2993   CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
2994 }
2995 
B(MipsLabel * label)2996 void MipsAssembler::B(MipsLabel* label) {
2997   Buncond(label);
2998 }
2999 
Bal(MipsLabel * label)3000 void MipsAssembler::Bal(MipsLabel* label) {
3001   Call(label);
3002 }
3003 
Beq(Register rs,Register rt,MipsLabel * label)3004 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
3005   Bcond(label, kCondEQ, rs, rt);
3006 }
3007 
Bne(Register rs,Register rt,MipsLabel * label)3008 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
3009   Bcond(label, kCondNE, rs, rt);
3010 }
3011 
Beqz(Register rt,MipsLabel * label)3012 void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
3013   Bcond(label, kCondEQZ, rt);
3014 }
3015 
Bnez(Register rt,MipsLabel * label)3016 void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
3017   Bcond(label, kCondNEZ, rt);
3018 }
3019 
Bltz(Register rt,MipsLabel * label)3020 void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
3021   Bcond(label, kCondLTZ, rt);
3022 }
3023 
Bgez(Register rt,MipsLabel * label)3024 void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
3025   Bcond(label, kCondGEZ, rt);
3026 }
3027 
Blez(Register rt,MipsLabel * label)3028 void MipsAssembler::Blez(Register rt, MipsLabel* label) {
3029   Bcond(label, kCondLEZ, rt);
3030 }
3031 
Bgtz(Register rt,MipsLabel * label)3032 void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
3033   Bcond(label, kCondGTZ, rt);
3034 }
3035 
CanExchangeWithSlt(Register rs,Register rt) const3036 bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
3037   // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u]
3038   // instruction because either slt[u] depends on `rs` or `rt` or the following
3039   // conditional branch depends on AT set by slt[u].
3040   // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
3041   // because slt[u] changes AT.
3042   return (delay_slot_.instruction_ != 0 &&
3043       (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
3044       (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0);
3045 }
3046 
ExchangeWithSlt(const DelaySlot & forwarded_slot)3047 void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
3048   // Exchange the last two instructions in the assembler buffer.
3049   size_t size = buffer_.Size();
3050   CHECK_GE(size, 2 * sizeof(uint32_t));
3051   size_t pos1 = size - 2 * sizeof(uint32_t);
3052   size_t pos2 = size - sizeof(uint32_t);
3053   uint32_t instr1 = buffer_.Load<uint32_t>(pos1);
3054   uint32_t instr2 = buffer_.Load<uint32_t>(pos2);
3055   CHECK_EQ(instr1, forwarded_slot.instruction_);
3056   CHECK_EQ(instr2, delay_slot_.instruction_);
3057   buffer_.Store<uint32_t>(pos1, instr2);
3058   buffer_.Store<uint32_t>(pos2, instr1);
3059   // Set the current delay slot information to that of the last instruction
3060   // in the buffer.
3061   delay_slot_ = forwarded_slot;
3062 }
3063 
GenerateSltForCondBranch(bool unsigned_slt,Register rs,Register rt)3064 void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) {
3065   // If possible, exchange the slt[u] instruction with the preceding instruction,
3066   // so it can fill the delay slot.
3067   DelaySlot forwarded_slot = delay_slot_;
3068   bool exchange = CanExchangeWithSlt(rs, rt);
3069   if (exchange) {
3070     // The last instruction cannot be used in a different delay slot,
3071     // do not commit the label before it (if any).
3072     DsFsmDropLabel();
3073   }
3074   if (unsigned_slt) {
3075     Sltu(AT, rs, rt);
3076   } else {
3077     Slt(AT, rs, rt);
3078   }
3079   if (exchange) {
3080     ExchangeWithSlt(forwarded_slot);
3081   }
3082 }
3083 
Blt(Register rs,Register rt,MipsLabel * label)3084 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
3085   if (IsR6()) {
3086     Bcond(label, kCondLT, rs, rt);
3087   } else if (!Branch::IsNop(kCondLT, rs, rt)) {
3088     // Synthesize the instruction (not available on R2).
3089     GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
3090     Bnez(AT, label);
3091   }
3092 }
3093 
Bge(Register rs,Register rt,MipsLabel * label)3094 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
3095   if (IsR6()) {
3096     Bcond(label, kCondGE, rs, rt);
3097   } else if (Branch::IsUncond(kCondGE, rs, rt)) {
3098     B(label);
3099   } else {
3100     // Synthesize the instruction (not available on R2).
3101     GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
3102     Beqz(AT, label);
3103   }
3104 }
3105 
Bltu(Register rs,Register rt,MipsLabel * label)3106 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
3107   if (IsR6()) {
3108     Bcond(label, kCondLTU, rs, rt);
3109   } else if (!Branch::IsNop(kCondLTU, rs, rt)) {
3110     // Synthesize the instruction (not available on R2).
3111     GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
3112     Bnez(AT, label);
3113   }
3114 }
3115 
Bgeu(Register rs,Register rt,MipsLabel * label)3116 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
3117   if (IsR6()) {
3118     Bcond(label, kCondGEU, rs, rt);
3119   } else if (Branch::IsUncond(kCondGEU, rs, rt)) {
3120     B(label);
3121   } else {
3122     // Synthesize the instruction (not available on R2).
3123     GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
3124     Beqz(AT, label);
3125   }
3126 }
3127 
Bc1f(MipsLabel * label)3128 void MipsAssembler::Bc1f(MipsLabel* label) {
3129   Bc1f(0, label);
3130 }
3131 
Bc1f(int cc,MipsLabel * label)3132 void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
3133   CHECK(IsUint<3>(cc)) << cc;
3134   Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
3135 }
3136 
Bc1t(MipsLabel * label)3137 void MipsAssembler::Bc1t(MipsLabel* label) {
3138   Bc1t(0, label);
3139 }
3140 
Bc1t(int cc,MipsLabel * label)3141 void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
3142   CHECK(IsUint<3>(cc)) << cc;
3143   Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
3144 }
3145 
Bc1eqz(FRegister ft,MipsLabel * label)3146 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
3147   Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
3148 }
3149 
Bc1nez(FRegister ft,MipsLabel * label)3150 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
3151   Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
3152 }
3153 
AdjustBaseAndOffset(Register & base,int32_t & offset,bool is_doubleword,bool is_float)3154 void MipsAssembler::AdjustBaseAndOffset(Register& base,
3155                                         int32_t& offset,
3156                                         bool is_doubleword,
3157                                         bool is_float) {
3158   // This method is used to adjust the base register and offset pair
3159   // for a load/store when the offset doesn't fit into int16_t.
3160   // It is assumed that `base + offset` is sufficiently aligned for memory
3161   // operands that are machine word in size or smaller. For doubleword-sized
3162   // operands it's assumed that `base` is a multiple of 8, while `offset`
3163   // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
3164   // and spilled variables on the stack accessed relative to the stack
3165   // pointer register).
3166   // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
3167   CHECK_NE(base, AT);  // Must not overwrite the register `base` while loading `offset`.
3168 
3169   bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
3170   bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
3171 
3172   // IsInt<16> must be passed a signed value, hence the static cast below.
3173   if (IsInt<16>(offset) &&
3174       (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
3175     // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
3176     return;
3177   }
3178 
3179   // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
3180   uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
3181 
3182   // Do not load the whole 32-bit `offset` if it can be represented as
3183   // a sum of two 16-bit signed offsets. This can save an instruction or two.
3184   // To simplify matters, only do this for a symmetric range of offsets from
3185   // about -64KB to about +64KB, allowing further addition of 4 when accessing
3186   // 64-bit variables with two 32-bit accesses.
3187   constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8;  // Max int16_t that's a multiple of 8.
3188   constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
3189   if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
3190     Addiu(AT, base, kMinOffsetForSimpleAdjustment);
3191     offset -= kMinOffsetForSimpleAdjustment;
3192   } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
3193     Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
3194     offset += kMinOffsetForSimpleAdjustment;
3195   } else if (IsR6()) {
3196     // On R6 take advantage of the aui instruction, e.g.:
3197     //   aui   AT, base, offset_high
3198     //   lw    reg_lo, offset_low(AT)
3199     //   lw    reg_hi, (offset_low+4)(AT)
3200     // or when offset_low+4 overflows int16_t:
3201     //   aui   AT, base, offset_high
3202     //   addiu AT, AT, 8
3203     //   lw    reg_lo, (offset_low-8)(AT)
3204     //   lw    reg_hi, (offset_low-4)(AT)
3205     int16_t offset_high = High16Bits(offset);
3206     int16_t offset_low = Low16Bits(offset);
3207     offset_high += (offset_low < 0) ? 1 : 0;  // Account for offset sign extension in load/store.
3208     Aui(AT, base, offset_high);
3209     if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
3210       // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
3211       Addiu(AT, AT, kMipsDoublewordSize);
3212       offset_low -= kMipsDoublewordSize;
3213     }
3214     offset = offset_low;
3215   } else {
3216     // Do not load the whole 32-bit `offset` if it can be represented as
3217     // a sum of three 16-bit signed offsets. This can save an instruction.
3218     // To simplify matters, only do this for a symmetric range of offsets from
3219     // about -96KB to about +96KB, allowing further addition of 4 when accessing
3220     // 64-bit variables with two 32-bit accesses.
3221     constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
3222     constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
3223     if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
3224       Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
3225       Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
3226       offset -= kMinOffsetForMediumAdjustment;
3227     } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
3228       Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
3229       Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
3230       offset += kMinOffsetForMediumAdjustment;
3231     } else {
3232       // Now that all shorter options have been exhausted, load the full 32-bit offset.
3233       int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
3234       LoadConst32(AT, loaded_offset);
3235       Addu(AT, AT, base);
3236       offset -= loaded_offset;
3237     }
3238   }
3239   base = AT;
3240 
3241   CHECK(IsInt<16>(offset));
3242   if (two_accesses) {
3243     CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
3244   }
3245   CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
3246 }
3247 
LoadFromOffset(LoadOperandType type,Register reg,Register base,int32_t offset)3248 void MipsAssembler::LoadFromOffset(LoadOperandType type,
3249                                    Register reg,
3250                                    Register base,
3251                                    int32_t offset) {
3252   LoadFromOffset<>(type, reg, base, offset);
3253 }
3254 
LoadSFromOffset(FRegister reg,Register base,int32_t offset)3255 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
3256   LoadSFromOffset<>(reg, base, offset);
3257 }
3258 
LoadDFromOffset(FRegister reg,Register base,int32_t offset)3259 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
3260   LoadDFromOffset<>(reg, base, offset);
3261 }
3262 
EmitLoad(ManagedRegister m_dst,Register src_register,int32_t src_offset,size_t size)3263 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
3264                              size_t size) {
3265   MipsManagedRegister dst = m_dst.AsMips();
3266   if (dst.IsNoRegister()) {
3267     CHECK_EQ(0u, size) << dst;
3268   } else if (dst.IsCoreRegister()) {
3269     CHECK_EQ(kMipsWordSize, size) << dst;
3270     LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
3271   } else if (dst.IsRegisterPair()) {
3272     CHECK_EQ(kMipsDoublewordSize, size) << dst;
3273     LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset);
3274   } else if (dst.IsFRegister()) {
3275     if (size == kMipsWordSize) {
3276       LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
3277     } else {
3278       CHECK_EQ(kMipsDoublewordSize, size) << dst;
3279       LoadDFromOffset(dst.AsFRegister(), src_register, src_offset);
3280     }
3281   } else if (dst.IsDRegister()) {
3282     CHECK_EQ(kMipsDoublewordSize, size) << dst;
3283     LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset);
3284   }
3285 }
3286 
StoreToOffset(StoreOperandType type,Register reg,Register base,int32_t offset)3287 void MipsAssembler::StoreToOffset(StoreOperandType type,
3288                                   Register reg,
3289                                   Register base,
3290                                   int32_t offset) {
3291   StoreToOffset<>(type, reg, base, offset);
3292 }
3293 
StoreSToOffset(FRegister reg,Register base,int32_t offset)3294 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
3295   StoreSToOffset<>(reg, base, offset);
3296 }
3297 
StoreDToOffset(FRegister reg,Register base,int32_t offset)3298 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
3299   StoreDToOffset<>(reg, base, offset);
3300 }
3301 
DWARFReg(Register reg)3302 static dwarf::Reg DWARFReg(Register reg) {
3303   return dwarf::Reg::MipsCore(static_cast<int>(reg));
3304 }
3305 
3306 constexpr size_t kFramePointerSize = 4;
3307 
BuildFrame(size_t frame_size,ManagedRegister method_reg,ArrayRef<const ManagedRegister> callee_save_regs,const ManagedRegisterEntrySpills & entry_spills)3308 void MipsAssembler::BuildFrame(size_t frame_size,
3309                                ManagedRegister method_reg,
3310                                ArrayRef<const ManagedRegister> callee_save_regs,
3311                                const ManagedRegisterEntrySpills& entry_spills) {
3312   CHECK_ALIGNED(frame_size, kStackAlignment);
3313   DCHECK(!overwriting_);
3314 
3315   // Increase frame to required size.
3316   IncreaseFrameSize(frame_size);
3317 
3318   // Push callee saves and return address.
3319   int stack_offset = frame_size - kFramePointerSize;
3320   StoreToOffset(kStoreWord, RA, SP, stack_offset);
3321   cfi_.RelOffset(DWARFReg(RA), stack_offset);
3322   for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
3323     stack_offset -= kFramePointerSize;
3324     Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
3325     StoreToOffset(kStoreWord, reg, SP, stack_offset);
3326     cfi_.RelOffset(DWARFReg(reg), stack_offset);
3327   }
3328 
3329   // Write out Method*.
3330   StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
3331 
3332   // Write out entry spills.
3333   int32_t offset = frame_size + kFramePointerSize;
3334   for (size_t i = 0; i < entry_spills.size(); ++i) {
3335     MipsManagedRegister reg = entry_spills.at(i).AsMips();
3336     if (reg.IsNoRegister()) {
3337       ManagedRegisterSpill spill = entry_spills.at(i);
3338       offset += spill.getSize();
3339     } else if (reg.IsCoreRegister()) {
3340       StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
3341       offset += kMipsWordSize;
3342     } else if (reg.IsFRegister()) {
3343       StoreSToOffset(reg.AsFRegister(), SP, offset);
3344       offset += kMipsWordSize;
3345     } else if (reg.IsDRegister()) {
3346       StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset);
3347       offset += kMipsDoublewordSize;
3348     }
3349   }
3350 }
3351 
RemoveFrame(size_t frame_size,ArrayRef<const ManagedRegister> callee_save_regs)3352 void MipsAssembler::RemoveFrame(size_t frame_size,
3353                                 ArrayRef<const ManagedRegister> callee_save_regs) {
3354   CHECK_ALIGNED(frame_size, kStackAlignment);
3355   DCHECK(!overwriting_);
3356   cfi_.RememberState();
3357 
3358   // Pop callee saves and return address.
3359   int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
3360   for (size_t i = 0; i < callee_save_regs.size(); ++i) {
3361     Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
3362     LoadFromOffset(kLoadWord, reg, SP, stack_offset);
3363     cfi_.Restore(DWARFReg(reg));
3364     stack_offset += kFramePointerSize;
3365   }
3366   LoadFromOffset(kLoadWord, RA, SP, stack_offset);
3367   cfi_.Restore(DWARFReg(RA));
3368 
3369   // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
3370   bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
3371   bool reordering = SetReorder(false);
3372   if (exchange) {
3373     // Jump to the return address.
3374     Jr(RA);
3375     // Decrease frame to required size.
3376     DecreaseFrameSize(frame_size);  // Single instruction in delay slot.
3377   } else {
3378     // Decrease frame to required size.
3379     DecreaseFrameSize(frame_size);
3380     // Jump to the return address.
3381     Jr(RA);
3382     Nop();  // In delay slot.
3383   }
3384   SetReorder(reordering);
3385 
3386   // The CFI should be restored for any code that follows the exit block.
3387   cfi_.RestoreState();
3388   cfi_.DefCFAOffset(frame_size);
3389 }
3390 
IncreaseFrameSize(size_t adjust)3391 void MipsAssembler::IncreaseFrameSize(size_t adjust) {
3392   CHECK_ALIGNED(adjust, kFramePointerSize);
3393   Addiu32(SP, SP, -adjust);
3394   cfi_.AdjustCFAOffset(adjust);
3395   if (overwriting_) {
3396     cfi_.OverrideDelayedPC(overwrite_location_);
3397   }
3398 }
3399 
DecreaseFrameSize(size_t adjust)3400 void MipsAssembler::DecreaseFrameSize(size_t adjust) {
3401   CHECK_ALIGNED(adjust, kFramePointerSize);
3402   Addiu32(SP, SP, adjust);
3403   cfi_.AdjustCFAOffset(-adjust);
3404   if (overwriting_) {
3405     cfi_.OverrideDelayedPC(overwrite_location_);
3406   }
3407 }
3408 
Store(FrameOffset dest,ManagedRegister msrc,size_t size)3409 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
3410   MipsManagedRegister src = msrc.AsMips();
3411   if (src.IsNoRegister()) {
3412     CHECK_EQ(0u, size);
3413   } else if (src.IsCoreRegister()) {
3414     CHECK_EQ(kMipsWordSize, size);
3415     StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
3416   } else if (src.IsRegisterPair()) {
3417     CHECK_EQ(kMipsDoublewordSize, size);
3418     StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
3419     StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
3420                   SP, dest.Int32Value() + kMipsWordSize);
3421   } else if (src.IsFRegister()) {
3422     if (size == kMipsWordSize) {
3423       StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
3424     } else {
3425       CHECK_EQ(kMipsDoublewordSize, size);
3426       StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value());
3427     }
3428   } else if (src.IsDRegister()) {
3429     CHECK_EQ(kMipsDoublewordSize, size);
3430     StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value());
3431   }
3432 }
3433 
StoreRef(FrameOffset dest,ManagedRegister msrc)3434 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
3435   MipsManagedRegister src = msrc.AsMips();
3436   CHECK(src.IsCoreRegister());
3437   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
3438 }
3439 
StoreRawPtr(FrameOffset dest,ManagedRegister msrc)3440 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
3441   MipsManagedRegister src = msrc.AsMips();
3442   CHECK(src.IsCoreRegister());
3443   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
3444 }
3445 
StoreImmediateToFrame(FrameOffset dest,uint32_t imm,ManagedRegister mscratch)3446 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
3447                                           ManagedRegister mscratch) {
3448   MipsManagedRegister scratch = mscratch.AsMips();
3449   CHECK(scratch.IsCoreRegister()) << scratch;
3450   LoadConst32(scratch.AsCoreRegister(), imm);
3451   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
3452 }
3453 
StoreStackOffsetToThread(ThreadOffset32 thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)3454 void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
3455                                              FrameOffset fr_offs,
3456                                              ManagedRegister mscratch) {
3457   MipsManagedRegister scratch = mscratch.AsMips();
3458   CHECK(scratch.IsCoreRegister()) << scratch;
3459   Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
3460   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
3461                 S1, thr_offs.Int32Value());
3462 }
3463 
StoreStackPointerToThread(ThreadOffset32 thr_offs)3464 void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
3465   StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
3466 }
3467 
StoreSpanning(FrameOffset dest,ManagedRegister msrc,FrameOffset in_off,ManagedRegister mscratch)3468 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
3469                                   FrameOffset in_off, ManagedRegister mscratch) {
3470   MipsManagedRegister src = msrc.AsMips();
3471   MipsManagedRegister scratch = mscratch.AsMips();
3472   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
3473   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
3474   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
3475 }
3476 
Load(ManagedRegister mdest,FrameOffset src,size_t size)3477 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
3478   return EmitLoad(mdest, SP, src.Int32Value(), size);
3479 }
3480 
LoadFromThread(ManagedRegister mdest,ThreadOffset32 src,size_t size)3481 void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
3482   return EmitLoad(mdest, S1, src.Int32Value(), size);
3483 }
3484 
LoadRef(ManagedRegister mdest,FrameOffset src)3485 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
3486   MipsManagedRegister dest = mdest.AsMips();
3487   CHECK(dest.IsCoreRegister());
3488   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
3489 }
3490 
LoadRef(ManagedRegister mdest,ManagedRegister base,MemberOffset offs,bool unpoison_reference)3491 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
3492                             bool unpoison_reference) {
3493   MipsManagedRegister dest = mdest.AsMips();
3494   CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
3495   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
3496                  base.AsMips().AsCoreRegister(), offs.Int32Value());
3497   if (unpoison_reference) {
3498     MaybeUnpoisonHeapReference(dest.AsCoreRegister());
3499   }
3500 }
3501 
LoadRawPtr(ManagedRegister mdest,ManagedRegister base,Offset offs)3502 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) {
3503   MipsManagedRegister dest = mdest.AsMips();
3504   CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister());
3505   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
3506                  base.AsMips().AsCoreRegister(), offs.Int32Value());
3507 }
3508 
LoadRawPtrFromThread(ManagedRegister mdest,ThreadOffset32 offs)3509 void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
3510   MipsManagedRegister dest = mdest.AsMips();
3511   CHECK(dest.IsCoreRegister());
3512   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
3513 }
3514 
SignExtend(ManagedRegister,size_t)3515 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
3516   UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
3517 }
3518 
ZeroExtend(ManagedRegister,size_t)3519 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
3520   UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
3521 }
3522 
Move(ManagedRegister mdest,ManagedRegister msrc,size_t size)3523 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
3524   MipsManagedRegister dest = mdest.AsMips();
3525   MipsManagedRegister src = msrc.AsMips();
3526   if (!dest.Equals(src)) {
3527     if (dest.IsCoreRegister()) {
3528       CHECK(src.IsCoreRegister()) << src;
3529       Move(dest.AsCoreRegister(), src.AsCoreRegister());
3530     } else if (dest.IsFRegister()) {
3531       CHECK(src.IsFRegister()) << src;
3532       if (size == kMipsWordSize) {
3533         MovS(dest.AsFRegister(), src.AsFRegister());
3534       } else {
3535         CHECK_EQ(kMipsDoublewordSize, size);
3536         MovD(dest.AsFRegister(), src.AsFRegister());
3537       }
3538     } else if (dest.IsDRegister()) {
3539       CHECK(src.IsDRegister()) << src;
3540       MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow());
3541     } else {
3542       CHECK(dest.IsRegisterPair()) << dest;
3543       CHECK(src.IsRegisterPair()) << src;
3544       // Ensure that the first move doesn't clobber the input of the second.
3545       if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
3546         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
3547         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
3548       } else {
3549         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
3550         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
3551       }
3552     }
3553   }
3554 }
3555 
CopyRef(FrameOffset dest,FrameOffset src,ManagedRegister mscratch)3556 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
3557   MipsManagedRegister scratch = mscratch.AsMips();
3558   CHECK(scratch.IsCoreRegister()) << scratch;
3559   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
3560   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
3561 }
3562 
CopyRawPtrFromThread(FrameOffset fr_offs,ThreadOffset32 thr_offs,ManagedRegister mscratch)3563 void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
3564                                          ThreadOffset32 thr_offs,
3565                                          ManagedRegister mscratch) {
3566   MipsManagedRegister scratch = mscratch.AsMips();
3567   CHECK(scratch.IsCoreRegister()) << scratch;
3568   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
3569                  S1, thr_offs.Int32Value());
3570   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
3571                 SP, fr_offs.Int32Value());
3572 }
3573 
CopyRawPtrToThread(ThreadOffset32 thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)3574 void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
3575                                        FrameOffset fr_offs,
3576                                        ManagedRegister mscratch) {
3577   MipsManagedRegister scratch = mscratch.AsMips();
3578   CHECK(scratch.IsCoreRegister()) << scratch;
3579   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
3580                  SP, fr_offs.Int32Value());
3581   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
3582                 S1, thr_offs.Int32Value());
3583 }
3584 
Copy(FrameOffset dest,FrameOffset src,ManagedRegister mscratch,size_t size)3585 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
3586   MipsManagedRegister scratch = mscratch.AsMips();
3587   CHECK(scratch.IsCoreRegister()) << scratch;
3588   CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size;
3589   if (size == kMipsWordSize) {
3590     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
3591     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
3592   } else if (size == kMipsDoublewordSize) {
3593     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
3594     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
3595     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize);
3596     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize);
3597   }
3598 }
3599 
Copy(FrameOffset dest,ManagedRegister src_base,Offset src_offset,ManagedRegister mscratch,size_t size)3600 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
3601                          ManagedRegister mscratch, size_t size) {
3602   Register scratch = mscratch.AsMips().AsCoreRegister();
3603   CHECK_EQ(size, kMipsWordSize);
3604   LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
3605   StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
3606 }
3607 
Copy(ManagedRegister dest_base,Offset dest_offset,FrameOffset src,ManagedRegister mscratch,size_t size)3608 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
3609                          ManagedRegister mscratch, size_t size) {
3610   Register scratch = mscratch.AsMips().AsCoreRegister();
3611   CHECK_EQ(size, kMipsWordSize);
3612   LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
3613   StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
3614 }
3615 
Copy(FrameOffset dest ATTRIBUTE_UNUSED,FrameOffset src_base ATTRIBUTE_UNUSED,Offset src_offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)3616 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3617                          FrameOffset src_base ATTRIBUTE_UNUSED,
3618                          Offset src_offset ATTRIBUTE_UNUSED,
3619                          ManagedRegister mscratch ATTRIBUTE_UNUSED,
3620                          size_t size ATTRIBUTE_UNUSED) {
3621   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
3622 }
3623 
Copy(ManagedRegister dest,Offset dest_offset,ManagedRegister src,Offset src_offset,ManagedRegister mscratch,size_t size)3624 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
3625                          ManagedRegister src, Offset src_offset,
3626                          ManagedRegister mscratch, size_t size) {
3627   CHECK_EQ(size, kMipsWordSize);
3628   Register scratch = mscratch.AsMips().AsCoreRegister();
3629   LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
3630   StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
3631 }
3632 
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)3633 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
3634                          Offset dest_offset ATTRIBUTE_UNUSED,
3635                          FrameOffset src ATTRIBUTE_UNUSED,
3636                          Offset src_offset ATTRIBUTE_UNUSED,
3637                          ManagedRegister mscratch ATTRIBUTE_UNUSED,
3638                          size_t size ATTRIBUTE_UNUSED) {
3639   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
3640 }
3641 
MemoryBarrier(ManagedRegister)3642 void MipsAssembler::MemoryBarrier(ManagedRegister) {
3643   // TODO: sync?
3644   UNIMPLEMENTED(FATAL) << "no MIPS implementation";
3645 }
3646 
CreateHandleScopeEntry(ManagedRegister mout_reg,FrameOffset handle_scope_offset,ManagedRegister min_reg,bool null_allowed)3647 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
3648                                            FrameOffset handle_scope_offset,
3649                                            ManagedRegister min_reg,
3650                                            bool null_allowed) {
3651   MipsManagedRegister out_reg = mout_reg.AsMips();
3652   MipsManagedRegister in_reg = min_reg.AsMips();
3653   CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
3654   CHECK(out_reg.IsCoreRegister()) << out_reg;
3655   if (null_allowed) {
3656     MipsLabel null_arg;
3657     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
3658     // the address in the handle scope holding the reference.
3659     // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset).
3660     if (in_reg.IsNoRegister()) {
3661       LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
3662                      SP, handle_scope_offset.Int32Value());
3663       in_reg = out_reg;
3664     }
3665     if (!out_reg.Equals(in_reg)) {
3666       LoadConst32(out_reg.AsCoreRegister(), 0);
3667     }
3668     Beqz(in_reg.AsCoreRegister(), &null_arg);
3669     Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
3670     Bind(&null_arg);
3671   } else {
3672     Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
3673   }
3674 }
3675 
CreateHandleScopeEntry(FrameOffset out_off,FrameOffset handle_scope_offset,ManagedRegister mscratch,bool null_allowed)3676 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
3677                                            FrameOffset handle_scope_offset,
3678                                            ManagedRegister mscratch,
3679                                            bool null_allowed) {
3680   MipsManagedRegister scratch = mscratch.AsMips();
3681   CHECK(scratch.IsCoreRegister()) << scratch;
3682   if (null_allowed) {
3683     MipsLabel null_arg;
3684     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
3685     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
3686     // the address in the handle scope holding the reference.
3687     // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset).
3688     Beqz(scratch.AsCoreRegister(), &null_arg);
3689     Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
3690     Bind(&null_arg);
3691   } else {
3692     Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
3693   }
3694   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
3695 }
3696 
3697 // Given a handle scope entry, load the associated reference.
LoadReferenceFromHandleScope(ManagedRegister mout_reg,ManagedRegister min_reg)3698 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
3699                                                  ManagedRegister min_reg) {
3700   MipsManagedRegister out_reg = mout_reg.AsMips();
3701   MipsManagedRegister in_reg = min_reg.AsMips();
3702   CHECK(out_reg.IsCoreRegister()) << out_reg;
3703   CHECK(in_reg.IsCoreRegister()) << in_reg;
3704   MipsLabel null_arg;
3705   if (!out_reg.Equals(in_reg)) {
3706     LoadConst32(out_reg.AsCoreRegister(), 0);
3707   }
3708   Beqz(in_reg.AsCoreRegister(), &null_arg);
3709   LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
3710                  in_reg.AsCoreRegister(), 0);
3711   Bind(&null_arg);
3712 }
3713 
VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)3714 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
3715                                  bool could_be_null ATTRIBUTE_UNUSED) {
3716   // TODO: not validating references.
3717 }
3718 
VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,bool could_be_null ATTRIBUTE_UNUSED)3719 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
3720                                  bool could_be_null ATTRIBUTE_UNUSED) {
3721   // TODO: not validating references.
3722 }
3723 
Call(ManagedRegister mbase,Offset offset,ManagedRegister mscratch)3724 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
3725   MipsManagedRegister base = mbase.AsMips();
3726   MipsManagedRegister scratch = mscratch.AsMips();
3727   CHECK(base.IsCoreRegister()) << base;
3728   CHECK(scratch.IsCoreRegister()) << scratch;
3729   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
3730                  base.AsCoreRegister(), offset.Int32Value());
3731   Jalr(scratch.AsCoreRegister());
3732   NopIfNoReordering();
3733   // TODO: place reference map on call.
3734 }
3735 
Call(FrameOffset base,Offset offset,ManagedRegister mscratch)3736 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
3737   MipsManagedRegister scratch = mscratch.AsMips();
3738   CHECK(scratch.IsCoreRegister()) << scratch;
3739   // Call *(*(SP + base) + offset)
3740   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value());
3741   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
3742                  scratch.AsCoreRegister(), offset.Int32Value());
3743   Jalr(scratch.AsCoreRegister());
3744   NopIfNoReordering();
3745   // TODO: place reference map on call.
3746 }
3747 
CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,ManagedRegister mscratch ATTRIBUTE_UNUSED)3748 void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
3749                                    ManagedRegister mscratch ATTRIBUTE_UNUSED) {
3750   UNIMPLEMENTED(FATAL) << "no mips implementation";
3751 }
3752 
GetCurrentThread(ManagedRegister tr)3753 void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
3754   Move(tr.AsMips().AsCoreRegister(), S1);
3755 }
3756 
GetCurrentThread(FrameOffset offset,ManagedRegister mscratch ATTRIBUTE_UNUSED)3757 void MipsAssembler::GetCurrentThread(FrameOffset offset,
3758                                      ManagedRegister mscratch ATTRIBUTE_UNUSED) {
3759   StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
3760 }
3761 
ExceptionPoll(ManagedRegister mscratch,size_t stack_adjust)3762 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
3763   MipsManagedRegister scratch = mscratch.AsMips();
3764   exception_blocks_.emplace_back(scratch, stack_adjust);
3765   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
3766                  S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value());
3767   Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry());
3768 }
3769 
EmitExceptionPoll(MipsExceptionSlowPath * exception)3770 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) {
3771   Bind(exception->Entry());
3772   if (exception->stack_adjust_ != 0) {  // Fix up the frame.
3773     DecreaseFrameSize(exception->stack_adjust_);
3774   }
3775   // Pass exception object as argument.
3776   // Don't care about preserving A0 as this call won't return.
3777   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
3778   Move(A0, exception->scratch_.AsCoreRegister());
3779   // Set up call to Thread::Current()->pDeliverException.
3780   LoadFromOffset(kLoadWord, T9, S1,
3781     QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value());
3782   Jr(T9);
3783   NopIfNoReordering();
3784 
3785   // Call never returns.
3786   Break();
3787 }
3788 
3789 }  // namespace mips
3790 }  // namespace art
3791