1/*
2 * Copyright (C) 2015 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 "code_generator_mips.h"
18
19#include "arch/mips/entrypoints_direct_mips.h"
20#include "arch/mips/instruction_set_features_mips.h"
21#include "art_method.h"
22#include "code_generator_utils.h"
23#include "compiled_method.h"
24#include "entrypoints/quick/quick_entrypoints.h"
25#include "entrypoints/quick/quick_entrypoints_enum.h"
26#include "gc/accounting/card_table.h"
27#include "intrinsics.h"
28#include "intrinsics_mips.h"
29#include "mirror/array-inl.h"
30#include "mirror/class-inl.h"
31#include "offsets.h"
32#include "thread.h"
33#include "utils/assembler.h"
34#include "utils/mips/assembler_mips.h"
35#include "utils/stack_checks.h"
36
37namespace art {
38namespace mips {
39
40static constexpr int kCurrentMethodStackOffset = 0;
41static constexpr Register kMethodRegisterArgument = A0;
42
43// We'll maximize the range of a single load instruction for dex cache array accesses
44// by aligning offset -32768 with the offset of the first used element.
45static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000;
46
47Location MipsReturnLocation(Primitive::Type return_type) {
48  switch (return_type) {
49    case Primitive::kPrimBoolean:
50    case Primitive::kPrimByte:
51    case Primitive::kPrimChar:
52    case Primitive::kPrimShort:
53    case Primitive::kPrimInt:
54    case Primitive::kPrimNot:
55      return Location::RegisterLocation(V0);
56
57    case Primitive::kPrimLong:
58      return Location::RegisterPairLocation(V0, V1);
59
60    case Primitive::kPrimFloat:
61    case Primitive::kPrimDouble:
62      return Location::FpuRegisterLocation(F0);
63
64    case Primitive::kPrimVoid:
65      return Location();
66  }
67  UNREACHABLE();
68}
69
70Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(Primitive::Type type) const {
71  return MipsReturnLocation(type);
72}
73
74Location InvokeDexCallingConventionVisitorMIPS::GetMethodLocation() const {
75  return Location::RegisterLocation(kMethodRegisterArgument);
76}
77
78Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(Primitive::Type type) {
79  Location next_location;
80
81  switch (type) {
82    case Primitive::kPrimBoolean:
83    case Primitive::kPrimByte:
84    case Primitive::kPrimChar:
85    case Primitive::kPrimShort:
86    case Primitive::kPrimInt:
87    case Primitive::kPrimNot: {
88      uint32_t gp_index = gp_index_++;
89      if (gp_index < calling_convention.GetNumberOfRegisters()) {
90        next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
91      } else {
92        size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
93        next_location = Location::StackSlot(stack_offset);
94      }
95      break;
96    }
97
98    case Primitive::kPrimLong: {
99      uint32_t gp_index = gp_index_;
100      gp_index_ += 2;
101      if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
102        Register reg = calling_convention.GetRegisterAt(gp_index);
103        if (reg == A1 || reg == A3) {
104          gp_index_++;  // Skip A1(A3), and use A2_A3(T0_T1) instead.
105          gp_index++;
106        }
107        Register low_even = calling_convention.GetRegisterAt(gp_index);
108        Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
109        DCHECK_EQ(low_even + 1, high_odd);
110        next_location = Location::RegisterPairLocation(low_even, high_odd);
111      } else {
112        size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
113        next_location = Location::DoubleStackSlot(stack_offset);
114      }
115      break;
116    }
117
118    // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
119    // will take up the even/odd pair, while floats are stored in even regs only.
120    // On 64 bit FPU, both double and float are stored in even registers only.
121    case Primitive::kPrimFloat:
122    case Primitive::kPrimDouble: {
123      uint32_t float_index = float_index_++;
124      if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
125        next_location = Location::FpuRegisterLocation(
126            calling_convention.GetFpuRegisterAt(float_index));
127      } else {
128        size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
129        next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
130                                                     : Location::StackSlot(stack_offset);
131      }
132      break;
133    }
134
135    case Primitive::kPrimVoid:
136      LOG(FATAL) << "Unexpected parameter type " << type;
137      break;
138  }
139
140  // Space on the stack is reserved for all arguments.
141  stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
142
143  return next_location;
144}
145
146Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
147  return MipsReturnLocation(type);
148}
149
150// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
151#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()->  // NOLINT
152#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
153
154class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
155 public:
156  explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
157
158  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
159    LocationSummary* locations = instruction_->GetLocations();
160    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
161    __ Bind(GetEntryLabel());
162    if (instruction_->CanThrowIntoCatchBlock()) {
163      // Live registers will be restored in the catch block if caught.
164      SaveLiveRegisters(codegen, instruction_->GetLocations());
165    }
166    // We're moving two locations to locations that could overlap, so we need a parallel
167    // move resolver.
168    InvokeRuntimeCallingConvention calling_convention;
169    codegen->EmitParallelMoves(locations->InAt(0),
170                               Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
171                               Primitive::kPrimInt,
172                               locations->InAt(1),
173                               Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
174                               Primitive::kPrimInt);
175    QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
176        ? kQuickThrowStringBounds
177        : kQuickThrowArrayBounds;
178    mips_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
179    CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
180    CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
181  }
182
183  bool IsFatal() const OVERRIDE { return true; }
184
185  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
186
187 private:
188  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
189};
190
191class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
192 public:
193  explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
194
195  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
196    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
197    __ Bind(GetEntryLabel());
198    mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
199    CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
200  }
201
202  bool IsFatal() const OVERRIDE { return true; }
203
204  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
205
206 private:
207  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
208};
209
210class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
211 public:
212  LoadClassSlowPathMIPS(HLoadClass* cls,
213                        HInstruction* at,
214                        uint32_t dex_pc,
215                        bool do_clinit)
216      : SlowPathCodeMIPS(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
217    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
218  }
219
220  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
221    LocationSummary* locations = instruction_->GetLocations();
222    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
223
224    __ Bind(GetEntryLabel());
225    SaveLiveRegisters(codegen, locations);
226
227    InvokeRuntimeCallingConvention calling_convention;
228    dex::TypeIndex type_index = cls_->GetTypeIndex();
229    __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
230
231    QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
232                                                : kQuickInitializeType;
233    mips_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
234    if (do_clinit_) {
235      CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
236    } else {
237      CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
238    }
239
240    // Move the class to the desired location.
241    Location out = locations->Out();
242    if (out.IsValid()) {
243      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
244      Primitive::Type type = instruction_->GetType();
245      mips_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
246    }
247
248    RestoreLiveRegisters(codegen, locations);
249    // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
250    DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
251    if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
252      DCHECK(out.IsValid());
253      // TODO: Change art_quick_initialize_type/art_quick_initialize_static_storage to
254      // kSaveEverything and use a temporary for the .bss entry address in the fast path,
255      // so that we can avoid another calculation here.
256      bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
257      Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
258      DCHECK_NE(out.AsRegister<Register>(), AT);
259      CodeGeneratorMIPS::PcRelativePatchInfo* info =
260          mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
261      bool reordering = __ SetReorder(false);
262      mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
263      __ StoreToOffset(kStoreWord, out.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
264      __ SetReorder(reordering);
265    }
266    __ B(GetExitLabel());
267  }
268
269  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS"; }
270
271 private:
272  // The class this slow path will load.
273  HLoadClass* const cls_;
274
275  // The dex PC of `at_`.
276  const uint32_t dex_pc_;
277
278  // Whether to initialize the class.
279  const bool do_clinit_;
280
281  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
282};
283
284class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
285 public:
286  explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
287
288  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
289    LocationSummary* locations = instruction_->GetLocations();
290    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
291    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
292
293    __ Bind(GetEntryLabel());
294    SaveLiveRegisters(codegen, locations);
295
296    InvokeRuntimeCallingConvention calling_convention;
297    HLoadString* load = instruction_->AsLoadString();
298    const dex::StringIndex string_index = load->GetStringIndex();
299    __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
300    mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
301    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
302    Primitive::Type type = instruction_->GetType();
303    mips_codegen->MoveLocation(locations->Out(),
304                               calling_convention.GetReturnLocation(type),
305                               type);
306
307    RestoreLiveRegisters(codegen, locations);
308
309    // Store the resolved String to the BSS entry.
310    // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the
311    // .bss entry address in the fast path, so that we can avoid another calculation here.
312    bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
313    Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
314    Register out = locations->Out().AsRegister<Register>();
315    DCHECK_NE(out, AT);
316    CodeGeneratorMIPS::PcRelativePatchInfo* info =
317        mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
318    bool reordering = __ SetReorder(false);
319    mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
320    __ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
321    __ SetReorder(reordering);
322
323    __ B(GetExitLabel());
324  }
325
326  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
327
328 private:
329  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
330};
331
332class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
333 public:
334  explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
335
336  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
337    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
338    __ Bind(GetEntryLabel());
339    if (instruction_->CanThrowIntoCatchBlock()) {
340      // Live registers will be restored in the catch block if caught.
341      SaveLiveRegisters(codegen, instruction_->GetLocations());
342    }
343    mips_codegen->InvokeRuntime(kQuickThrowNullPointer,
344                                instruction_,
345                                instruction_->GetDexPc(),
346                                this);
347    CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
348  }
349
350  bool IsFatal() const OVERRIDE { return true; }
351
352  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
353
354 private:
355  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
356};
357
358class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
359 public:
360  SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
361      : SlowPathCodeMIPS(instruction), successor_(successor) {}
362
363  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
364    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
365    __ Bind(GetEntryLabel());
366    mips_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
367    CheckEntrypointTypes<kQuickTestSuspend, void, void>();
368    if (successor_ == nullptr) {
369      __ B(GetReturnLabel());
370    } else {
371      __ B(mips_codegen->GetLabelOf(successor_));
372    }
373  }
374
375  MipsLabel* GetReturnLabel() {
376    DCHECK(successor_ == nullptr);
377    return &return_label_;
378  }
379
380  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
381
382 private:
383  // If not null, the block to branch to after the suspend check.
384  HBasicBlock* const successor_;
385
386  // If `successor_` is null, the label to branch to after the suspend check.
387  MipsLabel return_label_;
388
389  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
390};
391
392class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
393 public:
394  explicit TypeCheckSlowPathMIPS(HInstruction* instruction, bool is_fatal)
395      : SlowPathCodeMIPS(instruction), is_fatal_(is_fatal) {}
396
397  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
398    LocationSummary* locations = instruction_->GetLocations();
399    uint32_t dex_pc = instruction_->GetDexPc();
400    DCHECK(instruction_->IsCheckCast()
401           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
402    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
403
404    __ Bind(GetEntryLabel());
405    if (!is_fatal_) {
406      SaveLiveRegisters(codegen, locations);
407    }
408
409    // We're moving two locations to locations that could overlap, so we need a parallel
410    // move resolver.
411    InvokeRuntimeCallingConvention calling_convention;
412    codegen->EmitParallelMoves(locations->InAt(0),
413                               Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
414                               Primitive::kPrimNot,
415                               locations->InAt(1),
416                               Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
417                               Primitive::kPrimNot);
418    if (instruction_->IsInstanceOf()) {
419      mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
420      CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
421      Primitive::Type ret_type = instruction_->GetType();
422      Location ret_loc = calling_convention.GetReturnLocation(ret_type);
423      mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
424    } else {
425      DCHECK(instruction_->IsCheckCast());
426      mips_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
427      CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
428    }
429
430    if (!is_fatal_) {
431      RestoreLiveRegisters(codegen, locations);
432      __ B(GetExitLabel());
433    }
434  }
435
436  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
437
438  bool IsFatal() const OVERRIDE { return is_fatal_; }
439
440 private:
441  const bool is_fatal_;
442
443  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
444};
445
446class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
447 public:
448  explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
449    : SlowPathCodeMIPS(instruction) {}
450
451  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
452    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
453    __ Bind(GetEntryLabel());
454    LocationSummary* locations = instruction_->GetLocations();
455    SaveLiveRegisters(codegen, locations);
456    InvokeRuntimeCallingConvention calling_convention;
457    __ LoadConst32(calling_convention.GetRegisterAt(0),
458                   static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
459    mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
460    CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
461  }
462
463  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
464
465 private:
466  DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
467};
468
469class ArraySetSlowPathMIPS : public SlowPathCodeMIPS {
470 public:
471  explicit ArraySetSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
472
473  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
474    LocationSummary* locations = instruction_->GetLocations();
475    __ Bind(GetEntryLabel());
476    SaveLiveRegisters(codegen, locations);
477
478    InvokeRuntimeCallingConvention calling_convention;
479    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
480    parallel_move.AddMove(
481        locations->InAt(0),
482        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
483        Primitive::kPrimNot,
484        nullptr);
485    parallel_move.AddMove(
486        locations->InAt(1),
487        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
488        Primitive::kPrimInt,
489        nullptr);
490    parallel_move.AddMove(
491        locations->InAt(2),
492        Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
493        Primitive::kPrimNot,
494        nullptr);
495    codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
496
497    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
498    mips_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
499    CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
500    RestoreLiveRegisters(codegen, locations);
501    __ B(GetExitLabel());
502  }
503
504  const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathMIPS"; }
505
506 private:
507  DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathMIPS);
508};
509
510// Slow path marking an object reference `ref` during a read
511// barrier. The field `obj.field` in the object `obj` holding this
512// reference does not get updated by this slow path after marking (see
513// ReadBarrierMarkAndUpdateFieldSlowPathMIPS below for that).
514//
515// This means that after the execution of this slow path, `ref` will
516// always be up-to-date, but `obj.field` may not; i.e., after the
517// flip, `ref` will be a to-space reference, but `obj.field` will
518// probably still be a from-space reference (unless it gets updated by
519// another thread, or if another thread installed another object
520// reference (different from `ref`) in `obj.field`).
521//
522// If `entrypoint` is a valid location it is assumed to already be
523// holding the entrypoint. The case where the entrypoint is passed in
524// is for the GcRoot read barrier.
525class ReadBarrierMarkSlowPathMIPS : public SlowPathCodeMIPS {
526 public:
527  ReadBarrierMarkSlowPathMIPS(HInstruction* instruction,
528                              Location ref,
529                              Location entrypoint = Location::NoLocation())
530      : SlowPathCodeMIPS(instruction), ref_(ref), entrypoint_(entrypoint) {
531    DCHECK(kEmitCompilerReadBarrier);
532  }
533
534  const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathMIPS"; }
535
536  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
537    LocationSummary* locations = instruction_->GetLocations();
538    Register ref_reg = ref_.AsRegister<Register>();
539    DCHECK(locations->CanCall());
540    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
541    DCHECK(instruction_->IsInstanceFieldGet() ||
542           instruction_->IsStaticFieldGet() ||
543           instruction_->IsArrayGet() ||
544           instruction_->IsArraySet() ||
545           instruction_->IsLoadClass() ||
546           instruction_->IsLoadString() ||
547           instruction_->IsInstanceOf() ||
548           instruction_->IsCheckCast() ||
549           (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
550           (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
551        << "Unexpected instruction in read barrier marking slow path: "
552        << instruction_->DebugName();
553
554    __ Bind(GetEntryLabel());
555    // No need to save live registers; it's taken care of by the
556    // entrypoint. Also, there is no need to update the stack mask,
557    // as this runtime call will not trigger a garbage collection.
558    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
559    DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
560           (S2 <= ref_reg && ref_reg <= S7) ||
561           (ref_reg == FP)) << ref_reg;
562    // "Compact" slow path, saving two moves.
563    //
564    // Instead of using the standard runtime calling convention (input
565    // and output in A0 and V0 respectively):
566    //
567    //   A0 <- ref
568    //   V0 <- ReadBarrierMark(A0)
569    //   ref <- V0
570    //
571    // we just use rX (the register containing `ref`) as input and output
572    // of a dedicated entrypoint:
573    //
574    //   rX <- ReadBarrierMarkRegX(rX)
575    //
576    if (entrypoint_.IsValid()) {
577      mips_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
578      DCHECK_EQ(entrypoint_.AsRegister<Register>(), T9);
579      __ Jalr(entrypoint_.AsRegister<Register>());
580      __ NopIfNoReordering();
581    } else {
582      int32_t entry_point_offset =
583          CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
584      // This runtime call does not require a stack map.
585      mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
586                                                        instruction_,
587                                                        this,
588                                                        /* direct */ false);
589    }
590    __ B(GetExitLabel());
591  }
592
593 private:
594  // The location (register) of the marked object reference.
595  const Location ref_;
596
597  // The location of the entrypoint if already loaded.
598  const Location entrypoint_;
599
600  DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathMIPS);
601};
602
603// Slow path marking an object reference `ref` during a read barrier,
604// and if needed, atomically updating the field `obj.field` in the
605// object `obj` holding this reference after marking (contrary to
606// ReadBarrierMarkSlowPathMIPS above, which never tries to update
607// `obj.field`).
608//
609// This means that after the execution of this slow path, both `ref`
610// and `obj.field` will be up-to-date; i.e., after the flip, both will
611// hold the same to-space reference (unless another thread installed
612// another object reference (different from `ref`) in `obj.field`).
613class ReadBarrierMarkAndUpdateFieldSlowPathMIPS : public SlowPathCodeMIPS {
614 public:
615  ReadBarrierMarkAndUpdateFieldSlowPathMIPS(HInstruction* instruction,
616                                            Location ref,
617                                            Register obj,
618                                            Location field_offset,
619                                            Register temp1)
620      : SlowPathCodeMIPS(instruction),
621        ref_(ref),
622        obj_(obj),
623        field_offset_(field_offset),
624        temp1_(temp1) {
625    DCHECK(kEmitCompilerReadBarrier);
626  }
627
628  const char* GetDescription() const OVERRIDE {
629    return "ReadBarrierMarkAndUpdateFieldSlowPathMIPS";
630  }
631
632  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
633    LocationSummary* locations = instruction_->GetLocations();
634    Register ref_reg = ref_.AsRegister<Register>();
635    DCHECK(locations->CanCall());
636    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
637    // This slow path is only used by the UnsafeCASObject intrinsic.
638    DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
639        << "Unexpected instruction in read barrier marking and field updating slow path: "
640        << instruction_->DebugName();
641    DCHECK(instruction_->GetLocations()->Intrinsified());
642    DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
643    DCHECK(field_offset_.IsRegisterPair()) << field_offset_;
644
645    __ Bind(GetEntryLabel());
646
647    // Save the old reference.
648    // Note that we cannot use AT or TMP to save the old reference, as those
649    // are used by the code that follows, but we need the old reference after
650    // the call to the ReadBarrierMarkRegX entry point.
651    DCHECK_NE(temp1_, AT);
652    DCHECK_NE(temp1_, TMP);
653    __ Move(temp1_, ref_reg);
654
655    // No need to save live registers; it's taken care of by the
656    // entrypoint. Also, there is no need to update the stack mask,
657    // as this runtime call will not trigger a garbage collection.
658    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
659    DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
660           (S2 <= ref_reg && ref_reg <= S7) ||
661           (ref_reg == FP)) << ref_reg;
662    // "Compact" slow path, saving two moves.
663    //
664    // Instead of using the standard runtime calling convention (input
665    // and output in A0 and V0 respectively):
666    //
667    //   A0 <- ref
668    //   V0 <- ReadBarrierMark(A0)
669    //   ref <- V0
670    //
671    // we just use rX (the register containing `ref`) as input and output
672    // of a dedicated entrypoint:
673    //
674    //   rX <- ReadBarrierMarkRegX(rX)
675    //
676    int32_t entry_point_offset =
677        CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
678    // This runtime call does not require a stack map.
679    mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
680                                                      instruction_,
681                                                      this,
682                                                      /* direct */ false);
683
684    // If the new reference is different from the old reference,
685    // update the field in the holder (`*(obj_ + field_offset_)`).
686    //
687    // Note that this field could also hold a different object, if
688    // another thread had concurrently changed it. In that case, the
689    // the compare-and-set (CAS) loop below would abort, leaving the
690    // field as-is.
691    MipsLabel done;
692    __ Beq(temp1_, ref_reg, &done);
693
694    // Update the the holder's field atomically.  This may fail if
695    // mutator updates before us, but it's OK.  This is achieved
696    // using a strong compare-and-set (CAS) operation with relaxed
697    // memory synchronization ordering, where the expected value is
698    // the old reference and the desired value is the new reference.
699
700    // Convenience aliases.
701    Register base = obj_;
702    // The UnsafeCASObject intrinsic uses a register pair as field
703    // offset ("long offset"), of which only the low part contains
704    // data.
705    Register offset = field_offset_.AsRegisterPairLow<Register>();
706    Register expected = temp1_;
707    Register value = ref_reg;
708    Register tmp_ptr = TMP;      // Pointer to actual memory.
709    Register tmp = AT;           // Value in memory.
710
711    __ Addu(tmp_ptr, base, offset);
712
713    if (kPoisonHeapReferences) {
714      __ PoisonHeapReference(expected);
715      // Do not poison `value` if it is the same register as
716      // `expected`, which has just been poisoned.
717      if (value != expected) {
718        __ PoisonHeapReference(value);
719      }
720    }
721
722    // do {
723    //   tmp = [r_ptr] - expected;
724    // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
725
726    bool is_r6 = mips_codegen->GetInstructionSetFeatures().IsR6();
727    MipsLabel loop_head, exit_loop;
728    __ Bind(&loop_head);
729    if (is_r6) {
730      __ LlR6(tmp, tmp_ptr);
731    } else {
732      __ LlR2(tmp, tmp_ptr);
733    }
734    __ Bne(tmp, expected, &exit_loop);
735    __ Move(tmp, value);
736    if (is_r6) {
737      __ ScR6(tmp, tmp_ptr);
738    } else {
739      __ ScR2(tmp, tmp_ptr);
740    }
741    __ Beqz(tmp, &loop_head);
742    __ Bind(&exit_loop);
743
744    if (kPoisonHeapReferences) {
745      __ UnpoisonHeapReference(expected);
746      // Do not unpoison `value` if it is the same register as
747      // `expected`, which has just been unpoisoned.
748      if (value != expected) {
749        __ UnpoisonHeapReference(value);
750      }
751    }
752
753    __ Bind(&done);
754    __ B(GetExitLabel());
755  }
756
757 private:
758  // The location (register) of the marked object reference.
759  const Location ref_;
760  // The register containing the object holding the marked object reference field.
761  const Register obj_;
762  // The location of the offset of the marked reference field within `obj_`.
763  Location field_offset_;
764
765  const Register temp1_;
766
767  DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathMIPS);
768};
769
770// Slow path generating a read barrier for a heap reference.
771class ReadBarrierForHeapReferenceSlowPathMIPS : public SlowPathCodeMIPS {
772 public:
773  ReadBarrierForHeapReferenceSlowPathMIPS(HInstruction* instruction,
774                                          Location out,
775                                          Location ref,
776                                          Location obj,
777                                          uint32_t offset,
778                                          Location index)
779      : SlowPathCodeMIPS(instruction),
780        out_(out),
781        ref_(ref),
782        obj_(obj),
783        offset_(offset),
784        index_(index) {
785    DCHECK(kEmitCompilerReadBarrier);
786    // If `obj` is equal to `out` or `ref`, it means the initial object
787    // has been overwritten by (or after) the heap object reference load
788    // to be instrumented, e.g.:
789    //
790    //   __ LoadFromOffset(kLoadWord, out, out, offset);
791    //   codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
792    //
793    // In that case, we have lost the information about the original
794    // object, and the emitted read barrier cannot work properly.
795    DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
796    DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
797  }
798
799  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
800    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
801    LocationSummary* locations = instruction_->GetLocations();
802    Register reg_out = out_.AsRegister<Register>();
803    DCHECK(locations->CanCall());
804    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
805    DCHECK(instruction_->IsInstanceFieldGet() ||
806           instruction_->IsStaticFieldGet() ||
807           instruction_->IsArrayGet() ||
808           instruction_->IsInstanceOf() ||
809           instruction_->IsCheckCast() ||
810           (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
811        << "Unexpected instruction in read barrier for heap reference slow path: "
812        << instruction_->DebugName();
813
814    __ Bind(GetEntryLabel());
815    SaveLiveRegisters(codegen, locations);
816
817    // We may have to change the index's value, but as `index_` is a
818    // constant member (like other "inputs" of this slow path),
819    // introduce a copy of it, `index`.
820    Location index = index_;
821    if (index_.IsValid()) {
822      // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
823      if (instruction_->IsArrayGet()) {
824        // Compute the actual memory offset and store it in `index`.
825        Register index_reg = index_.AsRegister<Register>();
826        DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
827        if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
828          // We are about to change the value of `index_reg` (see the
829          // calls to art::mips::MipsAssembler::Sll and
830          // art::mips::MipsAssembler::Addiu32 below), but it has
831          // not been saved by the previous call to
832          // art::SlowPathCode::SaveLiveRegisters, as it is a
833          // callee-save register --
834          // art::SlowPathCode::SaveLiveRegisters does not consider
835          // callee-save registers, as it has been designed with the
836          // assumption that callee-save registers are supposed to be
837          // handled by the called function.  So, as a callee-save
838          // register, `index_reg` _would_ eventually be saved onto
839          // the stack, but it would be too late: we would have
840          // changed its value earlier.  Therefore, we manually save
841          // it here into another freely available register,
842          // `free_reg`, chosen of course among the caller-save
843          // registers (as a callee-save `free_reg` register would
844          // exhibit the same problem).
845          //
846          // Note we could have requested a temporary register from
847          // the register allocator instead; but we prefer not to, as
848          // this is a slow path, and we know we can find a
849          // caller-save register that is available.
850          Register free_reg = FindAvailableCallerSaveRegister(codegen);
851          __ Move(free_reg, index_reg);
852          index_reg = free_reg;
853          index = Location::RegisterLocation(index_reg);
854        } else {
855          // The initial register stored in `index_` has already been
856          // saved in the call to art::SlowPathCode::SaveLiveRegisters
857          // (as it is not a callee-save register), so we can freely
858          // use it.
859        }
860        // Shifting the index value contained in `index_reg` by the scale
861        // factor (2) cannot overflow in practice, as the runtime is
862        // unable to allocate object arrays with a size larger than
863        // 2^26 - 1 (that is, 2^28 - 4 bytes).
864        __ Sll(index_reg, index_reg, TIMES_4);
865        static_assert(
866            sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
867            "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
868        __ Addiu32(index_reg, index_reg, offset_);
869      } else {
870        // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
871        // intrinsics, `index_` is not shifted by a scale factor of 2
872        // (as in the case of ArrayGet), as it is actually an offset
873        // to an object field within an object.
874        DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
875        DCHECK(instruction_->GetLocations()->Intrinsified());
876        DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
877               (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
878            << instruction_->AsInvoke()->GetIntrinsic();
879        DCHECK_EQ(offset_, 0U);
880        DCHECK(index_.IsRegisterPair());
881        // UnsafeGet's offset location is a register pair, the low
882        // part contains the correct offset.
883        index = index_.ToLow();
884      }
885    }
886
887    // We're moving two or three locations to locations that could
888    // overlap, so we need a parallel move resolver.
889    InvokeRuntimeCallingConvention calling_convention;
890    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
891    parallel_move.AddMove(ref_,
892                          Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
893                          Primitive::kPrimNot,
894                          nullptr);
895    parallel_move.AddMove(obj_,
896                          Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
897                          Primitive::kPrimNot,
898                          nullptr);
899    if (index.IsValid()) {
900      parallel_move.AddMove(index,
901                            Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
902                            Primitive::kPrimInt,
903                            nullptr);
904      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
905    } else {
906      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
907      __ LoadConst32(calling_convention.GetRegisterAt(2), offset_);
908    }
909    mips_codegen->InvokeRuntime(kQuickReadBarrierSlow,
910                                instruction_,
911                                instruction_->GetDexPc(),
912                                this);
913    CheckEntrypointTypes<
914        kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
915    mips_codegen->Move32(out_, calling_convention.GetReturnLocation(Primitive::kPrimNot));
916
917    RestoreLiveRegisters(codegen, locations);
918    __ B(GetExitLabel());
919  }
920
921  const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathMIPS"; }
922
923 private:
924  Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
925    size_t ref = static_cast<int>(ref_.AsRegister<Register>());
926    size_t obj = static_cast<int>(obj_.AsRegister<Register>());
927    for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
928      if (i != ref &&
929          i != obj &&
930          !codegen->IsCoreCalleeSaveRegister(i) &&
931          !codegen->IsBlockedCoreRegister(i)) {
932        return static_cast<Register>(i);
933      }
934    }
935    // We shall never fail to find a free caller-save register, as
936    // there are more than two core caller-save registers on MIPS
937    // (meaning it is possible to find one which is different from
938    // `ref` and `obj`).
939    DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
940    LOG(FATAL) << "Could not find a free caller-save register";
941    UNREACHABLE();
942  }
943
944  const Location out_;
945  const Location ref_;
946  const Location obj_;
947  const uint32_t offset_;
948  // An additional location containing an index to an array.
949  // Only used for HArrayGet and the UnsafeGetObject &
950  // UnsafeGetObjectVolatile intrinsics.
951  const Location index_;
952
953  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathMIPS);
954};
955
956// Slow path generating a read barrier for a GC root.
957class ReadBarrierForRootSlowPathMIPS : public SlowPathCodeMIPS {
958 public:
959  ReadBarrierForRootSlowPathMIPS(HInstruction* instruction, Location out, Location root)
960      : SlowPathCodeMIPS(instruction), out_(out), root_(root) {
961    DCHECK(kEmitCompilerReadBarrier);
962  }
963
964  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
965    LocationSummary* locations = instruction_->GetLocations();
966    Register reg_out = out_.AsRegister<Register>();
967    DCHECK(locations->CanCall());
968    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
969    DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
970        << "Unexpected instruction in read barrier for GC root slow path: "
971        << instruction_->DebugName();
972
973    __ Bind(GetEntryLabel());
974    SaveLiveRegisters(codegen, locations);
975
976    InvokeRuntimeCallingConvention calling_convention;
977    CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
978    mips_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
979    mips_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
980                                instruction_,
981                                instruction_->GetDexPc(),
982                                this);
983    CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
984    mips_codegen->Move32(out_, calling_convention.GetReturnLocation(Primitive::kPrimNot));
985
986    RestoreLiveRegisters(codegen, locations);
987    __ B(GetExitLabel());
988  }
989
990  const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathMIPS"; }
991
992 private:
993  const Location out_;
994  const Location root_;
995
996  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathMIPS);
997};
998
999CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
1000                                     const MipsInstructionSetFeatures& isa_features,
1001                                     const CompilerOptions& compiler_options,
1002                                     OptimizingCompilerStats* stats)
1003    : CodeGenerator(graph,
1004                    kNumberOfCoreRegisters,
1005                    kNumberOfFRegisters,
1006                    kNumberOfRegisterPairs,
1007                    ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1008                                        arraysize(kCoreCalleeSaves)),
1009                    ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1010                                        arraysize(kFpuCalleeSaves)),
1011                    compiler_options,
1012                    stats),
1013      block_labels_(nullptr),
1014      location_builder_(graph, this),
1015      instruction_visitor_(graph, this),
1016      move_resolver_(graph->GetArena(), this),
1017      assembler_(graph->GetArena(), &isa_features),
1018      isa_features_(isa_features),
1019      uint32_literals_(std::less<uint32_t>(),
1020                       graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1021      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1022      boot_image_string_patches_(StringReferenceValueComparator(),
1023                                 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1024      pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1025      boot_image_type_patches_(TypeReferenceValueComparator(),
1026                               graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1027      pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1028      type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1029      jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1030      jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1031      clobbered_ra_(false) {
1032  // Save RA (containing the return address) to mimic Quick.
1033  AddAllocatedRegister(Location::RegisterLocation(RA));
1034}
1035
1036#undef __
1037// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1038#define __ down_cast<MipsAssembler*>(GetAssembler())->  // NOLINT
1039#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
1040
1041void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
1042  // Ensure that we fix up branches.
1043  __ FinalizeCode();
1044
1045  // Adjust native pc offsets in stack maps.
1046  for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
1047    uint32_t old_position =
1048        stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kMips);
1049    uint32_t new_position = __ GetAdjustedPosition(old_position);
1050    DCHECK_GE(new_position, old_position);
1051    stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
1052  }
1053
1054  // Adjust pc offsets for the disassembly information.
1055  if (disasm_info_ != nullptr) {
1056    GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
1057    frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
1058    frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1059    for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1060      it.second.start = __ GetAdjustedPosition(it.second.start);
1061      it.second.end = __ GetAdjustedPosition(it.second.end);
1062    }
1063    for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1064      it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
1065      it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
1066    }
1067  }
1068
1069  CodeGenerator::Finalize(allocator);
1070}
1071
1072MipsAssembler* ParallelMoveResolverMIPS::GetAssembler() const {
1073  return codegen_->GetAssembler();
1074}
1075
1076void ParallelMoveResolverMIPS::EmitMove(size_t index) {
1077  DCHECK_LT(index, moves_.size());
1078  MoveOperands* move = moves_[index];
1079  codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
1080}
1081
1082void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
1083  DCHECK_LT(index, moves_.size());
1084  MoveOperands* move = moves_[index];
1085  Primitive::Type type = move->GetType();
1086  Location loc1 = move->GetDestination();
1087  Location loc2 = move->GetSource();
1088
1089  DCHECK(!loc1.IsConstant());
1090  DCHECK(!loc2.IsConstant());
1091
1092  if (loc1.Equals(loc2)) {
1093    return;
1094  }
1095
1096  if (loc1.IsRegister() && loc2.IsRegister()) {
1097    // Swap 2 GPRs.
1098    Register r1 = loc1.AsRegister<Register>();
1099    Register r2 = loc2.AsRegister<Register>();
1100    __ Move(TMP, r2);
1101    __ Move(r2, r1);
1102    __ Move(r1, TMP);
1103  } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
1104    FRegister f1 = loc1.AsFpuRegister<FRegister>();
1105    FRegister f2 = loc2.AsFpuRegister<FRegister>();
1106    if (type == Primitive::kPrimFloat) {
1107      __ MovS(FTMP, f2);
1108      __ MovS(f2, f1);
1109      __ MovS(f1, FTMP);
1110    } else {
1111      DCHECK_EQ(type, Primitive::kPrimDouble);
1112      __ MovD(FTMP, f2);
1113      __ MovD(f2, f1);
1114      __ MovD(f1, FTMP);
1115    }
1116  } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
1117             (loc1.IsFpuRegister() && loc2.IsRegister())) {
1118    // Swap FPR and GPR.
1119    DCHECK_EQ(type, Primitive::kPrimFloat);  // Can only swap a float.
1120    FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1121                                        : loc2.AsFpuRegister<FRegister>();
1122    Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
1123    __ Move(TMP, r2);
1124    __ Mfc1(r2, f1);
1125    __ Mtc1(TMP, f1);
1126  } else if (loc1.IsRegisterPair() && loc2.IsRegisterPair()) {
1127    // Swap 2 GPR register pairs.
1128    Register r1 = loc1.AsRegisterPairLow<Register>();
1129    Register r2 = loc2.AsRegisterPairLow<Register>();
1130    __ Move(TMP, r2);
1131    __ Move(r2, r1);
1132    __ Move(r1, TMP);
1133    r1 = loc1.AsRegisterPairHigh<Register>();
1134    r2 = loc2.AsRegisterPairHigh<Register>();
1135    __ Move(TMP, r2);
1136    __ Move(r2, r1);
1137    __ Move(r1, TMP);
1138  } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
1139             (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
1140    // Swap FPR and GPR register pair.
1141    DCHECK_EQ(type, Primitive::kPrimDouble);
1142    FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1143                                        : loc2.AsFpuRegister<FRegister>();
1144    Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
1145                                          : loc2.AsRegisterPairLow<Register>();
1146    Register r2_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
1147                                          : loc2.AsRegisterPairHigh<Register>();
1148    // Use 2 temporary registers because we can't first swap the low 32 bits of an FPR and
1149    // then swap the high 32 bits of the same FPR. mtc1 makes the high 32 bits of an FPR
1150    // unpredictable and the following mfch1 will fail.
1151    __ Mfc1(TMP, f1);
1152    __ MoveFromFpuHigh(AT, f1);
1153    __ Mtc1(r2_l, f1);
1154    __ MoveToFpuHigh(r2_h, f1);
1155    __ Move(r2_l, TMP);
1156    __ Move(r2_h, AT);
1157  } else if (loc1.IsStackSlot() && loc2.IsStackSlot()) {
1158    Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
1159  } else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
1160    Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
1161  } else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
1162             (loc1.IsStackSlot() && loc2.IsRegister())) {
1163    Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
1164    intptr_t offset = loc1.IsStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
1165    __ Move(TMP, reg);
1166    __ LoadFromOffset(kLoadWord, reg, SP, offset);
1167    __ StoreToOffset(kStoreWord, TMP, SP, offset);
1168  } else if ((loc1.IsRegisterPair() && loc2.IsDoubleStackSlot()) ||
1169             (loc1.IsDoubleStackSlot() && loc2.IsRegisterPair())) {
1170    Register reg_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
1171                                           : loc2.AsRegisterPairLow<Register>();
1172    Register reg_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
1173                                           : loc2.AsRegisterPairHigh<Register>();
1174    intptr_t offset_l = loc1.IsDoubleStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
1175    intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize)
1176                                                 : loc2.GetHighStackIndex(kMipsWordSize);
1177    __ Move(TMP, reg_l);
1178    __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l);
1179    __ StoreToOffset(kStoreWord, TMP, SP, offset_l);
1180    __ Move(TMP, reg_h);
1181    __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
1182    __ StoreToOffset(kStoreWord, TMP, SP, offset_h);
1183  } else if (loc1.IsFpuRegister() || loc2.IsFpuRegister()) {
1184    FRegister reg = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1185                                         : loc2.AsFpuRegister<FRegister>();
1186    intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
1187    if (type == Primitive::kPrimFloat) {
1188      __ MovS(FTMP, reg);
1189      __ LoadSFromOffset(reg, SP, offset);
1190      __ StoreSToOffset(FTMP, SP, offset);
1191    } else {
1192      DCHECK_EQ(type, Primitive::kPrimDouble);
1193      __ MovD(FTMP, reg);
1194      __ LoadDFromOffset(reg, SP, offset);
1195      __ StoreDToOffset(FTMP, SP, offset);
1196    }
1197  } else {
1198    LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported";
1199  }
1200}
1201
1202void ParallelMoveResolverMIPS::RestoreScratch(int reg) {
1203  __ Pop(static_cast<Register>(reg));
1204}
1205
1206void ParallelMoveResolverMIPS::SpillScratch(int reg) {
1207  __ Push(static_cast<Register>(reg));
1208}
1209
1210void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot) {
1211  // Allocate a scratch register other than TMP, if available.
1212  // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
1213  // automatically unspilled when the scratch scope object is destroyed).
1214  ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
1215  // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
1216  int stack_offset = ensure_scratch.IsSpilled() ? kMipsWordSize : 0;
1217  for (int i = 0; i <= (double_slot ? 1 : 0); i++, stack_offset += kMipsWordSize) {
1218    __ LoadFromOffset(kLoadWord,
1219                      Register(ensure_scratch.GetRegister()),
1220                      SP,
1221                      index1 + stack_offset);
1222    __ LoadFromOffset(kLoadWord,
1223                      TMP,
1224                      SP,
1225                      index2 + stack_offset);
1226    __ StoreToOffset(kStoreWord,
1227                     Register(ensure_scratch.GetRegister()),
1228                     SP,
1229                     index2 + stack_offset);
1230    __ StoreToOffset(kStoreWord, TMP, SP, index1 + stack_offset);
1231  }
1232}
1233
1234void CodeGeneratorMIPS::ComputeSpillMask() {
1235  core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
1236  fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
1237  DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
1238  // If there're FPU callee-saved registers and there's an odd number of GPR callee-saved
1239  // registers, include the ZERO register to force alignment of FPU callee-saved registers
1240  // within the stack frame.
1241  if ((fpu_spill_mask_ != 0) && (POPCOUNT(core_spill_mask_) % 2 != 0)) {
1242    core_spill_mask_ |= (1 << ZERO);
1243  }
1244}
1245
1246bool CodeGeneratorMIPS::HasAllocatedCalleeSaveRegisters() const {
1247  // If RA is clobbered by PC-relative operations on R2 and it's the only spilled register
1248  // (this can happen in leaf methods), force CodeGenerator::InitializeCodeGeneration()
1249  // into the path that creates a stack frame so that RA can be explicitly saved and restored.
1250  // RA can't otherwise be saved/restored when it's the only spilled register.
1251  return CodeGenerator::HasAllocatedCalleeSaveRegisters() || clobbered_ra_;
1252}
1253
1254static dwarf::Reg DWARFReg(Register reg) {
1255  return dwarf::Reg::MipsCore(static_cast<int>(reg));
1256}
1257
1258// TODO: mapping of floating-point registers to DWARF.
1259
1260void CodeGeneratorMIPS::GenerateFrameEntry() {
1261  __ Bind(&frame_entry_label_);
1262
1263  bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kMips) || !IsLeafMethod();
1264
1265  if (do_overflow_check) {
1266    __ LoadFromOffset(kLoadWord,
1267                      ZERO,
1268                      SP,
1269                      -static_cast<int32_t>(GetStackOverflowReservedBytes(kMips)));
1270    RecordPcInfo(nullptr, 0);
1271  }
1272
1273  if (HasEmptyFrame()) {
1274    CHECK_EQ(fpu_spill_mask_, 0u);
1275    CHECK_EQ(core_spill_mask_, 1u << RA);
1276    CHECK(!clobbered_ra_);
1277    return;
1278  }
1279
1280  // Make sure the frame size isn't unreasonably large.
1281  if (GetFrameSize() > GetStackOverflowReservedBytes(kMips)) {
1282    LOG(FATAL) << "Stack frame larger than " << GetStackOverflowReservedBytes(kMips) << " bytes";
1283  }
1284
1285  // Spill callee-saved registers.
1286
1287  uint32_t ofs = GetFrameSize();
1288  __ IncreaseFrameSize(ofs);
1289
1290  for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1291    Register reg = static_cast<Register>(MostSignificantBit(mask));
1292    mask ^= 1u << reg;
1293    ofs -= kMipsWordSize;
1294    // The ZERO register is only included for alignment.
1295    if (reg != ZERO) {
1296      __ StoreToOffset(kStoreWord, reg, SP, ofs);
1297      __ cfi().RelOffset(DWARFReg(reg), ofs);
1298    }
1299  }
1300
1301  for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1302    FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1303    mask ^= 1u << reg;
1304    ofs -= kMipsDoublewordSize;
1305    __ StoreDToOffset(reg, SP, ofs);
1306    // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
1307  }
1308
1309  // Save the current method if we need it. Note that we do not
1310  // do this in HCurrentMethod, as the instruction might have been removed
1311  // in the SSA graph.
1312  if (RequiresCurrentMethod()) {
1313    __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
1314  }
1315
1316  if (GetGraph()->HasShouldDeoptimizeFlag()) {
1317    // Initialize should deoptimize flag to 0.
1318    __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag());
1319  }
1320}
1321
1322void CodeGeneratorMIPS::GenerateFrameExit() {
1323  __ cfi().RememberState();
1324
1325  if (!HasEmptyFrame()) {
1326    // Restore callee-saved registers.
1327
1328    // For better instruction scheduling restore RA before other registers.
1329    uint32_t ofs = GetFrameSize();
1330    for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1331      Register reg = static_cast<Register>(MostSignificantBit(mask));
1332      mask ^= 1u << reg;
1333      ofs -= kMipsWordSize;
1334      // The ZERO register is only included for alignment.
1335      if (reg != ZERO) {
1336        __ LoadFromOffset(kLoadWord, reg, SP, ofs);
1337        __ cfi().Restore(DWARFReg(reg));
1338      }
1339    }
1340
1341    for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1342      FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1343      mask ^= 1u << reg;
1344      ofs -= kMipsDoublewordSize;
1345      __ LoadDFromOffset(reg, SP, ofs);
1346      // TODO: __ cfi().Restore(DWARFReg(reg));
1347    }
1348
1349    size_t frame_size = GetFrameSize();
1350    // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
1351    bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
1352    bool reordering = __ SetReorder(false);
1353    if (exchange) {
1354      __ Jr(RA);
1355      __ DecreaseFrameSize(frame_size);  // Single instruction in delay slot.
1356    } else {
1357      __ DecreaseFrameSize(frame_size);
1358      __ Jr(RA);
1359      __ Nop();  // In delay slot.
1360    }
1361    __ SetReorder(reordering);
1362  } else {
1363    __ Jr(RA);
1364    __ NopIfNoReordering();
1365  }
1366
1367  __ cfi().RestoreState();
1368  __ cfi().DefCFAOffset(GetFrameSize());
1369}
1370
1371void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
1372  __ Bind(GetLabelOf(block));
1373}
1374
1375void CodeGeneratorMIPS::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1376  if (src.Equals(dst)) {
1377    return;
1378  }
1379
1380  if (src.IsConstant()) {
1381    MoveConstant(dst, src.GetConstant());
1382  } else {
1383    if (Primitive::Is64BitType(dst_type)) {
1384      Move64(dst, src);
1385    } else {
1386      Move32(dst, src);
1387    }
1388  }
1389}
1390
1391void CodeGeneratorMIPS::Move32(Location destination, Location source) {
1392  if (source.Equals(destination)) {
1393    return;
1394  }
1395
1396  if (destination.IsRegister()) {
1397    if (source.IsRegister()) {
1398      __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
1399    } else if (source.IsFpuRegister()) {
1400      __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
1401    } else {
1402      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1403      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
1404    }
1405  } else if (destination.IsFpuRegister()) {
1406    if (source.IsRegister()) {
1407      __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
1408    } else if (source.IsFpuRegister()) {
1409      __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1410    } else {
1411      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1412      __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1413    }
1414  } else {
1415    DCHECK(destination.IsStackSlot()) << destination;
1416    if (source.IsRegister()) {
1417      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
1418    } else if (source.IsFpuRegister()) {
1419      __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
1420    } else {
1421      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1422      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1423      __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
1424    }
1425  }
1426}
1427
1428void CodeGeneratorMIPS::Move64(Location destination, Location source) {
1429  if (source.Equals(destination)) {
1430    return;
1431  }
1432
1433  if (destination.IsRegisterPair()) {
1434    if (source.IsRegisterPair()) {
1435      __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
1436      __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
1437    } else if (source.IsFpuRegister()) {
1438      Register dst_high = destination.AsRegisterPairHigh<Register>();
1439      Register dst_low =  destination.AsRegisterPairLow<Register>();
1440      FRegister src = source.AsFpuRegister<FRegister>();
1441      __ Mfc1(dst_low, src);
1442      __ MoveFromFpuHigh(dst_high, src);
1443    } else {
1444      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
1445      int32_t off = source.GetStackIndex();
1446      Register r = destination.AsRegisterPairLow<Register>();
1447      __ LoadFromOffset(kLoadDoubleword, r, SP, off);
1448    }
1449  } else if (destination.IsFpuRegister()) {
1450    if (source.IsRegisterPair()) {
1451      FRegister dst = destination.AsFpuRegister<FRegister>();
1452      Register src_high = source.AsRegisterPairHigh<Register>();
1453      Register src_low = source.AsRegisterPairLow<Register>();
1454      __ Mtc1(src_low, dst);
1455      __ MoveToFpuHigh(src_high, dst);
1456    } else if (source.IsFpuRegister()) {
1457      __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1458    } else {
1459      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
1460      __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1461    }
1462  } else {
1463    DCHECK(destination.IsDoubleStackSlot()) << destination;
1464    int32_t off = destination.GetStackIndex();
1465    if (source.IsRegisterPair()) {
1466      __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, off);
1467    } else if (source.IsFpuRegister()) {
1468      __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, off);
1469    } else {
1470      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
1471      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1472      __ StoreToOffset(kStoreWord, TMP, SP, off);
1473      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
1474      __ StoreToOffset(kStoreWord, TMP, SP, off + 4);
1475    }
1476  }
1477}
1478
1479void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
1480  if (c->IsIntConstant() || c->IsNullConstant()) {
1481    // Move 32 bit constant.
1482    int32_t value = GetInt32ValueOf(c);
1483    if (destination.IsRegister()) {
1484      Register dst = destination.AsRegister<Register>();
1485      __ LoadConst32(dst, value);
1486    } else {
1487      DCHECK(destination.IsStackSlot())
1488          << "Cannot move " << c->DebugName() << " to " << destination;
1489      __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
1490    }
1491  } else if (c->IsLongConstant()) {
1492    // Move 64 bit constant.
1493    int64_t value = GetInt64ValueOf(c);
1494    if (destination.IsRegisterPair()) {
1495      Register r_h = destination.AsRegisterPairHigh<Register>();
1496      Register r_l = destination.AsRegisterPairLow<Register>();
1497      __ LoadConst64(r_h, r_l, value);
1498    } else {
1499      DCHECK(destination.IsDoubleStackSlot())
1500          << "Cannot move " << c->DebugName() << " to " << destination;
1501      __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
1502    }
1503  } else if (c->IsFloatConstant()) {
1504    // Move 32 bit float constant.
1505    int32_t value = GetInt32ValueOf(c);
1506    if (destination.IsFpuRegister()) {
1507      __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
1508    } else {
1509      DCHECK(destination.IsStackSlot())
1510          << "Cannot move " << c->DebugName() << " to " << destination;
1511      __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
1512    }
1513  } else {
1514    // Move 64 bit double constant.
1515    DCHECK(c->IsDoubleConstant()) << c->DebugName();
1516    int64_t value = GetInt64ValueOf(c);
1517    if (destination.IsFpuRegister()) {
1518      FRegister fd = destination.AsFpuRegister<FRegister>();
1519      __ LoadDConst64(fd, value, TMP);
1520    } else {
1521      DCHECK(destination.IsDoubleStackSlot())
1522          << "Cannot move " << c->DebugName() << " to " << destination;
1523      __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
1524    }
1525  }
1526}
1527
1528void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
1529  DCHECK(destination.IsRegister());
1530  Register dst = destination.AsRegister<Register>();
1531  __ LoadConst32(dst, value);
1532}
1533
1534void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
1535  if (location.IsRegister()) {
1536    locations->AddTemp(location);
1537  } else if (location.IsRegisterPair()) {
1538    locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1539    locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1540  } else {
1541    UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1542  }
1543}
1544
1545template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1546inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
1547    const ArenaDeque<PcRelativePatchInfo>& infos,
1548    ArenaVector<LinkerPatch>* linker_patches) {
1549  for (const PcRelativePatchInfo& info : infos) {
1550    const DexFile& dex_file = info.target_dex_file;
1551    size_t offset_or_index = info.offset_or_index;
1552    DCHECK(info.high_label.IsBound());
1553    uint32_t high_offset = __ GetLabelLocation(&info.high_label);
1554    // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1555    // the assembler's base label used for PC-relative addressing.
1556    uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
1557        ? __ GetLabelLocation(&info.pc_rel_label)
1558        : __ GetPcRelBaseLabelLocation();
1559    linker_patches->push_back(Factory(high_offset, &dex_file, pc_rel_offset, offset_or_index));
1560  }
1561}
1562
1563void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
1564  DCHECK(linker_patches->empty());
1565  size_t size =
1566      pc_relative_dex_cache_patches_.size() +
1567      pc_relative_string_patches_.size() +
1568      pc_relative_type_patches_.size() +
1569      type_bss_entry_patches_.size() +
1570      boot_image_string_patches_.size() +
1571      boot_image_type_patches_.size();
1572  linker_patches->reserve(size);
1573  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
1574                                                               linker_patches);
1575  if (!GetCompilerOptions().IsBootImage()) {
1576    DCHECK(pc_relative_type_patches_.empty());
1577    EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
1578                                                                  linker_patches);
1579  } else {
1580    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
1581                                                                linker_patches);
1582    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
1583                                                                  linker_patches);
1584  }
1585  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
1586                                                              linker_patches);
1587  for (const auto& entry : boot_image_string_patches_) {
1588    const StringReference& target_string = entry.first;
1589    Literal* literal = entry.second;
1590    DCHECK(literal->GetLabel()->IsBound());
1591    uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1592    linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
1593                                                       target_string.dex_file,
1594                                                       target_string.string_index.index_));
1595  }
1596  for (const auto& entry : boot_image_type_patches_) {
1597    const TypeReference& target_type = entry.first;
1598    Literal* literal = entry.second;
1599    DCHECK(literal->GetLabel()->IsBound());
1600    uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1601    linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
1602                                                     target_type.dex_file,
1603                                                     target_type.type_index.index_));
1604  }
1605  DCHECK_EQ(size, linker_patches->size());
1606}
1607
1608CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
1609    const DexFile& dex_file, dex::StringIndex string_index) {
1610  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
1611}
1612
1613CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
1614    const DexFile& dex_file, dex::TypeIndex type_index) {
1615  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
1616}
1617
1618CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
1619    const DexFile& dex_file, dex::TypeIndex type_index) {
1620  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
1621}
1622
1623CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
1624    const DexFile& dex_file, uint32_t element_offset) {
1625  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
1626}
1627
1628CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
1629    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
1630  patches->emplace_back(dex_file, offset_or_index);
1631  return &patches->back();
1632}
1633
1634Literal* CodeGeneratorMIPS::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1635  return map->GetOrCreate(
1636      value,
1637      [this, value]() { return __ NewLiteral<uint32_t>(value); });
1638}
1639
1640Literal* CodeGeneratorMIPS::DeduplicateMethodLiteral(MethodReference target_method,
1641                                                     MethodToLiteralMap* map) {
1642  return map->GetOrCreate(
1643      target_method,
1644      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1645}
1646
1647Literal* CodeGeneratorMIPS::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
1648                                                              dex::StringIndex string_index) {
1649  return boot_image_string_patches_.GetOrCreate(
1650      StringReference(&dex_file, string_index),
1651      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1652}
1653
1654Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
1655                                                            dex::TypeIndex type_index) {
1656  return boot_image_type_patches_.GetOrCreate(
1657      TypeReference(&dex_file, type_index),
1658      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1659}
1660
1661Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address) {
1662  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
1663}
1664
1665void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
1666                                                             Register out,
1667                                                             Register base) {
1668  if (GetInstructionSetFeatures().IsR6()) {
1669    DCHECK_EQ(base, ZERO);
1670    __ Bind(&info->high_label);
1671    __ Bind(&info->pc_rel_label);
1672    // Add the high half of a 32-bit offset to PC.
1673    __ Auipc(out, /* placeholder */ 0x1234);
1674  } else {
1675    // If base is ZERO, emit NAL to obtain the actual base.
1676    if (base == ZERO) {
1677      // Generate a dummy PC-relative call to obtain PC.
1678      __ Nal();
1679    }
1680    __ Bind(&info->high_label);
1681    __ Lui(out, /* placeholder */ 0x1234);
1682    // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
1683    // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
1684    if (base == ZERO) {
1685      __ Bind(&info->pc_rel_label);
1686    }
1687    // Add the high half of a 32-bit offset to PC.
1688    __ Addu(out, out, (base == ZERO) ? RA : base);
1689  }
1690  // The immediately following instruction will add the sign-extended low half of the 32-bit
1691  // offset to `out` (e.g. lw, jialc, addiu).
1692}
1693
1694CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
1695    const DexFile& dex_file,
1696    dex::StringIndex dex_index,
1697    Handle<mirror::String> handle) {
1698  jit_string_roots_.Overwrite(StringReference(&dex_file, dex_index),
1699                              reinterpret_cast64<uint64_t>(handle.GetReference()));
1700  jit_string_patches_.emplace_back(dex_file, dex_index.index_);
1701  return &jit_string_patches_.back();
1702}
1703
1704CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootClassPatch(
1705    const DexFile& dex_file,
1706    dex::TypeIndex dex_index,
1707    Handle<mirror::Class> handle) {
1708  jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index),
1709                             reinterpret_cast64<uint64_t>(handle.GetReference()));
1710  jit_class_patches_.emplace_back(dex_file, dex_index.index_);
1711  return &jit_class_patches_.back();
1712}
1713
1714void CodeGeneratorMIPS::PatchJitRootUse(uint8_t* code,
1715                                        const uint8_t* roots_data,
1716                                        const CodeGeneratorMIPS::JitPatchInfo& info,
1717                                        uint64_t index_in_table) const {
1718  uint32_t literal_offset = GetAssembler().GetLabelLocation(&info.high_label);
1719  uintptr_t address =
1720      reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
1721  uint32_t addr32 = dchecked_integral_cast<uint32_t>(address);
1722  // lui reg, addr32_high
1723  DCHECK_EQ(code[literal_offset + 0], 0x34);
1724  DCHECK_EQ(code[literal_offset + 1], 0x12);
1725  DCHECK_EQ((code[literal_offset + 2] & 0xE0), 0x00);
1726  DCHECK_EQ(code[literal_offset + 3], 0x3C);
1727  // lw reg, reg, addr32_low
1728  DCHECK_EQ(code[literal_offset + 4], 0x78);
1729  DCHECK_EQ(code[literal_offset + 5], 0x56);
1730  DCHECK_EQ((code[literal_offset + 7] & 0xFC), 0x8C);
1731  addr32 += (addr32 & 0x8000) << 1;  // Account for sign extension in "lw reg, reg, addr32_low".
1732  // lui reg, addr32_high
1733  code[literal_offset + 0] = static_cast<uint8_t>(addr32 >> 16);
1734  code[literal_offset + 1] = static_cast<uint8_t>(addr32 >> 24);
1735  // lw reg, reg, addr32_low
1736  code[literal_offset + 4] = static_cast<uint8_t>(addr32 >> 0);
1737  code[literal_offset + 5] = static_cast<uint8_t>(addr32 >> 8);
1738}
1739
1740void CodeGeneratorMIPS::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
1741  for (const JitPatchInfo& info : jit_string_patches_) {
1742    const auto& it = jit_string_roots_.find(StringReference(&info.target_dex_file,
1743                                                            dex::StringIndex(info.index)));
1744    DCHECK(it != jit_string_roots_.end());
1745    PatchJitRootUse(code, roots_data, info, it->second);
1746  }
1747  for (const JitPatchInfo& info : jit_class_patches_) {
1748    const auto& it = jit_class_roots_.find(TypeReference(&info.target_dex_file,
1749                                                         dex::TypeIndex(info.index)));
1750    DCHECK(it != jit_class_roots_.end());
1751    PatchJitRootUse(code, roots_data, info, it->second);
1752  }
1753}
1754
1755void CodeGeneratorMIPS::MarkGCCard(Register object,
1756                                   Register value,
1757                                   bool value_can_be_null) {
1758  MipsLabel done;
1759  Register card = AT;
1760  Register temp = TMP;
1761  if (value_can_be_null) {
1762    __ Beqz(value, &done);
1763  }
1764  __ LoadFromOffset(kLoadWord,
1765                    card,
1766                    TR,
1767                    Thread::CardTableOffset<kMipsPointerSize>().Int32Value());
1768  __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1769  __ Addu(temp, card, temp);
1770  __ Sb(card, temp, 0);
1771  if (value_can_be_null) {
1772    __ Bind(&done);
1773  }
1774}
1775
1776void CodeGeneratorMIPS::SetupBlockedRegisters() const {
1777  // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1778  blocked_core_registers_[ZERO] = true;
1779  blocked_core_registers_[K0] = true;
1780  blocked_core_registers_[K1] = true;
1781  blocked_core_registers_[GP] = true;
1782  blocked_core_registers_[SP] = true;
1783  blocked_core_registers_[RA] = true;
1784
1785  // AT and TMP(T8) are used as temporary/scratch registers
1786  // (similar to how AT is used by MIPS assemblers).
1787  blocked_core_registers_[AT] = true;
1788  blocked_core_registers_[TMP] = true;
1789  blocked_fpu_registers_[FTMP] = true;
1790
1791  // Reserve suspend and thread registers.
1792  blocked_core_registers_[S0] = true;
1793  blocked_core_registers_[TR] = true;
1794
1795  // Reserve T9 for function calls
1796  blocked_core_registers_[T9] = true;
1797
1798  // Reserve odd-numbered FPU registers.
1799  for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1800    blocked_fpu_registers_[i] = true;
1801  }
1802
1803  if (GetGraph()->IsDebuggable()) {
1804    // Stubs do not save callee-save floating point registers. If the graph
1805    // is debuggable, we need to deal with these registers differently. For
1806    // now, just block them.
1807    for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1808      blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1809    }
1810  }
1811}
1812
1813size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1814  __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1815  return kMipsWordSize;
1816}
1817
1818size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1819  __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1820  return kMipsWordSize;
1821}
1822
1823size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1824  __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1825  return kMipsDoublewordSize;
1826}
1827
1828size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1829  __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1830  return kMipsDoublewordSize;
1831}
1832
1833void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
1834  stream << Register(reg);
1835}
1836
1837void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
1838  stream << FRegister(reg);
1839}
1840
1841constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1842
1843void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1844                                      HInstruction* instruction,
1845                                      uint32_t dex_pc,
1846                                      SlowPathCode* slow_path) {
1847  ValidateInvokeRuntime(entrypoint, instruction, slow_path);
1848  GenerateInvokeRuntime(GetThreadOffset<kMipsPointerSize>(entrypoint).Int32Value(),
1849                        IsDirectEntrypoint(entrypoint));
1850  if (EntrypointRequiresStackMap(entrypoint)) {
1851    RecordPcInfo(instruction, dex_pc, slow_path);
1852  }
1853}
1854
1855void CodeGeneratorMIPS::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1856                                                            HInstruction* instruction,
1857                                                            SlowPathCode* slow_path,
1858                                                            bool direct) {
1859  ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1860  GenerateInvokeRuntime(entry_point_offset, direct);
1861}
1862
1863void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool direct) {
1864  bool reordering = __ SetReorder(false);
1865  __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
1866  __ Jalr(T9);
1867  if (direct) {
1868    // Reserve argument space on stack (for $a0-$a3) for
1869    // entrypoints that directly reference native implementations.
1870    // Called function may use this space to store $a0-$a3 regs.
1871    __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);  // Single instruction in delay slot.
1872    __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
1873  } else {
1874    __ Nop();  // In delay slot.
1875  }
1876  __ SetReorder(reordering);
1877}
1878
1879void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1880                                                                    Register class_reg) {
1881  __ LoadFromOffset(kLoadWord, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
1882  __ LoadConst32(AT, mirror::Class::kStatusInitialized);
1883  __ Blt(TMP, AT, slow_path->GetEntryLabel());
1884  // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1885  __ Sync(0);
1886  __ Bind(slow_path->GetExitLabel());
1887}
1888
1889void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1890  __ Sync(0);  // Only stype 0 is supported.
1891}
1892
1893void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
1894                                                        HBasicBlock* successor) {
1895  SuspendCheckSlowPathMIPS* slow_path =
1896    new (GetGraph()->GetArena()) SuspendCheckSlowPathMIPS(instruction, successor);
1897  codegen_->AddSlowPath(slow_path);
1898
1899  __ LoadFromOffset(kLoadUnsignedHalfword,
1900                    TMP,
1901                    TR,
1902                    Thread::ThreadFlagsOffset<kMipsPointerSize>().Int32Value());
1903  if (successor == nullptr) {
1904    __ Bnez(TMP, slow_path->GetEntryLabel());
1905    __ Bind(slow_path->GetReturnLabel());
1906  } else {
1907    __ Beqz(TMP, codegen_->GetLabelOf(successor));
1908    __ B(slow_path->GetEntryLabel());
1909    // slow_path will return to GetLabelOf(successor).
1910  }
1911}
1912
1913InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
1914                                                           CodeGeneratorMIPS* codegen)
1915      : InstructionCodeGenerator(graph, codegen),
1916        assembler_(codegen->GetAssembler()),
1917        codegen_(codegen) {}
1918
1919void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1920  DCHECK_EQ(instruction->InputCount(), 2U);
1921  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1922  Primitive::Type type = instruction->GetResultType();
1923  switch (type) {
1924    case Primitive::kPrimInt: {
1925      locations->SetInAt(0, Location::RequiresRegister());
1926      HInstruction* right = instruction->InputAt(1);
1927      bool can_use_imm = false;
1928      if (right->IsConstant()) {
1929        int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
1930        if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1931          can_use_imm = IsUint<16>(imm);
1932        } else if (instruction->IsAdd()) {
1933          can_use_imm = IsInt<16>(imm);
1934        } else {
1935          DCHECK(instruction->IsSub());
1936          can_use_imm = IsInt<16>(-imm);
1937        }
1938      }
1939      if (can_use_imm)
1940        locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1941      else
1942        locations->SetInAt(1, Location::RequiresRegister());
1943      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1944      break;
1945    }
1946
1947    case Primitive::kPrimLong: {
1948      locations->SetInAt(0, Location::RequiresRegister());
1949      locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1950      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1951      break;
1952    }
1953
1954    case Primitive::kPrimFloat:
1955    case Primitive::kPrimDouble:
1956      DCHECK(instruction->IsAdd() || instruction->IsSub());
1957      locations->SetInAt(0, Location::RequiresFpuRegister());
1958      locations->SetInAt(1, Location::RequiresFpuRegister());
1959      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1960      break;
1961
1962    default:
1963      LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
1964  }
1965}
1966
1967void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1968  Primitive::Type type = instruction->GetType();
1969  LocationSummary* locations = instruction->GetLocations();
1970
1971  switch (type) {
1972    case Primitive::kPrimInt: {
1973      Register dst = locations->Out().AsRegister<Register>();
1974      Register lhs = locations->InAt(0).AsRegister<Register>();
1975      Location rhs_location = locations->InAt(1);
1976
1977      Register rhs_reg = ZERO;
1978      int32_t rhs_imm = 0;
1979      bool use_imm = rhs_location.IsConstant();
1980      if (use_imm) {
1981        rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
1982      } else {
1983        rhs_reg = rhs_location.AsRegister<Register>();
1984      }
1985
1986      if (instruction->IsAnd()) {
1987        if (use_imm)
1988          __ Andi(dst, lhs, rhs_imm);
1989        else
1990          __ And(dst, lhs, rhs_reg);
1991      } else if (instruction->IsOr()) {
1992        if (use_imm)
1993          __ Ori(dst, lhs, rhs_imm);
1994        else
1995          __ Or(dst, lhs, rhs_reg);
1996      } else if (instruction->IsXor()) {
1997        if (use_imm)
1998          __ Xori(dst, lhs, rhs_imm);
1999        else
2000          __ Xor(dst, lhs, rhs_reg);
2001      } else if (instruction->IsAdd()) {
2002        if (use_imm)
2003          __ Addiu(dst, lhs, rhs_imm);
2004        else
2005          __ Addu(dst, lhs, rhs_reg);
2006      } else {
2007        DCHECK(instruction->IsSub());
2008        if (use_imm)
2009          __ Addiu(dst, lhs, -rhs_imm);
2010        else
2011          __ Subu(dst, lhs, rhs_reg);
2012      }
2013      break;
2014    }
2015
2016    case Primitive::kPrimLong: {
2017      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2018      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2019      Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2020      Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2021      Location rhs_location = locations->InAt(1);
2022      bool use_imm = rhs_location.IsConstant();
2023      if (!use_imm) {
2024        Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
2025        Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
2026        if (instruction->IsAnd()) {
2027          __ And(dst_low, lhs_low, rhs_low);
2028          __ And(dst_high, lhs_high, rhs_high);
2029        } else if (instruction->IsOr()) {
2030          __ Or(dst_low, lhs_low, rhs_low);
2031          __ Or(dst_high, lhs_high, rhs_high);
2032        } else if (instruction->IsXor()) {
2033          __ Xor(dst_low, lhs_low, rhs_low);
2034          __ Xor(dst_high, lhs_high, rhs_high);
2035        } else if (instruction->IsAdd()) {
2036          if (lhs_low == rhs_low) {
2037            // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
2038            __ Slt(TMP, lhs_low, ZERO);
2039            __ Addu(dst_low, lhs_low, rhs_low);
2040          } else {
2041            __ Addu(dst_low, lhs_low, rhs_low);
2042            // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
2043            __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
2044          }
2045          __ Addu(dst_high, lhs_high, rhs_high);
2046          __ Addu(dst_high, dst_high, TMP);
2047        } else {
2048          DCHECK(instruction->IsSub());
2049          __ Sltu(TMP, lhs_low, rhs_low);
2050          __ Subu(dst_low, lhs_low, rhs_low);
2051          __ Subu(dst_high, lhs_high, rhs_high);
2052          __ Subu(dst_high, dst_high, TMP);
2053        }
2054      } else {
2055        int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
2056        if (instruction->IsOr()) {
2057          uint32_t low = Low32Bits(value);
2058          uint32_t high = High32Bits(value);
2059          if (IsUint<16>(low)) {
2060            if (dst_low != lhs_low || low != 0) {
2061              __ Ori(dst_low, lhs_low, low);
2062            }
2063          } else {
2064            __ LoadConst32(TMP, low);
2065            __ Or(dst_low, lhs_low, TMP);
2066          }
2067          if (IsUint<16>(high)) {
2068            if (dst_high != lhs_high || high != 0) {
2069              __ Ori(dst_high, lhs_high, high);
2070            }
2071          } else {
2072            if (high != low) {
2073              __ LoadConst32(TMP, high);
2074            }
2075            __ Or(dst_high, lhs_high, TMP);
2076          }
2077        } else if (instruction->IsXor()) {
2078          uint32_t low = Low32Bits(value);
2079          uint32_t high = High32Bits(value);
2080          if (IsUint<16>(low)) {
2081            if (dst_low != lhs_low || low != 0) {
2082              __ Xori(dst_low, lhs_low, low);
2083            }
2084          } else {
2085            __ LoadConst32(TMP, low);
2086            __ Xor(dst_low, lhs_low, TMP);
2087          }
2088          if (IsUint<16>(high)) {
2089            if (dst_high != lhs_high || high != 0) {
2090              __ Xori(dst_high, lhs_high, high);
2091            }
2092          } else {
2093            if (high != low) {
2094              __ LoadConst32(TMP, high);
2095            }
2096            __ Xor(dst_high, lhs_high, TMP);
2097          }
2098        } else if (instruction->IsAnd()) {
2099          uint32_t low = Low32Bits(value);
2100          uint32_t high = High32Bits(value);
2101          if (IsUint<16>(low)) {
2102            __ Andi(dst_low, lhs_low, low);
2103          } else if (low != 0xFFFFFFFF) {
2104            __ LoadConst32(TMP, low);
2105            __ And(dst_low, lhs_low, TMP);
2106          } else if (dst_low != lhs_low) {
2107            __ Move(dst_low, lhs_low);
2108          }
2109          if (IsUint<16>(high)) {
2110            __ Andi(dst_high, lhs_high, high);
2111          } else if (high != 0xFFFFFFFF) {
2112            if (high != low) {
2113              __ LoadConst32(TMP, high);
2114            }
2115            __ And(dst_high, lhs_high, TMP);
2116          } else if (dst_high != lhs_high) {
2117            __ Move(dst_high, lhs_high);
2118          }
2119        } else {
2120          if (instruction->IsSub()) {
2121            value = -value;
2122          } else {
2123            DCHECK(instruction->IsAdd());
2124          }
2125          int32_t low = Low32Bits(value);
2126          int32_t high = High32Bits(value);
2127          if (IsInt<16>(low)) {
2128            if (dst_low != lhs_low || low != 0) {
2129              __ Addiu(dst_low, lhs_low, low);
2130            }
2131            if (low != 0) {
2132              __ Sltiu(AT, dst_low, low);
2133            }
2134          } else {
2135            __ LoadConst32(TMP, low);
2136            __ Addu(dst_low, lhs_low, TMP);
2137            __ Sltu(AT, dst_low, TMP);
2138          }
2139          if (IsInt<16>(high)) {
2140            if (dst_high != lhs_high || high != 0) {
2141              __ Addiu(dst_high, lhs_high, high);
2142            }
2143          } else {
2144            if (high != low) {
2145              __ LoadConst32(TMP, high);
2146            }
2147            __ Addu(dst_high, lhs_high, TMP);
2148          }
2149          if (low != 0) {
2150            __ Addu(dst_high, dst_high, AT);
2151          }
2152        }
2153      }
2154      break;
2155    }
2156
2157    case Primitive::kPrimFloat:
2158    case Primitive::kPrimDouble: {
2159      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2160      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2161      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2162      if (instruction->IsAdd()) {
2163        if (type == Primitive::kPrimFloat) {
2164          __ AddS(dst, lhs, rhs);
2165        } else {
2166          __ AddD(dst, lhs, rhs);
2167        }
2168      } else {
2169        DCHECK(instruction->IsSub());
2170        if (type == Primitive::kPrimFloat) {
2171          __ SubS(dst, lhs, rhs);
2172        } else {
2173          __ SubD(dst, lhs, rhs);
2174        }
2175      }
2176      break;
2177    }
2178
2179    default:
2180      LOG(FATAL) << "Unexpected binary operation type " << type;
2181  }
2182}
2183
2184void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
2185  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
2186
2187  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
2188  Primitive::Type type = instr->GetResultType();
2189  switch (type) {
2190    case Primitive::kPrimInt:
2191      locations->SetInAt(0, Location::RequiresRegister());
2192      locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2193      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2194      break;
2195    case Primitive::kPrimLong:
2196      locations->SetInAt(0, Location::RequiresRegister());
2197      locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2198      locations->SetOut(Location::RequiresRegister());
2199      break;
2200    default:
2201      LOG(FATAL) << "Unexpected shift type " << type;
2202  }
2203}
2204
2205static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
2206
2207void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
2208  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
2209  LocationSummary* locations = instr->GetLocations();
2210  Primitive::Type type = instr->GetType();
2211
2212  Location rhs_location = locations->InAt(1);
2213  bool use_imm = rhs_location.IsConstant();
2214  Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
2215  int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
2216  const uint32_t shift_mask =
2217      (type == Primitive::kPrimInt) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
2218  const uint32_t shift_value = rhs_imm & shift_mask;
2219  // Are the INS (Insert Bit Field) and ROTR instructions supported?
2220  bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
2221
2222  switch (type) {
2223    case Primitive::kPrimInt: {
2224      Register dst = locations->Out().AsRegister<Register>();
2225      Register lhs = locations->InAt(0).AsRegister<Register>();
2226      if (use_imm) {
2227        if (shift_value == 0) {
2228          if (dst != lhs) {
2229            __ Move(dst, lhs);
2230          }
2231        } else if (instr->IsShl()) {
2232          __ Sll(dst, lhs, shift_value);
2233        } else if (instr->IsShr()) {
2234          __ Sra(dst, lhs, shift_value);
2235        } else if (instr->IsUShr()) {
2236          __ Srl(dst, lhs, shift_value);
2237        } else {
2238          if (has_ins_rotr) {
2239            __ Rotr(dst, lhs, shift_value);
2240          } else {
2241            __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
2242            __ Srl(dst, lhs, shift_value);
2243            __ Or(dst, dst, TMP);
2244          }
2245        }
2246      } else {
2247        if (instr->IsShl()) {
2248          __ Sllv(dst, lhs, rhs_reg);
2249        } else if (instr->IsShr()) {
2250          __ Srav(dst, lhs, rhs_reg);
2251        } else if (instr->IsUShr()) {
2252          __ Srlv(dst, lhs, rhs_reg);
2253        } else {
2254          if (has_ins_rotr) {
2255            __ Rotrv(dst, lhs, rhs_reg);
2256          } else {
2257            __ Subu(TMP, ZERO, rhs_reg);
2258            // 32-bit shift instructions use the 5 least significant bits of the shift count, so
2259            // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
2260            // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
2261            // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
2262            // IOW, the OR'd values are equal.
2263            __ Sllv(TMP, lhs, TMP);
2264            __ Srlv(dst, lhs, rhs_reg);
2265            __ Or(dst, dst, TMP);
2266          }
2267        }
2268      }
2269      break;
2270    }
2271
2272    case Primitive::kPrimLong: {
2273      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2274      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2275      Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2276      Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2277      if (use_imm) {
2278          if (shift_value == 0) {
2279            codegen_->Move64(locations->Out(), locations->InAt(0));
2280          } else if (shift_value < kMipsBitsPerWord) {
2281            if (has_ins_rotr) {
2282              if (instr->IsShl()) {
2283                __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2284                __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
2285                __ Sll(dst_low, lhs_low, shift_value);
2286              } else if (instr->IsShr()) {
2287                __ Srl(dst_low, lhs_low, shift_value);
2288                __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2289                __ Sra(dst_high, lhs_high, shift_value);
2290              } else if (instr->IsUShr()) {
2291                __ Srl(dst_low, lhs_low, shift_value);
2292                __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2293                __ Srl(dst_high, lhs_high, shift_value);
2294              } else {
2295                __ Srl(dst_low, lhs_low, shift_value);
2296                __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2297                __ Srl(dst_high, lhs_high, shift_value);
2298                __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
2299              }
2300            } else {
2301              if (instr->IsShl()) {
2302                __ Sll(dst_low, lhs_low, shift_value);
2303                __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
2304                __ Sll(dst_high, lhs_high, shift_value);
2305                __ Or(dst_high, dst_high, TMP);
2306              } else if (instr->IsShr()) {
2307                __ Sra(dst_high, lhs_high, shift_value);
2308                __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2309                __ Srl(dst_low, lhs_low, shift_value);
2310                __ Or(dst_low, dst_low, TMP);
2311              } else if (instr->IsUShr()) {
2312                __ Srl(dst_high, lhs_high, shift_value);
2313                __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2314                __ Srl(dst_low, lhs_low, shift_value);
2315                __ Or(dst_low, dst_low, TMP);
2316              } else {
2317                __ Srl(TMP, lhs_low, shift_value);
2318                __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
2319                __ Or(dst_low, dst_low, TMP);
2320                __ Srl(TMP, lhs_high, shift_value);
2321                __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2322                __ Or(dst_high, dst_high, TMP);
2323              }
2324            }
2325          } else {
2326            const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
2327            if (instr->IsShl()) {
2328              __ Sll(dst_high, lhs_low, shift_value_high);
2329              __ Move(dst_low, ZERO);
2330            } else if (instr->IsShr()) {
2331              __ Sra(dst_low, lhs_high, shift_value_high);
2332              __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
2333            } else if (instr->IsUShr()) {
2334              __ Srl(dst_low, lhs_high, shift_value_high);
2335              __ Move(dst_high, ZERO);
2336            } else {
2337              if (shift_value == kMipsBitsPerWord) {
2338                // 64-bit rotation by 32 is just a swap.
2339                __ Move(dst_low, lhs_high);
2340                __ Move(dst_high, lhs_low);
2341              } else {
2342                if (has_ins_rotr) {
2343                  __ Srl(dst_low, lhs_high, shift_value_high);
2344                  __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
2345                  __ Srl(dst_high, lhs_low, shift_value_high);
2346                  __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
2347                } else {
2348                  __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
2349                  __ Srl(dst_low, lhs_high, shift_value_high);
2350                  __ Or(dst_low, dst_low, TMP);
2351                  __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
2352                  __ Srl(dst_high, lhs_low, shift_value_high);
2353                  __ Or(dst_high, dst_high, TMP);
2354                }
2355              }
2356            }
2357          }
2358      } else {
2359        MipsLabel done;
2360        if (instr->IsShl()) {
2361          __ Sllv(dst_low, lhs_low, rhs_reg);
2362          __ Nor(AT, ZERO, rhs_reg);
2363          __ Srl(TMP, lhs_low, 1);
2364          __ Srlv(TMP, TMP, AT);
2365          __ Sllv(dst_high, lhs_high, rhs_reg);
2366          __ Or(dst_high, dst_high, TMP);
2367          __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
2368          __ Beqz(TMP, &done);
2369          __ Move(dst_high, dst_low);
2370          __ Move(dst_low, ZERO);
2371        } else if (instr->IsShr()) {
2372          __ Srav(dst_high, lhs_high, rhs_reg);
2373          __ Nor(AT, ZERO, rhs_reg);
2374          __ Sll(TMP, lhs_high, 1);
2375          __ Sllv(TMP, TMP, AT);
2376          __ Srlv(dst_low, lhs_low, rhs_reg);
2377          __ Or(dst_low, dst_low, TMP);
2378          __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
2379          __ Beqz(TMP, &done);
2380          __ Move(dst_low, dst_high);
2381          __ Sra(dst_high, dst_high, 31);
2382        } else if (instr->IsUShr()) {
2383          __ Srlv(dst_high, lhs_high, rhs_reg);
2384          __ Nor(AT, ZERO, rhs_reg);
2385          __ Sll(TMP, lhs_high, 1);
2386          __ Sllv(TMP, TMP, AT);
2387          __ Srlv(dst_low, lhs_low, rhs_reg);
2388          __ Or(dst_low, dst_low, TMP);
2389          __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
2390          __ Beqz(TMP, &done);
2391          __ Move(dst_low, dst_high);
2392          __ Move(dst_high, ZERO);
2393        } else {
2394          __ Nor(AT, ZERO, rhs_reg);
2395          __ Srlv(TMP, lhs_low, rhs_reg);
2396          __ Sll(dst_low, lhs_high, 1);
2397          __ Sllv(dst_low, dst_low, AT);
2398          __ Or(dst_low, dst_low, TMP);
2399          __ Srlv(TMP, lhs_high, rhs_reg);
2400          __ Sll(dst_high, lhs_low, 1);
2401          __ Sllv(dst_high, dst_high, AT);
2402          __ Or(dst_high, dst_high, TMP);
2403          __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
2404          __ Beqz(TMP, &done);
2405          __ Move(TMP, dst_high);
2406          __ Move(dst_high, dst_low);
2407          __ Move(dst_low, TMP);
2408        }
2409        __ Bind(&done);
2410      }
2411      break;
2412    }
2413
2414    default:
2415      LOG(FATAL) << "Unexpected shift operation type " << type;
2416  }
2417}
2418
2419void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
2420  HandleBinaryOp(instruction);
2421}
2422
2423void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
2424  HandleBinaryOp(instruction);
2425}
2426
2427void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
2428  HandleBinaryOp(instruction);
2429}
2430
2431void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
2432  HandleBinaryOp(instruction);
2433}
2434
2435void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
2436  Primitive::Type type = instruction->GetType();
2437  bool object_array_get_with_read_barrier =
2438      kEmitCompilerReadBarrier && (type == Primitive::kPrimNot);
2439  LocationSummary* locations =
2440      new (GetGraph()->GetArena()) LocationSummary(instruction,
2441                                                   object_array_get_with_read_barrier
2442                                                       ? LocationSummary::kCallOnSlowPath
2443                                                       : LocationSummary::kNoCall);
2444  locations->SetInAt(0, Location::RequiresRegister());
2445  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2446  if (Primitive::IsFloatingPointType(type)) {
2447    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2448  } else {
2449    // The output overlaps in the case of an object array get with
2450    // read barriers enabled: we do not want the move to overwrite the
2451    // array's location, as we need it to emit the read barrier.
2452    locations->SetOut(Location::RequiresRegister(),
2453                      object_array_get_with_read_barrier
2454                          ? Location::kOutputOverlap
2455                          : Location::kNoOutputOverlap);
2456  }
2457  // We need a temporary register for the read barrier marking slow
2458  // path in CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier.
2459  if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
2460    locations->AddTemp(Location::RequiresRegister());
2461  }
2462}
2463
2464static auto GetImplicitNullChecker(HInstruction* instruction, CodeGeneratorMIPS* codegen) {
2465  auto null_checker = [codegen, instruction]() {
2466    codegen->MaybeRecordImplicitNullCheck(instruction);
2467  };
2468  return null_checker;
2469}
2470
2471void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
2472  LocationSummary* locations = instruction->GetLocations();
2473  Location obj_loc = locations->InAt(0);
2474  Register obj = obj_loc.AsRegister<Register>();
2475  Location out_loc = locations->Out();
2476  Location index = locations->InAt(1);
2477  uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
2478  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
2479
2480  Primitive::Type type = instruction->GetType();
2481  const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
2482                                        instruction->IsStringCharAt();
2483  switch (type) {
2484    case Primitive::kPrimBoolean: {
2485      Register out = out_loc.AsRegister<Register>();
2486      if (index.IsConstant()) {
2487        size_t offset =
2488            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2489        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
2490      } else {
2491        __ Addu(TMP, obj, index.AsRegister<Register>());
2492        __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
2493      }
2494      break;
2495    }
2496
2497    case Primitive::kPrimByte: {
2498      Register out = out_loc.AsRegister<Register>();
2499      if (index.IsConstant()) {
2500        size_t offset =
2501            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2502        __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
2503      } else {
2504        __ Addu(TMP, obj, index.AsRegister<Register>());
2505        __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
2506      }
2507      break;
2508    }
2509
2510    case Primitive::kPrimShort: {
2511      Register out = out_loc.AsRegister<Register>();
2512      if (index.IsConstant()) {
2513        size_t offset =
2514            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2515        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
2516      } else {
2517        __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
2518        __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
2519      }
2520      break;
2521    }
2522
2523    case Primitive::kPrimChar: {
2524      Register out = out_loc.AsRegister<Register>();
2525      if (maybe_compressed_char_at) {
2526        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2527        __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker);
2528        __ Sll(TMP, TMP, 31);    // Extract compression flag into the most significant bit of TMP.
2529        static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2530                      "Expecting 0=compressed, 1=uncompressed");
2531      }
2532      if (index.IsConstant()) {
2533        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
2534        if (maybe_compressed_char_at) {
2535          MipsLabel uncompressed_load, done;
2536          __ Bnez(TMP, &uncompressed_load);
2537          __ LoadFromOffset(kLoadUnsignedByte,
2538                            out,
2539                            obj,
2540                            data_offset + (const_index << TIMES_1));
2541          __ B(&done);
2542          __ Bind(&uncompressed_load);
2543          __ LoadFromOffset(kLoadUnsignedHalfword,
2544                            out,
2545                            obj,
2546                            data_offset + (const_index << TIMES_2));
2547          __ Bind(&done);
2548        } else {
2549          __ LoadFromOffset(kLoadUnsignedHalfword,
2550                            out,
2551                            obj,
2552                            data_offset + (const_index << TIMES_2),
2553                            null_checker);
2554        }
2555      } else {
2556        Register index_reg = index.AsRegister<Register>();
2557        if (maybe_compressed_char_at) {
2558          MipsLabel uncompressed_load, done;
2559          __ Bnez(TMP, &uncompressed_load);
2560          __ Addu(TMP, obj, index_reg);
2561          __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
2562          __ B(&done);
2563          __ Bind(&uncompressed_load);
2564          __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
2565          __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
2566          __ Bind(&done);
2567        } else {
2568          __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
2569          __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
2570        }
2571      }
2572      break;
2573    }
2574
2575    case Primitive::kPrimInt: {
2576      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2577      Register out = out_loc.AsRegister<Register>();
2578      if (index.IsConstant()) {
2579        size_t offset =
2580            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2581        __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
2582      } else {
2583        __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
2584        __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
2585      }
2586      break;
2587    }
2588
2589    case Primitive::kPrimNot: {
2590      static_assert(
2591          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
2592          "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
2593      // /* HeapReference<Object> */ out =
2594      //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
2595      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
2596        Location temp = locations->GetTemp(0);
2597        // Note that a potential implicit null check is handled in this
2598        // CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier call.
2599        codegen_->GenerateArrayLoadWithBakerReadBarrier(instruction,
2600                                                        out_loc,
2601                                                        obj,
2602                                                        data_offset,
2603                                                        index,
2604                                                        temp,
2605                                                        /* needs_null_check */ true);
2606      } else {
2607        Register out = out_loc.AsRegister<Register>();
2608        if (index.IsConstant()) {
2609          size_t offset =
2610              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2611          __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
2612          // If read barriers are enabled, emit read barriers other than
2613          // Baker's using a slow path (and also unpoison the loaded
2614          // reference, if heap poisoning is enabled).
2615          codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
2616        } else {
2617          __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
2618          __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
2619          // If read barriers are enabled, emit read barriers other than
2620          // Baker's using a slow path (and also unpoison the loaded
2621          // reference, if heap poisoning is enabled).
2622          codegen_->MaybeGenerateReadBarrierSlow(instruction,
2623                                                 out_loc,
2624                                                 out_loc,
2625                                                 obj_loc,
2626                                                 data_offset,
2627                                                 index);
2628        }
2629      }
2630      break;
2631    }
2632
2633    case Primitive::kPrimLong: {
2634      Register out = out_loc.AsRegisterPairLow<Register>();
2635      if (index.IsConstant()) {
2636        size_t offset =
2637            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
2638        __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
2639      } else {
2640        __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
2641        __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
2642      }
2643      break;
2644    }
2645
2646    case Primitive::kPrimFloat: {
2647      FRegister out = out_loc.AsFpuRegister<FRegister>();
2648      if (index.IsConstant()) {
2649        size_t offset =
2650            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2651        __ LoadSFromOffset(out, obj, offset, null_checker);
2652      } else {
2653        __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
2654        __ LoadSFromOffset(out, TMP, data_offset, null_checker);
2655      }
2656      break;
2657    }
2658
2659    case Primitive::kPrimDouble: {
2660      FRegister out = out_loc.AsFpuRegister<FRegister>();
2661      if (index.IsConstant()) {
2662        size_t offset =
2663            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
2664        __ LoadDFromOffset(out, obj, offset, null_checker);
2665      } else {
2666        __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
2667        __ LoadDFromOffset(out, TMP, data_offset, null_checker);
2668      }
2669      break;
2670    }
2671
2672    case Primitive::kPrimVoid:
2673      LOG(FATAL) << "Unreachable type " << instruction->GetType();
2674      UNREACHABLE();
2675  }
2676}
2677
2678void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
2679  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2680  locations->SetInAt(0, Location::RequiresRegister());
2681  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2682}
2683
2684void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
2685  LocationSummary* locations = instruction->GetLocations();
2686  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
2687  Register obj = locations->InAt(0).AsRegister<Register>();
2688  Register out = locations->Out().AsRegister<Register>();
2689  __ LoadFromOffset(kLoadWord, out, obj, offset);
2690  codegen_->MaybeRecordImplicitNullCheck(instruction);
2691  // Mask out compression flag from String's array length.
2692  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
2693    __ Srl(out, out, 1u);
2694  }
2695}
2696
2697Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) {
2698  return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
2699      ? Location::ConstantLocation(instruction->AsConstant())
2700      : Location::RequiresRegister();
2701}
2702
2703Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) {
2704  // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
2705  // We can store a non-zero float or double constant without first loading it into the FPU,
2706  // but we should only prefer this if the constant has a single use.
2707  if (instruction->IsConstant() &&
2708      (instruction->AsConstant()->IsZeroBitPattern() ||
2709       instruction->GetUses().HasExactlyOneElement())) {
2710    return Location::ConstantLocation(instruction->AsConstant());
2711    // Otherwise fall through and require an FPU register for the constant.
2712  }
2713  return Location::RequiresFpuRegister();
2714}
2715
2716void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
2717  Primitive::Type value_type = instruction->GetComponentType();
2718
2719  bool needs_write_barrier =
2720      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2721  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2722
2723  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2724      instruction,
2725      may_need_runtime_call_for_type_check ?
2726          LocationSummary::kCallOnSlowPath :
2727          LocationSummary::kNoCall);
2728
2729  locations->SetInAt(0, Location::RequiresRegister());
2730  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2731  if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
2732    locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
2733  } else {
2734    locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
2735  }
2736  if (needs_write_barrier) {
2737    // Temporary register for the write barrier.
2738    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
2739  }
2740}
2741
2742void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
2743  LocationSummary* locations = instruction->GetLocations();
2744  Register obj = locations->InAt(0).AsRegister<Register>();
2745  Location index = locations->InAt(1);
2746  Location value_location = locations->InAt(2);
2747  Primitive::Type value_type = instruction->GetComponentType();
2748  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2749  bool needs_write_barrier =
2750      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2751  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
2752  Register base_reg = index.IsConstant() ? obj : TMP;
2753
2754  switch (value_type) {
2755    case Primitive::kPrimBoolean:
2756    case Primitive::kPrimByte: {
2757      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
2758      if (index.IsConstant()) {
2759        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
2760      } else {
2761        __ Addu(base_reg, obj, index.AsRegister<Register>());
2762      }
2763      if (value_location.IsConstant()) {
2764        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2765        __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2766      } else {
2767        Register value = value_location.AsRegister<Register>();
2768        __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
2769      }
2770      break;
2771    }
2772
2773    case Primitive::kPrimShort:
2774    case Primitive::kPrimChar: {
2775      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
2776      if (index.IsConstant()) {
2777        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
2778      } else {
2779        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
2780      }
2781      if (value_location.IsConstant()) {
2782        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2783        __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
2784      } else {
2785        Register value = value_location.AsRegister<Register>();
2786        __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
2787      }
2788      break;
2789    }
2790
2791    case Primitive::kPrimInt: {
2792      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2793      if (index.IsConstant()) {
2794        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2795      } else {
2796        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
2797      }
2798      if (value_location.IsConstant()) {
2799        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2800        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2801      } else {
2802        Register value = value_location.AsRegister<Register>();
2803        __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2804      }
2805      break;
2806    }
2807
2808    case Primitive::kPrimNot: {
2809      if (value_location.IsConstant()) {
2810        // Just setting null.
2811        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2812        if (index.IsConstant()) {
2813          data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2814        } else {
2815          __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
2816        }
2817        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2818        DCHECK_EQ(value, 0);
2819        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2820        DCHECK(!needs_write_barrier);
2821        DCHECK(!may_need_runtime_call_for_type_check);
2822        break;
2823      }
2824
2825      DCHECK(needs_write_barrier);
2826      Register value = value_location.AsRegister<Register>();
2827      Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2828      Register temp2 = TMP;  // Doesn't need to survive slow path.
2829      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2830      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
2831      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
2832      MipsLabel done;
2833      SlowPathCodeMIPS* slow_path = nullptr;
2834
2835      if (may_need_runtime_call_for_type_check) {
2836        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathMIPS(instruction);
2837        codegen_->AddSlowPath(slow_path);
2838        if (instruction->GetValueCanBeNull()) {
2839          MipsLabel non_zero;
2840          __ Bnez(value, &non_zero);
2841          uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2842          if (index.IsConstant()) {
2843            data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2844          } else {
2845            __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
2846          }
2847          __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2848          __ B(&done);
2849          __ Bind(&non_zero);
2850        }
2851
2852        // Note that when read barriers are enabled, the type checks
2853        // are performed without read barriers.  This is fine, even in
2854        // the case where a class object is in the from-space after
2855        // the flip, as a comparison involving such a type would not
2856        // produce a false positive; it may of course produce a false
2857        // negative, in which case we would take the ArraySet slow
2858        // path.
2859
2860        // /* HeapReference<Class> */ temp1 = obj->klass_
2861        __ LoadFromOffset(kLoadWord, temp1, obj, class_offset, null_checker);
2862        __ MaybeUnpoisonHeapReference(temp1);
2863
2864        // /* HeapReference<Class> */ temp1 = temp1->component_type_
2865        __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
2866        // /* HeapReference<Class> */ temp2 = value->klass_
2867        __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
2868        // If heap poisoning is enabled, no need to unpoison `temp1`
2869        // nor `temp2`, as we are comparing two poisoned references.
2870
2871        if (instruction->StaticTypeOfArrayIsObjectArray()) {
2872          MipsLabel do_put;
2873          __ Beq(temp1, temp2, &do_put);
2874          // If heap poisoning is enabled, the `temp1` reference has
2875          // not been unpoisoned yet; unpoison it now.
2876          __ MaybeUnpoisonHeapReference(temp1);
2877
2878          // /* HeapReference<Class> */ temp1 = temp1->super_class_
2879          __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
2880          // If heap poisoning is enabled, no need to unpoison
2881          // `temp1`, as we are comparing against null below.
2882          __ Bnez(temp1, slow_path->GetEntryLabel());
2883          __ Bind(&do_put);
2884        } else {
2885          __ Bne(temp1, temp2, slow_path->GetEntryLabel());
2886        }
2887      }
2888
2889      Register source = value;
2890      if (kPoisonHeapReferences) {
2891        // Note that in the case where `value` is a null reference,
2892        // we do not enter this block, as a null reference does not
2893        // need poisoning.
2894        __ Move(temp1, value);
2895        __ PoisonHeapReference(temp1);
2896        source = temp1;
2897      }
2898
2899      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2900      if (index.IsConstant()) {
2901        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2902      } else {
2903        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
2904      }
2905      __ StoreToOffset(kStoreWord, source, base_reg, data_offset);
2906
2907      if (!may_need_runtime_call_for_type_check) {
2908        codegen_->MaybeRecordImplicitNullCheck(instruction);
2909      }
2910
2911      codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull());
2912
2913      if (done.IsLinked()) {
2914        __ Bind(&done);
2915      }
2916
2917      if (slow_path != nullptr) {
2918        __ Bind(slow_path->GetExitLabel());
2919      }
2920      break;
2921    }
2922
2923    case Primitive::kPrimLong: {
2924      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
2925      if (index.IsConstant()) {
2926        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
2927      } else {
2928        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
2929      }
2930      if (value_location.IsConstant()) {
2931        int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2932        __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2933      } else {
2934        Register value = value_location.AsRegisterPairLow<Register>();
2935        __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
2936      }
2937      break;
2938    }
2939
2940    case Primitive::kPrimFloat: {
2941      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
2942      if (index.IsConstant()) {
2943        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2944      } else {
2945        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
2946      }
2947      if (value_location.IsConstant()) {
2948        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2949        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2950      } else {
2951        FRegister value = value_location.AsFpuRegister<FRegister>();
2952        __ StoreSToOffset(value, base_reg, data_offset, null_checker);
2953      }
2954      break;
2955    }
2956
2957    case Primitive::kPrimDouble: {
2958      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
2959      if (index.IsConstant()) {
2960        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
2961      } else {
2962        __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
2963      }
2964      if (value_location.IsConstant()) {
2965        int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2966        __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2967      } else {
2968        FRegister value = value_location.AsFpuRegister<FRegister>();
2969        __ StoreDToOffset(value, base_reg, data_offset, null_checker);
2970      }
2971      break;
2972    }
2973
2974    case Primitive::kPrimVoid:
2975      LOG(FATAL) << "Unreachable type " << instruction->GetType();
2976      UNREACHABLE();
2977  }
2978}
2979
2980void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
2981  RegisterSet caller_saves = RegisterSet::Empty();
2982  InvokeRuntimeCallingConvention calling_convention;
2983  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2984  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2985  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
2986  locations->SetInAt(0, Location::RequiresRegister());
2987  locations->SetInAt(1, Location::RequiresRegister());
2988}
2989
2990void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
2991  LocationSummary* locations = instruction->GetLocations();
2992  BoundsCheckSlowPathMIPS* slow_path =
2993      new (GetGraph()->GetArena()) BoundsCheckSlowPathMIPS(instruction);
2994  codegen_->AddSlowPath(slow_path);
2995
2996  Register index = locations->InAt(0).AsRegister<Register>();
2997  Register length = locations->InAt(1).AsRegister<Register>();
2998
2999  // length is limited by the maximum positive signed 32-bit integer.
3000  // Unsigned comparison of length and index checks for index < 0
3001  // and for length <= index simultaneously.
3002  __ Bgeu(index, length, slow_path->GetEntryLabel());
3003}
3004
3005// Temp is used for read barrier.
3006static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
3007  if (kEmitCompilerReadBarrier &&
3008      (kUseBakerReadBarrier ||
3009       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
3010       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
3011       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
3012    return 1;
3013  }
3014  return 0;
3015}
3016
3017// Extra temp is used for read barrier.
3018static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
3019  return 1 + NumberOfInstanceOfTemps(type_check_kind);
3020}
3021
3022void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
3023  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
3024  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
3025
3026  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
3027  switch (type_check_kind) {
3028    case TypeCheckKind::kExactCheck:
3029    case TypeCheckKind::kAbstractClassCheck:
3030    case TypeCheckKind::kClassHierarchyCheck:
3031    case TypeCheckKind::kArrayObjectCheck:
3032      call_kind = (throws_into_catch || kEmitCompilerReadBarrier)
3033          ? LocationSummary::kCallOnSlowPath
3034          : LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
3035      break;
3036    case TypeCheckKind::kArrayCheck:
3037    case TypeCheckKind::kUnresolvedCheck:
3038    case TypeCheckKind::kInterfaceCheck:
3039      call_kind = LocationSummary::kCallOnSlowPath;
3040      break;
3041  }
3042
3043  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3044  locations->SetInAt(0, Location::RequiresRegister());
3045  locations->SetInAt(1, Location::RequiresRegister());
3046  locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
3047}
3048
3049void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
3050  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
3051  LocationSummary* locations = instruction->GetLocations();
3052  Location obj_loc = locations->InAt(0);
3053  Register obj = obj_loc.AsRegister<Register>();
3054  Register cls = locations->InAt(1).AsRegister<Register>();
3055  Location temp_loc = locations->GetTemp(0);
3056  Register temp = temp_loc.AsRegister<Register>();
3057  const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
3058  DCHECK_LE(num_temps, 2u);
3059  Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
3060  const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3061  const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3062  const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3063  const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
3064  const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
3065  const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
3066  const uint32_t object_array_data_offset =
3067      mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
3068  MipsLabel done;
3069
3070  // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
3071  // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
3072  // read barriers is done for performance and code size reasons.
3073  bool is_type_check_slow_path_fatal = false;
3074  if (!kEmitCompilerReadBarrier) {
3075    is_type_check_slow_path_fatal =
3076        (type_check_kind == TypeCheckKind::kExactCheck ||
3077         type_check_kind == TypeCheckKind::kAbstractClassCheck ||
3078         type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
3079         type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
3080        !instruction->CanThrowIntoCatchBlock();
3081  }
3082  SlowPathCodeMIPS* slow_path =
3083      new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction,
3084                                                         is_type_check_slow_path_fatal);
3085  codegen_->AddSlowPath(slow_path);
3086
3087  // Avoid this check if we know `obj` is not null.
3088  if (instruction->MustDoNullCheck()) {
3089    __ Beqz(obj, &done);
3090  }
3091
3092  switch (type_check_kind) {
3093    case TypeCheckKind::kExactCheck:
3094    case TypeCheckKind::kArrayCheck: {
3095      // /* HeapReference<Class> */ temp = obj->klass_
3096      GenerateReferenceLoadTwoRegisters(instruction,
3097                                        temp_loc,
3098                                        obj_loc,
3099                                        class_offset,
3100                                        maybe_temp2_loc,
3101                                        kWithoutReadBarrier);
3102      // Jump to slow path for throwing the exception or doing a
3103      // more involved array check.
3104      __ Bne(temp, cls, slow_path->GetEntryLabel());
3105      break;
3106    }
3107
3108    case TypeCheckKind::kAbstractClassCheck: {
3109      // /* HeapReference<Class> */ temp = obj->klass_
3110      GenerateReferenceLoadTwoRegisters(instruction,
3111                                        temp_loc,
3112                                        obj_loc,
3113                                        class_offset,
3114                                        maybe_temp2_loc,
3115                                        kWithoutReadBarrier);
3116      // If the class is abstract, we eagerly fetch the super class of the
3117      // object to avoid doing a comparison we know will fail.
3118      MipsLabel loop;
3119      __ Bind(&loop);
3120      // /* HeapReference<Class> */ temp = temp->super_class_
3121      GenerateReferenceLoadOneRegister(instruction,
3122                                       temp_loc,
3123                                       super_offset,
3124                                       maybe_temp2_loc,
3125                                       kWithoutReadBarrier);
3126      // If the class reference currently in `temp` is null, jump to the slow path to throw the
3127      // exception.
3128      __ Beqz(temp, slow_path->GetEntryLabel());
3129      // Otherwise, compare the classes.
3130      __ Bne(temp, cls, &loop);
3131      break;
3132    }
3133
3134    case TypeCheckKind::kClassHierarchyCheck: {
3135      // /* HeapReference<Class> */ temp = obj->klass_
3136      GenerateReferenceLoadTwoRegisters(instruction,
3137                                        temp_loc,
3138                                        obj_loc,
3139                                        class_offset,
3140                                        maybe_temp2_loc,
3141                                        kWithoutReadBarrier);
3142      // Walk over the class hierarchy to find a match.
3143      MipsLabel loop;
3144      __ Bind(&loop);
3145      __ Beq(temp, cls, &done);
3146      // /* HeapReference<Class> */ temp = temp->super_class_
3147      GenerateReferenceLoadOneRegister(instruction,
3148                                       temp_loc,
3149                                       super_offset,
3150                                       maybe_temp2_loc,
3151                                       kWithoutReadBarrier);
3152      // If the class reference currently in `temp` is null, jump to the slow path to throw the
3153      // exception. Otherwise, jump to the beginning of the loop.
3154      __ Bnez(temp, &loop);
3155      __ B(slow_path->GetEntryLabel());
3156      break;
3157    }
3158
3159    case TypeCheckKind::kArrayObjectCheck: {
3160      // /* HeapReference<Class> */ temp = obj->klass_
3161      GenerateReferenceLoadTwoRegisters(instruction,
3162                                        temp_loc,
3163                                        obj_loc,
3164                                        class_offset,
3165                                        maybe_temp2_loc,
3166                                        kWithoutReadBarrier);
3167      // Do an exact check.
3168      __ Beq(temp, cls, &done);
3169      // Otherwise, we need to check that the object's class is a non-primitive array.
3170      // /* HeapReference<Class> */ temp = temp->component_type_
3171      GenerateReferenceLoadOneRegister(instruction,
3172                                       temp_loc,
3173                                       component_offset,
3174                                       maybe_temp2_loc,
3175                                       kWithoutReadBarrier);
3176      // If the component type is null, jump to the slow path to throw the exception.
3177      __ Beqz(temp, slow_path->GetEntryLabel());
3178      // Otherwise, the object is indeed an array, further check that this component
3179      // type is not a primitive type.
3180      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
3181      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
3182      __ Bnez(temp, slow_path->GetEntryLabel());
3183      break;
3184    }
3185
3186    case TypeCheckKind::kUnresolvedCheck:
3187      // We always go into the type check slow path for the unresolved check case.
3188      // We cannot directly call the CheckCast runtime entry point
3189      // without resorting to a type checking slow path here (i.e. by
3190      // calling InvokeRuntime directly), as it would require to
3191      // assign fixed registers for the inputs of this HInstanceOf
3192      // instruction (following the runtime calling convention), which
3193      // might be cluttered by the potential first read barrier
3194      // emission at the beginning of this method.
3195      __ B(slow_path->GetEntryLabel());
3196      break;
3197
3198    case TypeCheckKind::kInterfaceCheck: {
3199      // Avoid read barriers to improve performance of the fast path. We can not get false
3200      // positives by doing this.
3201      // /* HeapReference<Class> */ temp = obj->klass_
3202      GenerateReferenceLoadTwoRegisters(instruction,
3203                                        temp_loc,
3204                                        obj_loc,
3205                                        class_offset,
3206                                        maybe_temp2_loc,
3207                                        kWithoutReadBarrier);
3208      // /* HeapReference<Class> */ temp = temp->iftable_
3209      GenerateReferenceLoadTwoRegisters(instruction,
3210                                        temp_loc,
3211                                        temp_loc,
3212                                        iftable_offset,
3213                                        maybe_temp2_loc,
3214                                        kWithoutReadBarrier);
3215      // Iftable is never null.
3216      __ Lw(TMP, temp, array_length_offset);
3217      // Loop through the iftable and check if any class matches.
3218      MipsLabel loop;
3219      __ Bind(&loop);
3220      __ Addiu(temp, temp, 2 * kHeapReferenceSize);  // Possibly in delay slot on R2.
3221      __ Beqz(TMP, slow_path->GetEntryLabel());
3222      __ Lw(AT, temp, object_array_data_offset - 2 * kHeapReferenceSize);
3223      __ MaybeUnpoisonHeapReference(AT);
3224      // Go to next interface.
3225      __ Addiu(TMP, TMP, -2);
3226      // Compare the classes and continue the loop if they do not match.
3227      __ Bne(AT, cls, &loop);
3228      break;
3229    }
3230  }
3231
3232  __ Bind(&done);
3233  __ Bind(slow_path->GetExitLabel());
3234}
3235
3236void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
3237  LocationSummary* locations =
3238      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3239  locations->SetInAt(0, Location::RequiresRegister());
3240  if (check->HasUses()) {
3241    locations->SetOut(Location::SameAsFirstInput());
3242  }
3243}
3244
3245void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
3246  // We assume the class is not null.
3247  SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
3248      check->GetLoadClass(),
3249      check,
3250      check->GetDexPc(),
3251      true);
3252  codegen_->AddSlowPath(slow_path);
3253  GenerateClassInitializationCheck(slow_path,
3254                                   check->GetLocations()->InAt(0).AsRegister<Register>());
3255}
3256
3257void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
3258  Primitive::Type in_type = compare->InputAt(0)->GetType();
3259
3260  LocationSummary* locations =
3261      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
3262
3263  switch (in_type) {
3264    case Primitive::kPrimBoolean:
3265    case Primitive::kPrimByte:
3266    case Primitive::kPrimShort:
3267    case Primitive::kPrimChar:
3268    case Primitive::kPrimInt:
3269      locations->SetInAt(0, Location::RequiresRegister());
3270      locations->SetInAt(1, Location::RequiresRegister());
3271      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3272      break;
3273
3274    case Primitive::kPrimLong:
3275      locations->SetInAt(0, Location::RequiresRegister());
3276      locations->SetInAt(1, Location::RequiresRegister());
3277      // Output overlaps because it is written before doing the low comparison.
3278      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3279      break;
3280
3281    case Primitive::kPrimFloat:
3282    case Primitive::kPrimDouble:
3283      locations->SetInAt(0, Location::RequiresFpuRegister());
3284      locations->SetInAt(1, Location::RequiresFpuRegister());
3285      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3286      break;
3287
3288    default:
3289      LOG(FATAL) << "Unexpected type for compare operation " << in_type;
3290  }
3291}
3292
3293void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
3294  LocationSummary* locations = instruction->GetLocations();
3295  Register res = locations->Out().AsRegister<Register>();
3296  Primitive::Type in_type = instruction->InputAt(0)->GetType();
3297  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3298
3299  //  0 if: left == right
3300  //  1 if: left  > right
3301  // -1 if: left  < right
3302  switch (in_type) {
3303    case Primitive::kPrimBoolean:
3304    case Primitive::kPrimByte:
3305    case Primitive::kPrimShort:
3306    case Primitive::kPrimChar:
3307    case Primitive::kPrimInt: {
3308      Register lhs = locations->InAt(0).AsRegister<Register>();
3309      Register rhs = locations->InAt(1).AsRegister<Register>();
3310      __ Slt(TMP, lhs, rhs);
3311      __ Slt(res, rhs, lhs);
3312      __ Subu(res, res, TMP);
3313      break;
3314    }
3315    case Primitive::kPrimLong: {
3316      MipsLabel done;
3317      Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3318      Register lhs_low  = locations->InAt(0).AsRegisterPairLow<Register>();
3319      Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
3320      Register rhs_low  = locations->InAt(1).AsRegisterPairLow<Register>();
3321      // TODO: more efficient (direct) comparison with a constant.
3322      __ Slt(TMP, lhs_high, rhs_high);
3323      __ Slt(AT, rhs_high, lhs_high);  // Inverted: is actually gt.
3324      __ Subu(res, AT, TMP);           // Result -1:1:0 for [ <, >, == ].
3325      __ Bnez(res, &done);             // If we compared ==, check if lower bits are also equal.
3326      __ Sltu(TMP, lhs_low, rhs_low);
3327      __ Sltu(AT, rhs_low, lhs_low);   // Inverted: is actually gt.
3328      __ Subu(res, AT, TMP);           // Result -1:1:0 for [ <, >, == ].
3329      __ Bind(&done);
3330      break;
3331    }
3332
3333    case Primitive::kPrimFloat: {
3334      bool gt_bias = instruction->IsGtBias();
3335      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3336      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3337      MipsLabel done;
3338      if (isR6) {
3339        __ CmpEqS(FTMP, lhs, rhs);
3340        __ LoadConst32(res, 0);
3341        __ Bc1nez(FTMP, &done);
3342        if (gt_bias) {
3343          __ CmpLtS(FTMP, lhs, rhs);
3344          __ LoadConst32(res, -1);
3345          __ Bc1nez(FTMP, &done);
3346          __ LoadConst32(res, 1);
3347        } else {
3348          __ CmpLtS(FTMP, rhs, lhs);
3349          __ LoadConst32(res, 1);
3350          __ Bc1nez(FTMP, &done);
3351          __ LoadConst32(res, -1);
3352        }
3353      } else {
3354        if (gt_bias) {
3355          __ ColtS(0, lhs, rhs);
3356          __ LoadConst32(res, -1);
3357          __ Bc1t(0, &done);
3358          __ CeqS(0, lhs, rhs);
3359          __ LoadConst32(res, 1);
3360          __ Movt(res, ZERO, 0);
3361        } else {
3362          __ ColtS(0, rhs, lhs);
3363          __ LoadConst32(res, 1);
3364          __ Bc1t(0, &done);
3365          __ CeqS(0, lhs, rhs);
3366          __ LoadConst32(res, -1);
3367          __ Movt(res, ZERO, 0);
3368        }
3369      }
3370      __ Bind(&done);
3371      break;
3372    }
3373    case Primitive::kPrimDouble: {
3374      bool gt_bias = instruction->IsGtBias();
3375      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3376      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3377      MipsLabel done;
3378      if (isR6) {
3379        __ CmpEqD(FTMP, lhs, rhs);
3380        __ LoadConst32(res, 0);
3381        __ Bc1nez(FTMP, &done);
3382        if (gt_bias) {
3383          __ CmpLtD(FTMP, lhs, rhs);
3384          __ LoadConst32(res, -1);
3385          __ Bc1nez(FTMP, &done);
3386          __ LoadConst32(res, 1);
3387        } else {
3388          __ CmpLtD(FTMP, rhs, lhs);
3389          __ LoadConst32(res, 1);
3390          __ Bc1nez(FTMP, &done);
3391          __ LoadConst32(res, -1);
3392        }
3393      } else {
3394        if (gt_bias) {
3395          __ ColtD(0, lhs, rhs);
3396          __ LoadConst32(res, -1);
3397          __ Bc1t(0, &done);
3398          __ CeqD(0, lhs, rhs);
3399          __ LoadConst32(res, 1);
3400          __ Movt(res, ZERO, 0);
3401        } else {
3402          __ ColtD(0, rhs, lhs);
3403          __ LoadConst32(res, 1);
3404          __ Bc1t(0, &done);
3405          __ CeqD(0, lhs, rhs);
3406          __ LoadConst32(res, -1);
3407          __ Movt(res, ZERO, 0);
3408        }
3409      }
3410      __ Bind(&done);
3411      break;
3412    }
3413
3414    default:
3415      LOG(FATAL) << "Unimplemented compare type " << in_type;
3416  }
3417}
3418
3419void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
3420  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
3421  switch (instruction->InputAt(0)->GetType()) {
3422    default:
3423    case Primitive::kPrimLong:
3424      locations->SetInAt(0, Location::RequiresRegister());
3425      locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3426      break;
3427
3428    case Primitive::kPrimFloat:
3429    case Primitive::kPrimDouble:
3430      locations->SetInAt(0, Location::RequiresFpuRegister());
3431      locations->SetInAt(1, Location::RequiresFpuRegister());
3432      break;
3433  }
3434  if (!instruction->IsEmittedAtUseSite()) {
3435    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3436  }
3437}
3438
3439void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
3440  if (instruction->IsEmittedAtUseSite()) {
3441    return;
3442  }
3443
3444  Primitive::Type type = instruction->InputAt(0)->GetType();
3445  LocationSummary* locations = instruction->GetLocations();
3446  Register dst = locations->Out().AsRegister<Register>();
3447  MipsLabel true_label;
3448
3449  switch (type) {
3450    default:
3451      // Integer case.
3452      GenerateIntCompare(instruction->GetCondition(), locations);
3453      return;
3454
3455    case Primitive::kPrimLong:
3456      // TODO: don't use branches.
3457      GenerateLongCompareAndBranch(instruction->GetCondition(), locations, &true_label);
3458      break;
3459
3460    case Primitive::kPrimFloat:
3461    case Primitive::kPrimDouble:
3462      GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
3463      return;
3464  }
3465
3466  // Convert the branches into the result.
3467  MipsLabel done;
3468
3469  // False case: result = 0.
3470  __ LoadConst32(dst, 0);
3471  __ B(&done);
3472
3473  // True case: result = 1.
3474  __ Bind(&true_label);
3475  __ LoadConst32(dst, 1);
3476  __ Bind(&done);
3477}
3478
3479void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3480  DCHECK(instruction->IsDiv() || instruction->IsRem());
3481  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
3482
3483  LocationSummary* locations = instruction->GetLocations();
3484  Location second = locations->InAt(1);
3485  DCHECK(second.IsConstant());
3486
3487  Register out = locations->Out().AsRegister<Register>();
3488  Register dividend = locations->InAt(0).AsRegister<Register>();
3489  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3490  DCHECK(imm == 1 || imm == -1);
3491
3492  if (instruction->IsRem()) {
3493    __ Move(out, ZERO);
3494  } else {
3495    if (imm == -1) {
3496      __ Subu(out, ZERO, dividend);
3497    } else if (out != dividend) {
3498      __ Move(out, dividend);
3499    }
3500  }
3501}
3502
3503void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
3504  DCHECK(instruction->IsDiv() || instruction->IsRem());
3505  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
3506
3507  LocationSummary* locations = instruction->GetLocations();
3508  Location second = locations->InAt(1);
3509  DCHECK(second.IsConstant());
3510
3511  Register out = locations->Out().AsRegister<Register>();
3512  Register dividend = locations->InAt(0).AsRegister<Register>();
3513  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3514  uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
3515  int ctz_imm = CTZ(abs_imm);
3516
3517  if (instruction->IsDiv()) {
3518    if (ctz_imm == 1) {
3519      // Fast path for division by +/-2, which is very common.
3520      __ Srl(TMP, dividend, 31);
3521    } else {
3522      __ Sra(TMP, dividend, 31);
3523      __ Srl(TMP, TMP, 32 - ctz_imm);
3524    }
3525    __ Addu(out, dividend, TMP);
3526    __ Sra(out, out, ctz_imm);
3527    if (imm < 0) {
3528      __ Subu(out, ZERO, out);
3529    }
3530  } else {
3531    if (ctz_imm == 1) {
3532      // Fast path for modulo +/-2, which is very common.
3533      __ Sra(TMP, dividend, 31);
3534      __ Subu(out, dividend, TMP);
3535      __ Andi(out, out, 1);
3536      __ Addu(out, out, TMP);
3537    } else {
3538      __ Sra(TMP, dividend, 31);
3539      __ Srl(TMP, TMP, 32 - ctz_imm);
3540      __ Addu(out, dividend, TMP);
3541      if (IsUint<16>(abs_imm - 1)) {
3542        __ Andi(out, out, abs_imm - 1);
3543      } else {
3544        __ Sll(out, out, 32 - ctz_imm);
3545        __ Srl(out, out, 32 - ctz_imm);
3546      }
3547      __ Subu(out, out, TMP);
3548    }
3549  }
3550}
3551
3552void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3553  DCHECK(instruction->IsDiv() || instruction->IsRem());
3554  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
3555
3556  LocationSummary* locations = instruction->GetLocations();
3557  Location second = locations->InAt(1);
3558  DCHECK(second.IsConstant());
3559
3560  Register out = locations->Out().AsRegister<Register>();
3561  Register dividend = locations->InAt(0).AsRegister<Register>();
3562  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3563
3564  int64_t magic;
3565  int shift;
3566  CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3567
3568  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3569
3570  __ LoadConst32(TMP, magic);
3571  if (isR6) {
3572    __ MuhR6(TMP, dividend, TMP);
3573  } else {
3574    __ MultR2(dividend, TMP);
3575    __ Mfhi(TMP);
3576  }
3577  if (imm > 0 && magic < 0) {
3578    __ Addu(TMP, TMP, dividend);
3579  } else if (imm < 0 && magic > 0) {
3580    __ Subu(TMP, TMP, dividend);
3581  }
3582
3583  if (shift != 0) {
3584    __ Sra(TMP, TMP, shift);
3585  }
3586
3587  if (instruction->IsDiv()) {
3588    __ Sra(out, TMP, 31);
3589    __ Subu(out, TMP, out);
3590  } else {
3591    __ Sra(AT, TMP, 31);
3592    __ Subu(AT, TMP, AT);
3593    __ LoadConst32(TMP, imm);
3594    if (isR6) {
3595      __ MulR6(TMP, AT, TMP);
3596    } else {
3597      __ MulR2(TMP, AT, TMP);
3598    }
3599    __ Subu(out, dividend, TMP);
3600  }
3601}
3602
3603void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3604  DCHECK(instruction->IsDiv() || instruction->IsRem());
3605  DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
3606
3607  LocationSummary* locations = instruction->GetLocations();
3608  Register out = locations->Out().AsRegister<Register>();
3609  Location second = locations->InAt(1);
3610
3611  if (second.IsConstant()) {
3612    int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3613    if (imm == 0) {
3614      // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3615    } else if (imm == 1 || imm == -1) {
3616      DivRemOneOrMinusOne(instruction);
3617    } else if (IsPowerOfTwo(AbsOrMin(imm))) {
3618      DivRemByPowerOfTwo(instruction);
3619    } else {
3620      DCHECK(imm <= -2 || imm >= 2);
3621      GenerateDivRemWithAnyConstant(instruction);
3622    }
3623  } else {
3624    Register dividend = locations->InAt(0).AsRegister<Register>();
3625    Register divisor = second.AsRegister<Register>();
3626    bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3627    if (instruction->IsDiv()) {
3628      if (isR6) {
3629        __ DivR6(out, dividend, divisor);
3630      } else {
3631        __ DivR2(out, dividend, divisor);
3632      }
3633    } else {
3634      if (isR6) {
3635        __ ModR6(out, dividend, divisor);
3636      } else {
3637        __ ModR2(out, dividend, divisor);
3638      }
3639    }
3640  }
3641}
3642
3643void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
3644  Primitive::Type type = div->GetResultType();
3645  LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
3646      ? LocationSummary::kCallOnMainOnly
3647      : LocationSummary::kNoCall;
3648
3649  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3650
3651  switch (type) {
3652    case Primitive::kPrimInt:
3653      locations->SetInAt(0, Location::RequiresRegister());
3654      locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
3655      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3656      break;
3657
3658    case Primitive::kPrimLong: {
3659      InvokeRuntimeCallingConvention calling_convention;
3660      locations->SetInAt(0, Location::RegisterPairLocation(
3661          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3662      locations->SetInAt(1, Location::RegisterPairLocation(
3663          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3664      locations->SetOut(calling_convention.GetReturnLocation(type));
3665      break;
3666    }
3667
3668    case Primitive::kPrimFloat:
3669    case Primitive::kPrimDouble:
3670      locations->SetInAt(0, Location::RequiresFpuRegister());
3671      locations->SetInAt(1, Location::RequiresFpuRegister());
3672      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3673      break;
3674
3675    default:
3676      LOG(FATAL) << "Unexpected div type " << type;
3677  }
3678}
3679
3680void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
3681  Primitive::Type type = instruction->GetType();
3682  LocationSummary* locations = instruction->GetLocations();
3683
3684  switch (type) {
3685    case Primitive::kPrimInt:
3686      GenerateDivRemIntegral(instruction);
3687      break;
3688    case Primitive::kPrimLong: {
3689      codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
3690      CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
3691      break;
3692    }
3693    case Primitive::kPrimFloat:
3694    case Primitive::kPrimDouble: {
3695      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
3696      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3697      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3698      if (type == Primitive::kPrimFloat) {
3699        __ DivS(dst, lhs, rhs);
3700      } else {
3701        __ DivD(dst, lhs, rhs);
3702      }
3703      break;
3704    }
3705    default:
3706      LOG(FATAL) << "Unexpected div type " << type;
3707  }
3708}
3709
3710void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3711  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
3712  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3713}
3714
3715void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3716  SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS(instruction);
3717  codegen_->AddSlowPath(slow_path);
3718  Location value = instruction->GetLocations()->InAt(0);
3719  Primitive::Type type = instruction->GetType();
3720
3721  switch (type) {
3722    case Primitive::kPrimBoolean:
3723    case Primitive::kPrimByte:
3724    case Primitive::kPrimChar:
3725    case Primitive::kPrimShort:
3726    case Primitive::kPrimInt: {
3727      if (value.IsConstant()) {
3728        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3729          __ B(slow_path->GetEntryLabel());
3730        } else {
3731          // A division by a non-null constant is valid. We don't need to perform
3732          // any check, so simply fall through.
3733        }
3734      } else {
3735        DCHECK(value.IsRegister()) << value;
3736        __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
3737      }
3738      break;
3739    }
3740    case Primitive::kPrimLong: {
3741      if (value.IsConstant()) {
3742        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3743          __ B(slow_path->GetEntryLabel());
3744        } else {
3745          // A division by a non-null constant is valid. We don't need to perform
3746          // any check, so simply fall through.
3747        }
3748      } else {
3749        DCHECK(value.IsRegisterPair()) << value;
3750        __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
3751        __ Beqz(TMP, slow_path->GetEntryLabel());
3752      }
3753      break;
3754    }
3755    default:
3756      LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
3757  }
3758}
3759
3760void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
3761  LocationSummary* locations =
3762      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3763  locations->SetOut(Location::ConstantLocation(constant));
3764}
3765
3766void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
3767  // Will be generated at use site.
3768}
3769
3770void LocationsBuilderMIPS::VisitExit(HExit* exit) {
3771  exit->SetLocations(nullptr);
3772}
3773
3774void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
3775}
3776
3777void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
3778  LocationSummary* locations =
3779      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3780  locations->SetOut(Location::ConstantLocation(constant));
3781}
3782
3783void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
3784  // Will be generated at use site.
3785}
3786
3787void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
3788  got->SetLocations(nullptr);
3789}
3790
3791void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
3792  DCHECK(!successor->IsExitBlock());
3793  HBasicBlock* block = got->GetBlock();
3794  HInstruction* previous = got->GetPrevious();
3795  HLoopInformation* info = block->GetLoopInformation();
3796
3797  if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
3798    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
3799    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
3800    return;
3801  }
3802  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
3803    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
3804  }
3805  if (!codegen_->GoesToNextBlock(block, successor)) {
3806    __ B(codegen_->GetLabelOf(successor));
3807  }
3808}
3809
3810void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
3811  HandleGoto(got, got->GetSuccessor());
3812}
3813
3814void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
3815  try_boundary->SetLocations(nullptr);
3816}
3817
3818void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
3819  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
3820  if (!successor->IsExitBlock()) {
3821    HandleGoto(try_boundary, successor);
3822  }
3823}
3824
3825void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
3826                                                      LocationSummary* locations) {
3827  Register dst = locations->Out().AsRegister<Register>();
3828  Register lhs = locations->InAt(0).AsRegister<Register>();
3829  Location rhs_location = locations->InAt(1);
3830  Register rhs_reg = ZERO;
3831  int64_t rhs_imm = 0;
3832  bool use_imm = rhs_location.IsConstant();
3833  if (use_imm) {
3834    rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3835  } else {
3836    rhs_reg = rhs_location.AsRegister<Register>();
3837  }
3838
3839  switch (cond) {
3840    case kCondEQ:
3841    case kCondNE:
3842      if (use_imm && IsInt<16>(-rhs_imm)) {
3843        if (rhs_imm == 0) {
3844          if (cond == kCondEQ) {
3845            __ Sltiu(dst, lhs, 1);
3846          } else {
3847            __ Sltu(dst, ZERO, lhs);
3848          }
3849        } else {
3850          __ Addiu(dst, lhs, -rhs_imm);
3851          if (cond == kCondEQ) {
3852            __ Sltiu(dst, dst, 1);
3853          } else {
3854            __ Sltu(dst, ZERO, dst);
3855          }
3856        }
3857      } else {
3858        if (use_imm && IsUint<16>(rhs_imm)) {
3859          __ Xori(dst, lhs, rhs_imm);
3860        } else {
3861          if (use_imm) {
3862            rhs_reg = TMP;
3863            __ LoadConst32(rhs_reg, rhs_imm);
3864          }
3865          __ Xor(dst, lhs, rhs_reg);
3866        }
3867        if (cond == kCondEQ) {
3868          __ Sltiu(dst, dst, 1);
3869        } else {
3870          __ Sltu(dst, ZERO, dst);
3871        }
3872      }
3873      break;
3874
3875    case kCondLT:
3876    case kCondGE:
3877      if (use_imm && IsInt<16>(rhs_imm)) {
3878        __ Slti(dst, lhs, rhs_imm);
3879      } else {
3880        if (use_imm) {
3881          rhs_reg = TMP;
3882          __ LoadConst32(rhs_reg, rhs_imm);
3883        }
3884        __ Slt(dst, lhs, rhs_reg);
3885      }
3886      if (cond == kCondGE) {
3887        // Simulate lhs >= rhs via !(lhs < rhs) since there's
3888        // only the slt instruction but no sge.
3889        __ Xori(dst, dst, 1);
3890      }
3891      break;
3892
3893    case kCondLE:
3894    case kCondGT:
3895      if (use_imm && IsInt<16>(rhs_imm + 1)) {
3896        // Simulate lhs <= rhs via lhs < rhs + 1.
3897        __ Slti(dst, lhs, rhs_imm + 1);
3898        if (cond == kCondGT) {
3899          // Simulate lhs > rhs via !(lhs <= rhs) since there's
3900          // only the slti instruction but no sgti.
3901          __ Xori(dst, dst, 1);
3902        }
3903      } else {
3904        if (use_imm) {
3905          rhs_reg = TMP;
3906          __ LoadConst32(rhs_reg, rhs_imm);
3907        }
3908        __ Slt(dst, rhs_reg, lhs);
3909        if (cond == kCondLE) {
3910          // Simulate lhs <= rhs via !(rhs < lhs) since there's
3911          // only the slt instruction but no sle.
3912          __ Xori(dst, dst, 1);
3913        }
3914      }
3915      break;
3916
3917    case kCondB:
3918    case kCondAE:
3919      if (use_imm && IsInt<16>(rhs_imm)) {
3920        // Sltiu sign-extends its 16-bit immediate operand before
3921        // the comparison and thus lets us compare directly with
3922        // unsigned values in the ranges [0, 0x7fff] and
3923        // [0xffff8000, 0xffffffff].
3924        __ Sltiu(dst, lhs, rhs_imm);
3925      } else {
3926        if (use_imm) {
3927          rhs_reg = TMP;
3928          __ LoadConst32(rhs_reg, rhs_imm);
3929        }
3930        __ Sltu(dst, lhs, rhs_reg);
3931      }
3932      if (cond == kCondAE) {
3933        // Simulate lhs >= rhs via !(lhs < rhs) since there's
3934        // only the sltu instruction but no sgeu.
3935        __ Xori(dst, dst, 1);
3936      }
3937      break;
3938
3939    case kCondBE:
3940    case kCondA:
3941      if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
3942        // Simulate lhs <= rhs via lhs < rhs + 1.
3943        // Note that this only works if rhs + 1 does not overflow
3944        // to 0, hence the check above.
3945        // Sltiu sign-extends its 16-bit immediate operand before
3946        // the comparison and thus lets us compare directly with
3947        // unsigned values in the ranges [0, 0x7fff] and
3948        // [0xffff8000, 0xffffffff].
3949        __ Sltiu(dst, lhs, rhs_imm + 1);
3950        if (cond == kCondA) {
3951          // Simulate lhs > rhs via !(lhs <= rhs) since there's
3952          // only the sltiu instruction but no sgtiu.
3953          __ Xori(dst, dst, 1);
3954        }
3955      } else {
3956        if (use_imm) {
3957          rhs_reg = TMP;
3958          __ LoadConst32(rhs_reg, rhs_imm);
3959        }
3960        __ Sltu(dst, rhs_reg, lhs);
3961        if (cond == kCondBE) {
3962          // Simulate lhs <= rhs via !(rhs < lhs) since there's
3963          // only the sltu instruction but no sleu.
3964          __ Xori(dst, dst, 1);
3965        }
3966      }
3967      break;
3968  }
3969}
3970
3971bool InstructionCodeGeneratorMIPS::MaterializeIntCompare(IfCondition cond,
3972                                                         LocationSummary* input_locations,
3973                                                         Register dst) {
3974  Register lhs = input_locations->InAt(0).AsRegister<Register>();
3975  Location rhs_location = input_locations->InAt(1);
3976  Register rhs_reg = ZERO;
3977  int64_t rhs_imm = 0;
3978  bool use_imm = rhs_location.IsConstant();
3979  if (use_imm) {
3980    rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3981  } else {
3982    rhs_reg = rhs_location.AsRegister<Register>();
3983  }
3984
3985  switch (cond) {
3986    case kCondEQ:
3987    case kCondNE:
3988      if (use_imm && IsInt<16>(-rhs_imm)) {
3989        __ Addiu(dst, lhs, -rhs_imm);
3990      } else if (use_imm && IsUint<16>(rhs_imm)) {
3991        __ Xori(dst, lhs, rhs_imm);
3992      } else {
3993        if (use_imm) {
3994          rhs_reg = TMP;
3995          __ LoadConst32(rhs_reg, rhs_imm);
3996        }
3997        __ Xor(dst, lhs, rhs_reg);
3998      }
3999      return (cond == kCondEQ);
4000
4001    case kCondLT:
4002    case kCondGE:
4003      if (use_imm && IsInt<16>(rhs_imm)) {
4004        __ Slti(dst, lhs, rhs_imm);
4005      } else {
4006        if (use_imm) {
4007          rhs_reg = TMP;
4008          __ LoadConst32(rhs_reg, rhs_imm);
4009        }
4010        __ Slt(dst, lhs, rhs_reg);
4011      }
4012      return (cond == kCondGE);
4013
4014    case kCondLE:
4015    case kCondGT:
4016      if (use_imm && IsInt<16>(rhs_imm + 1)) {
4017        // Simulate lhs <= rhs via lhs < rhs + 1.
4018        __ Slti(dst, lhs, rhs_imm + 1);
4019        return (cond == kCondGT);
4020      } else {
4021        if (use_imm) {
4022          rhs_reg = TMP;
4023          __ LoadConst32(rhs_reg, rhs_imm);
4024        }
4025        __ Slt(dst, rhs_reg, lhs);
4026        return (cond == kCondLE);
4027      }
4028
4029    case kCondB:
4030    case kCondAE:
4031      if (use_imm && IsInt<16>(rhs_imm)) {
4032        // Sltiu sign-extends its 16-bit immediate operand before
4033        // the comparison and thus lets us compare directly with
4034        // unsigned values in the ranges [0, 0x7fff] and
4035        // [0xffff8000, 0xffffffff].
4036        __ Sltiu(dst, lhs, rhs_imm);
4037      } else {
4038        if (use_imm) {
4039          rhs_reg = TMP;
4040          __ LoadConst32(rhs_reg, rhs_imm);
4041        }
4042        __ Sltu(dst, lhs, rhs_reg);
4043      }
4044      return (cond == kCondAE);
4045
4046    case kCondBE:
4047    case kCondA:
4048      if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4049        // Simulate lhs <= rhs via lhs < rhs + 1.
4050        // Note that this only works if rhs + 1 does not overflow
4051        // to 0, hence the check above.
4052        // Sltiu sign-extends its 16-bit immediate operand before
4053        // the comparison and thus lets us compare directly with
4054        // unsigned values in the ranges [0, 0x7fff] and
4055        // [0xffff8000, 0xffffffff].
4056        __ Sltiu(dst, lhs, rhs_imm + 1);
4057        return (cond == kCondA);
4058      } else {
4059        if (use_imm) {
4060          rhs_reg = TMP;
4061          __ LoadConst32(rhs_reg, rhs_imm);
4062        }
4063        __ Sltu(dst, rhs_reg, lhs);
4064        return (cond == kCondBE);
4065      }
4066  }
4067}
4068
4069void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
4070                                                               LocationSummary* locations,
4071                                                               MipsLabel* label) {
4072  Register lhs = locations->InAt(0).AsRegister<Register>();
4073  Location rhs_location = locations->InAt(1);
4074  Register rhs_reg = ZERO;
4075  int64_t rhs_imm = 0;
4076  bool use_imm = rhs_location.IsConstant();
4077  if (use_imm) {
4078    rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4079  } else {
4080    rhs_reg = rhs_location.AsRegister<Register>();
4081  }
4082
4083  if (use_imm && rhs_imm == 0) {
4084    switch (cond) {
4085      case kCondEQ:
4086      case kCondBE:  // <= 0 if zero
4087        __ Beqz(lhs, label);
4088        break;
4089      case kCondNE:
4090      case kCondA:  // > 0 if non-zero
4091        __ Bnez(lhs, label);
4092        break;
4093      case kCondLT:
4094        __ Bltz(lhs, label);
4095        break;
4096      case kCondGE:
4097        __ Bgez(lhs, label);
4098        break;
4099      case kCondLE:
4100        __ Blez(lhs, label);
4101        break;
4102      case kCondGT:
4103        __ Bgtz(lhs, label);
4104        break;
4105      case kCondB:  // always false
4106        break;
4107      case kCondAE:  // always true
4108        __ B(label);
4109        break;
4110    }
4111  } else {
4112    bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4113    if (isR6 || !use_imm) {
4114      if (use_imm) {
4115        rhs_reg = TMP;
4116        __ LoadConst32(rhs_reg, rhs_imm);
4117      }
4118      switch (cond) {
4119        case kCondEQ:
4120          __ Beq(lhs, rhs_reg, label);
4121          break;
4122        case kCondNE:
4123          __ Bne(lhs, rhs_reg, label);
4124          break;
4125        case kCondLT:
4126          __ Blt(lhs, rhs_reg, label);
4127          break;
4128        case kCondGE:
4129          __ Bge(lhs, rhs_reg, label);
4130          break;
4131        case kCondLE:
4132          __ Bge(rhs_reg, lhs, label);
4133          break;
4134        case kCondGT:
4135          __ Blt(rhs_reg, lhs, label);
4136          break;
4137        case kCondB:
4138          __ Bltu(lhs, rhs_reg, label);
4139          break;
4140        case kCondAE:
4141          __ Bgeu(lhs, rhs_reg, label);
4142          break;
4143        case kCondBE:
4144          __ Bgeu(rhs_reg, lhs, label);
4145          break;
4146        case kCondA:
4147          __ Bltu(rhs_reg, lhs, label);
4148          break;
4149      }
4150    } else {
4151      // Special cases for more efficient comparison with constants on R2.
4152      switch (cond) {
4153        case kCondEQ:
4154          __ LoadConst32(TMP, rhs_imm);
4155          __ Beq(lhs, TMP, label);
4156          break;
4157        case kCondNE:
4158          __ LoadConst32(TMP, rhs_imm);
4159          __ Bne(lhs, TMP, label);
4160          break;
4161        case kCondLT:
4162          if (IsInt<16>(rhs_imm)) {
4163            __ Slti(TMP, lhs, rhs_imm);
4164            __ Bnez(TMP, label);
4165          } else {
4166            __ LoadConst32(TMP, rhs_imm);
4167            __ Blt(lhs, TMP, label);
4168          }
4169          break;
4170        case kCondGE:
4171          if (IsInt<16>(rhs_imm)) {
4172            __ Slti(TMP, lhs, rhs_imm);
4173            __ Beqz(TMP, label);
4174          } else {
4175            __ LoadConst32(TMP, rhs_imm);
4176            __ Bge(lhs, TMP, label);
4177          }
4178          break;
4179        case kCondLE:
4180          if (IsInt<16>(rhs_imm + 1)) {
4181            // Simulate lhs <= rhs via lhs < rhs + 1.
4182            __ Slti(TMP, lhs, rhs_imm + 1);
4183            __ Bnez(TMP, label);
4184          } else {
4185            __ LoadConst32(TMP, rhs_imm);
4186            __ Bge(TMP, lhs, label);
4187          }
4188          break;
4189        case kCondGT:
4190          if (IsInt<16>(rhs_imm + 1)) {
4191            // Simulate lhs > rhs via !(lhs < rhs + 1).
4192            __ Slti(TMP, lhs, rhs_imm + 1);
4193            __ Beqz(TMP, label);
4194          } else {
4195            __ LoadConst32(TMP, rhs_imm);
4196            __ Blt(TMP, lhs, label);
4197          }
4198          break;
4199        case kCondB:
4200          if (IsInt<16>(rhs_imm)) {
4201            __ Sltiu(TMP, lhs, rhs_imm);
4202            __ Bnez(TMP, label);
4203          } else {
4204            __ LoadConst32(TMP, rhs_imm);
4205            __ Bltu(lhs, TMP, label);
4206          }
4207          break;
4208        case kCondAE:
4209          if (IsInt<16>(rhs_imm)) {
4210            __ Sltiu(TMP, lhs, rhs_imm);
4211            __ Beqz(TMP, label);
4212          } else {
4213            __ LoadConst32(TMP, rhs_imm);
4214            __ Bgeu(lhs, TMP, label);
4215          }
4216          break;
4217        case kCondBE:
4218          if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4219            // Simulate lhs <= rhs via lhs < rhs + 1.
4220            // Note that this only works if rhs + 1 does not overflow
4221            // to 0, hence the check above.
4222            __ Sltiu(TMP, lhs, rhs_imm + 1);
4223            __ Bnez(TMP, label);
4224          } else {
4225            __ LoadConst32(TMP, rhs_imm);
4226            __ Bgeu(TMP, lhs, label);
4227          }
4228          break;
4229        case kCondA:
4230          if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4231            // Simulate lhs > rhs via !(lhs < rhs + 1).
4232            // Note that this only works if rhs + 1 does not overflow
4233            // to 0, hence the check above.
4234            __ Sltiu(TMP, lhs, rhs_imm + 1);
4235            __ Beqz(TMP, label);
4236          } else {
4237            __ LoadConst32(TMP, rhs_imm);
4238            __ Bltu(TMP, lhs, label);
4239          }
4240          break;
4241      }
4242    }
4243  }
4244}
4245
4246void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
4247                                                                LocationSummary* locations,
4248                                                                MipsLabel* label) {
4249  Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4250  Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4251  Location rhs_location = locations->InAt(1);
4252  Register rhs_high = ZERO;
4253  Register rhs_low = ZERO;
4254  int64_t imm = 0;
4255  uint32_t imm_high = 0;
4256  uint32_t imm_low = 0;
4257  bool use_imm = rhs_location.IsConstant();
4258  if (use_imm) {
4259    imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
4260    imm_high = High32Bits(imm);
4261    imm_low = Low32Bits(imm);
4262  } else {
4263    rhs_high = rhs_location.AsRegisterPairHigh<Register>();
4264    rhs_low = rhs_location.AsRegisterPairLow<Register>();
4265  }
4266
4267  if (use_imm && imm == 0) {
4268    switch (cond) {
4269      case kCondEQ:
4270      case kCondBE:  // <= 0 if zero
4271        __ Or(TMP, lhs_high, lhs_low);
4272        __ Beqz(TMP, label);
4273        break;
4274      case kCondNE:
4275      case kCondA:  // > 0 if non-zero
4276        __ Or(TMP, lhs_high, lhs_low);
4277        __ Bnez(TMP, label);
4278        break;
4279      case kCondLT:
4280        __ Bltz(lhs_high, label);
4281        break;
4282      case kCondGE:
4283        __ Bgez(lhs_high, label);
4284        break;
4285      case kCondLE:
4286        __ Or(TMP, lhs_high, lhs_low);
4287        __ Sra(AT, lhs_high, 31);
4288        __ Bgeu(AT, TMP, label);
4289        break;
4290      case kCondGT:
4291        __ Or(TMP, lhs_high, lhs_low);
4292        __ Sra(AT, lhs_high, 31);
4293        __ Bltu(AT, TMP, label);
4294        break;
4295      case kCondB:  // always false
4296        break;
4297      case kCondAE:  // always true
4298        __ B(label);
4299        break;
4300    }
4301  } else if (use_imm) {
4302    // TODO: more efficient comparison with constants without loading them into TMP/AT.
4303    switch (cond) {
4304      case kCondEQ:
4305        __ LoadConst32(TMP, imm_high);
4306        __ Xor(TMP, TMP, lhs_high);
4307        __ LoadConst32(AT, imm_low);
4308        __ Xor(AT, AT, lhs_low);
4309        __ Or(TMP, TMP, AT);
4310        __ Beqz(TMP, label);
4311        break;
4312      case kCondNE:
4313        __ LoadConst32(TMP, imm_high);
4314        __ Xor(TMP, TMP, lhs_high);
4315        __ LoadConst32(AT, imm_low);
4316        __ Xor(AT, AT, lhs_low);
4317        __ Or(TMP, TMP, AT);
4318        __ Bnez(TMP, label);
4319        break;
4320      case kCondLT:
4321        __ LoadConst32(TMP, imm_high);
4322        __ Blt(lhs_high, TMP, label);
4323        __ Slt(TMP, TMP, lhs_high);
4324        __ LoadConst32(AT, imm_low);
4325        __ Sltu(AT, lhs_low, AT);
4326        __ Blt(TMP, AT, label);
4327        break;
4328      case kCondGE:
4329        __ LoadConst32(TMP, imm_high);
4330        __ Blt(TMP, lhs_high, label);
4331        __ Slt(TMP, lhs_high, TMP);
4332        __ LoadConst32(AT, imm_low);
4333        __ Sltu(AT, lhs_low, AT);
4334        __ Or(TMP, TMP, AT);
4335        __ Beqz(TMP, label);
4336        break;
4337      case kCondLE:
4338        __ LoadConst32(TMP, imm_high);
4339        __ Blt(lhs_high, TMP, label);
4340        __ Slt(TMP, TMP, lhs_high);
4341        __ LoadConst32(AT, imm_low);
4342        __ Sltu(AT, AT, lhs_low);
4343        __ Or(TMP, TMP, AT);
4344        __ Beqz(TMP, label);
4345        break;
4346      case kCondGT:
4347        __ LoadConst32(TMP, imm_high);
4348        __ Blt(TMP, lhs_high, label);
4349        __ Slt(TMP, lhs_high, TMP);
4350        __ LoadConst32(AT, imm_low);
4351        __ Sltu(AT, AT, lhs_low);
4352        __ Blt(TMP, AT, label);
4353        break;
4354      case kCondB:
4355        __ LoadConst32(TMP, imm_high);
4356        __ Bltu(lhs_high, TMP, label);
4357        __ Sltu(TMP, TMP, lhs_high);
4358        __ LoadConst32(AT, imm_low);
4359        __ Sltu(AT, lhs_low, AT);
4360        __ Blt(TMP, AT, label);
4361        break;
4362      case kCondAE:
4363        __ LoadConst32(TMP, imm_high);
4364        __ Bltu(TMP, lhs_high, label);
4365        __ Sltu(TMP, lhs_high, TMP);
4366        __ LoadConst32(AT, imm_low);
4367        __ Sltu(AT, lhs_low, AT);
4368        __ Or(TMP, TMP, AT);
4369        __ Beqz(TMP, label);
4370        break;
4371      case kCondBE:
4372        __ LoadConst32(TMP, imm_high);
4373        __ Bltu(lhs_high, TMP, label);
4374        __ Sltu(TMP, TMP, lhs_high);
4375        __ LoadConst32(AT, imm_low);
4376        __ Sltu(AT, AT, lhs_low);
4377        __ Or(TMP, TMP, AT);
4378        __ Beqz(TMP, label);
4379        break;
4380      case kCondA:
4381        __ LoadConst32(TMP, imm_high);
4382        __ Bltu(TMP, lhs_high, label);
4383        __ Sltu(TMP, lhs_high, TMP);
4384        __ LoadConst32(AT, imm_low);
4385        __ Sltu(AT, AT, lhs_low);
4386        __ Blt(TMP, AT, label);
4387        break;
4388    }
4389  } else {
4390    switch (cond) {
4391      case kCondEQ:
4392        __ Xor(TMP, lhs_high, rhs_high);
4393        __ Xor(AT, lhs_low, rhs_low);
4394        __ Or(TMP, TMP, AT);
4395        __ Beqz(TMP, label);
4396        break;
4397      case kCondNE:
4398        __ Xor(TMP, lhs_high, rhs_high);
4399        __ Xor(AT, lhs_low, rhs_low);
4400        __ Or(TMP, TMP, AT);
4401        __ Bnez(TMP, label);
4402        break;
4403      case kCondLT:
4404        __ Blt(lhs_high, rhs_high, label);
4405        __ Slt(TMP, rhs_high, lhs_high);
4406        __ Sltu(AT, lhs_low, rhs_low);
4407        __ Blt(TMP, AT, label);
4408        break;
4409      case kCondGE:
4410        __ Blt(rhs_high, lhs_high, label);
4411        __ Slt(TMP, lhs_high, rhs_high);
4412        __ Sltu(AT, lhs_low, rhs_low);
4413        __ Or(TMP, TMP, AT);
4414        __ Beqz(TMP, label);
4415        break;
4416      case kCondLE:
4417        __ Blt(lhs_high, rhs_high, label);
4418        __ Slt(TMP, rhs_high, lhs_high);
4419        __ Sltu(AT, rhs_low, lhs_low);
4420        __ Or(TMP, TMP, AT);
4421        __ Beqz(TMP, label);
4422        break;
4423      case kCondGT:
4424        __ Blt(rhs_high, lhs_high, label);
4425        __ Slt(TMP, lhs_high, rhs_high);
4426        __ Sltu(AT, rhs_low, lhs_low);
4427        __ Blt(TMP, AT, label);
4428        break;
4429      case kCondB:
4430        __ Bltu(lhs_high, rhs_high, label);
4431        __ Sltu(TMP, rhs_high, lhs_high);
4432        __ Sltu(AT, lhs_low, rhs_low);
4433        __ Blt(TMP, AT, label);
4434        break;
4435      case kCondAE:
4436        __ Bltu(rhs_high, lhs_high, label);
4437        __ Sltu(TMP, lhs_high, rhs_high);
4438        __ Sltu(AT, lhs_low, rhs_low);
4439        __ Or(TMP, TMP, AT);
4440        __ Beqz(TMP, label);
4441        break;
4442      case kCondBE:
4443        __ Bltu(lhs_high, rhs_high, label);
4444        __ Sltu(TMP, rhs_high, lhs_high);
4445        __ Sltu(AT, rhs_low, lhs_low);
4446        __ Or(TMP, TMP, AT);
4447        __ Beqz(TMP, label);
4448        break;
4449      case kCondA:
4450        __ Bltu(rhs_high, lhs_high, label);
4451        __ Sltu(TMP, lhs_high, rhs_high);
4452        __ Sltu(AT, rhs_low, lhs_low);
4453        __ Blt(TMP, AT, label);
4454        break;
4455    }
4456  }
4457}
4458
4459void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
4460                                                     bool gt_bias,
4461                                                     Primitive::Type type,
4462                                                     LocationSummary* locations) {
4463  Register dst = locations->Out().AsRegister<Register>();
4464  FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4465  FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
4466  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4467  if (type == Primitive::kPrimFloat) {
4468    if (isR6) {
4469      switch (cond) {
4470        case kCondEQ:
4471          __ CmpEqS(FTMP, lhs, rhs);
4472          __ Mfc1(dst, FTMP);
4473          __ Andi(dst, dst, 1);
4474          break;
4475        case kCondNE:
4476          __ CmpEqS(FTMP, lhs, rhs);
4477          __ Mfc1(dst, FTMP);
4478          __ Addiu(dst, dst, 1);
4479          break;
4480        case kCondLT:
4481          if (gt_bias) {
4482            __ CmpLtS(FTMP, lhs, rhs);
4483          } else {
4484            __ CmpUltS(FTMP, lhs, rhs);
4485          }
4486          __ Mfc1(dst, FTMP);
4487          __ Andi(dst, dst, 1);
4488          break;
4489        case kCondLE:
4490          if (gt_bias) {
4491            __ CmpLeS(FTMP, lhs, rhs);
4492          } else {
4493            __ CmpUleS(FTMP, lhs, rhs);
4494          }
4495          __ Mfc1(dst, FTMP);
4496          __ Andi(dst, dst, 1);
4497          break;
4498        case kCondGT:
4499          if (gt_bias) {
4500            __ CmpUltS(FTMP, rhs, lhs);
4501          } else {
4502            __ CmpLtS(FTMP, rhs, lhs);
4503          }
4504          __ Mfc1(dst, FTMP);
4505          __ Andi(dst, dst, 1);
4506          break;
4507        case kCondGE:
4508          if (gt_bias) {
4509            __ CmpUleS(FTMP, rhs, lhs);
4510          } else {
4511            __ CmpLeS(FTMP, rhs, lhs);
4512          }
4513          __ Mfc1(dst, FTMP);
4514          __ Andi(dst, dst, 1);
4515          break;
4516        default:
4517          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
4518          UNREACHABLE();
4519      }
4520    } else {
4521      switch (cond) {
4522        case kCondEQ:
4523          __ CeqS(0, lhs, rhs);
4524          __ LoadConst32(dst, 1);
4525          __ Movf(dst, ZERO, 0);
4526          break;
4527        case kCondNE:
4528          __ CeqS(0, lhs, rhs);
4529          __ LoadConst32(dst, 1);
4530          __ Movt(dst, ZERO, 0);
4531          break;
4532        case kCondLT:
4533          if (gt_bias) {
4534            __ ColtS(0, lhs, rhs);
4535          } else {
4536            __ CultS(0, lhs, rhs);
4537          }
4538          __ LoadConst32(dst, 1);
4539          __ Movf(dst, ZERO, 0);
4540          break;
4541        case kCondLE:
4542          if (gt_bias) {
4543            __ ColeS(0, lhs, rhs);
4544          } else {
4545            __ CuleS(0, lhs, rhs);
4546          }
4547          __ LoadConst32(dst, 1);
4548          __ Movf(dst, ZERO, 0);
4549          break;
4550        case kCondGT:
4551          if (gt_bias) {
4552            __ CultS(0, rhs, lhs);
4553          } else {
4554            __ ColtS(0, rhs, lhs);
4555          }
4556          __ LoadConst32(dst, 1);
4557          __ Movf(dst, ZERO, 0);
4558          break;
4559        case kCondGE:
4560          if (gt_bias) {
4561            __ CuleS(0, rhs, lhs);
4562          } else {
4563            __ ColeS(0, rhs, lhs);
4564          }
4565          __ LoadConst32(dst, 1);
4566          __ Movf(dst, ZERO, 0);
4567          break;
4568        default:
4569          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
4570          UNREACHABLE();
4571      }
4572    }
4573  } else {
4574    DCHECK_EQ(type, Primitive::kPrimDouble);
4575    if (isR6) {
4576      switch (cond) {
4577        case kCondEQ:
4578          __ CmpEqD(FTMP, lhs, rhs);
4579          __ Mfc1(dst, FTMP);
4580          __ Andi(dst, dst, 1);
4581          break;
4582        case kCondNE:
4583          __ CmpEqD(FTMP, lhs, rhs);
4584          __ Mfc1(dst, FTMP);
4585          __ Addiu(dst, dst, 1);
4586          break;
4587        case kCondLT:
4588          if (gt_bias) {
4589            __ CmpLtD(FTMP, lhs, rhs);
4590          } else {
4591            __ CmpUltD(FTMP, lhs, rhs);
4592          }
4593          __ Mfc1(dst, FTMP);
4594          __ Andi(dst, dst, 1);
4595          break;
4596        case kCondLE:
4597          if (gt_bias) {
4598            __ CmpLeD(FTMP, lhs, rhs);
4599          } else {
4600            __ CmpUleD(FTMP, lhs, rhs);
4601          }
4602          __ Mfc1(dst, FTMP);
4603          __ Andi(dst, dst, 1);
4604          break;
4605        case kCondGT:
4606          if (gt_bias) {
4607            __ CmpUltD(FTMP, rhs, lhs);
4608          } else {
4609            __ CmpLtD(FTMP, rhs, lhs);
4610          }
4611          __ Mfc1(dst, FTMP);
4612          __ Andi(dst, dst, 1);
4613          break;
4614        case kCondGE:
4615          if (gt_bias) {
4616            __ CmpUleD(FTMP, rhs, lhs);
4617          } else {
4618            __ CmpLeD(FTMP, rhs, lhs);
4619          }
4620          __ Mfc1(dst, FTMP);
4621          __ Andi(dst, dst, 1);
4622          break;
4623        default:
4624          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
4625          UNREACHABLE();
4626      }
4627    } else {
4628      switch (cond) {
4629        case kCondEQ:
4630          __ CeqD(0, lhs, rhs);
4631          __ LoadConst32(dst, 1);
4632          __ Movf(dst, ZERO, 0);
4633          break;
4634        case kCondNE:
4635          __ CeqD(0, lhs, rhs);
4636          __ LoadConst32(dst, 1);
4637          __ Movt(dst, ZERO, 0);
4638          break;
4639        case kCondLT:
4640          if (gt_bias) {
4641            __ ColtD(0, lhs, rhs);
4642          } else {
4643            __ CultD(0, lhs, rhs);
4644          }
4645          __ LoadConst32(dst, 1);
4646          __ Movf(dst, ZERO, 0);
4647          break;
4648        case kCondLE:
4649          if (gt_bias) {
4650            __ ColeD(0, lhs, rhs);
4651          } else {
4652            __ CuleD(0, lhs, rhs);
4653          }
4654          __ LoadConst32(dst, 1);
4655          __ Movf(dst, ZERO, 0);
4656          break;
4657        case kCondGT:
4658          if (gt_bias) {
4659            __ CultD(0, rhs, lhs);
4660          } else {
4661            __ ColtD(0, rhs, lhs);
4662          }
4663          __ LoadConst32(dst, 1);
4664          __ Movf(dst, ZERO, 0);
4665          break;
4666        case kCondGE:
4667          if (gt_bias) {
4668            __ CuleD(0, rhs, lhs);
4669          } else {
4670            __ ColeD(0, rhs, lhs);
4671          }
4672          __ LoadConst32(dst, 1);
4673          __ Movf(dst, ZERO, 0);
4674          break;
4675        default:
4676          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
4677          UNREACHABLE();
4678      }
4679    }
4680  }
4681}
4682
4683bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR2(IfCondition cond,
4684                                                          bool gt_bias,
4685                                                          Primitive::Type type,
4686                                                          LocationSummary* input_locations,
4687                                                          int cc) {
4688  FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
4689  FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
4690  CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
4691  if (type == Primitive::kPrimFloat) {
4692    switch (cond) {
4693      case kCondEQ:
4694        __ CeqS(cc, lhs, rhs);
4695        return false;
4696      case kCondNE:
4697        __ CeqS(cc, lhs, rhs);
4698        return true;
4699      case kCondLT:
4700        if (gt_bias) {
4701          __ ColtS(cc, lhs, rhs);
4702        } else {
4703          __ CultS(cc, lhs, rhs);
4704        }
4705        return false;
4706      case kCondLE:
4707        if (gt_bias) {
4708          __ ColeS(cc, lhs, rhs);
4709        } else {
4710          __ CuleS(cc, lhs, rhs);
4711        }
4712        return false;
4713      case kCondGT:
4714        if (gt_bias) {
4715          __ CultS(cc, rhs, lhs);
4716        } else {
4717          __ ColtS(cc, rhs, lhs);
4718        }
4719        return false;
4720      case kCondGE:
4721        if (gt_bias) {
4722          __ CuleS(cc, rhs, lhs);
4723        } else {
4724          __ ColeS(cc, rhs, lhs);
4725        }
4726        return false;
4727      default:
4728        LOG(FATAL) << "Unexpected non-floating-point condition";
4729        UNREACHABLE();
4730    }
4731  } else {
4732    DCHECK_EQ(type, Primitive::kPrimDouble);
4733    switch (cond) {
4734      case kCondEQ:
4735        __ CeqD(cc, lhs, rhs);
4736        return false;
4737      case kCondNE:
4738        __ CeqD(cc, lhs, rhs);
4739        return true;
4740      case kCondLT:
4741        if (gt_bias) {
4742          __ ColtD(cc, lhs, rhs);
4743        } else {
4744          __ CultD(cc, lhs, rhs);
4745        }
4746        return false;
4747      case kCondLE:
4748        if (gt_bias) {
4749          __ ColeD(cc, lhs, rhs);
4750        } else {
4751          __ CuleD(cc, lhs, rhs);
4752        }
4753        return false;
4754      case kCondGT:
4755        if (gt_bias) {
4756          __ CultD(cc, rhs, lhs);
4757        } else {
4758          __ ColtD(cc, rhs, lhs);
4759        }
4760        return false;
4761      case kCondGE:
4762        if (gt_bias) {
4763          __ CuleD(cc, rhs, lhs);
4764        } else {
4765          __ ColeD(cc, rhs, lhs);
4766        }
4767        return false;
4768      default:
4769        LOG(FATAL) << "Unexpected non-floating-point condition";
4770        UNREACHABLE();
4771    }
4772  }
4773}
4774
4775bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR6(IfCondition cond,
4776                                                          bool gt_bias,
4777                                                          Primitive::Type type,
4778                                                          LocationSummary* input_locations,
4779                                                          FRegister dst) {
4780  FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
4781  FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
4782  CHECK(codegen_->GetInstructionSetFeatures().IsR6());
4783  if (type == Primitive::kPrimFloat) {
4784    switch (cond) {
4785      case kCondEQ:
4786        __ CmpEqS(dst, lhs, rhs);
4787        return false;
4788      case kCondNE:
4789        __ CmpEqS(dst, lhs, rhs);
4790        return true;
4791      case kCondLT:
4792        if (gt_bias) {
4793          __ CmpLtS(dst, lhs, rhs);
4794        } else {
4795          __ CmpUltS(dst, lhs, rhs);
4796        }
4797        return false;
4798      case kCondLE:
4799        if (gt_bias) {
4800          __ CmpLeS(dst, lhs, rhs);
4801        } else {
4802          __ CmpUleS(dst, lhs, rhs);
4803        }
4804        return false;
4805      case kCondGT:
4806        if (gt_bias) {
4807          __ CmpUltS(dst, rhs, lhs);
4808        } else {
4809          __ CmpLtS(dst, rhs, lhs);
4810        }
4811        return false;
4812      case kCondGE:
4813        if (gt_bias) {
4814          __ CmpUleS(dst, rhs, lhs);
4815        } else {
4816          __ CmpLeS(dst, rhs, lhs);
4817        }
4818        return false;
4819      default:
4820        LOG(FATAL) << "Unexpected non-floating-point condition";
4821        UNREACHABLE();
4822    }
4823  } else {
4824    DCHECK_EQ(type, Primitive::kPrimDouble);
4825    switch (cond) {
4826      case kCondEQ:
4827        __ CmpEqD(dst, lhs, rhs);
4828        return false;
4829      case kCondNE:
4830        __ CmpEqD(dst, lhs, rhs);
4831        return true;
4832      case kCondLT:
4833        if (gt_bias) {
4834          __ CmpLtD(dst, lhs, rhs);
4835        } else {
4836          __ CmpUltD(dst, lhs, rhs);
4837        }
4838        return false;
4839      case kCondLE:
4840        if (gt_bias) {
4841          __ CmpLeD(dst, lhs, rhs);
4842        } else {
4843          __ CmpUleD(dst, lhs, rhs);
4844        }
4845        return false;
4846      case kCondGT:
4847        if (gt_bias) {
4848          __ CmpUltD(dst, rhs, lhs);
4849        } else {
4850          __ CmpLtD(dst, rhs, lhs);
4851        }
4852        return false;
4853      case kCondGE:
4854        if (gt_bias) {
4855          __ CmpUleD(dst, rhs, lhs);
4856        } else {
4857          __ CmpLeD(dst, rhs, lhs);
4858        }
4859        return false;
4860      default:
4861        LOG(FATAL) << "Unexpected non-floating-point condition";
4862        UNREACHABLE();
4863    }
4864  }
4865}
4866
4867void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
4868                                                              bool gt_bias,
4869                                                              Primitive::Type type,
4870                                                              LocationSummary* locations,
4871                                                              MipsLabel* label) {
4872  FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4873  FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
4874  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4875  if (type == Primitive::kPrimFloat) {
4876    if (isR6) {
4877      switch (cond) {
4878        case kCondEQ:
4879          __ CmpEqS(FTMP, lhs, rhs);
4880          __ Bc1nez(FTMP, label);
4881          break;
4882        case kCondNE:
4883          __ CmpEqS(FTMP, lhs, rhs);
4884          __ Bc1eqz(FTMP, label);
4885          break;
4886        case kCondLT:
4887          if (gt_bias) {
4888            __ CmpLtS(FTMP, lhs, rhs);
4889          } else {
4890            __ CmpUltS(FTMP, lhs, rhs);
4891          }
4892          __ Bc1nez(FTMP, label);
4893          break;
4894        case kCondLE:
4895          if (gt_bias) {
4896            __ CmpLeS(FTMP, lhs, rhs);
4897          } else {
4898            __ CmpUleS(FTMP, lhs, rhs);
4899          }
4900          __ Bc1nez(FTMP, label);
4901          break;
4902        case kCondGT:
4903          if (gt_bias) {
4904            __ CmpUltS(FTMP, rhs, lhs);
4905          } else {
4906            __ CmpLtS(FTMP, rhs, lhs);
4907          }
4908          __ Bc1nez(FTMP, label);
4909          break;
4910        case kCondGE:
4911          if (gt_bias) {
4912            __ CmpUleS(FTMP, rhs, lhs);
4913          } else {
4914            __ CmpLeS(FTMP, rhs, lhs);
4915          }
4916          __ Bc1nez(FTMP, label);
4917          break;
4918        default:
4919          LOG(FATAL) << "Unexpected non-floating-point condition";
4920          UNREACHABLE();
4921      }
4922    } else {
4923      switch (cond) {
4924        case kCondEQ:
4925          __ CeqS(0, lhs, rhs);
4926          __ Bc1t(0, label);
4927          break;
4928        case kCondNE:
4929          __ CeqS(0, lhs, rhs);
4930          __ Bc1f(0, label);
4931          break;
4932        case kCondLT:
4933          if (gt_bias) {
4934            __ ColtS(0, lhs, rhs);
4935          } else {
4936            __ CultS(0, lhs, rhs);
4937          }
4938          __ Bc1t(0, label);
4939          break;
4940        case kCondLE:
4941          if (gt_bias) {
4942            __ ColeS(0, lhs, rhs);
4943          } else {
4944            __ CuleS(0, lhs, rhs);
4945          }
4946          __ Bc1t(0, label);
4947          break;
4948        case kCondGT:
4949          if (gt_bias) {
4950            __ CultS(0, rhs, lhs);
4951          } else {
4952            __ ColtS(0, rhs, lhs);
4953          }
4954          __ Bc1t(0, label);
4955          break;
4956        case kCondGE:
4957          if (gt_bias) {
4958            __ CuleS(0, rhs, lhs);
4959          } else {
4960            __ ColeS(0, rhs, lhs);
4961          }
4962          __ Bc1t(0, label);
4963          break;
4964        default:
4965          LOG(FATAL) << "Unexpected non-floating-point condition";
4966          UNREACHABLE();
4967      }
4968    }
4969  } else {
4970    DCHECK_EQ(type, Primitive::kPrimDouble);
4971    if (isR6) {
4972      switch (cond) {
4973        case kCondEQ:
4974          __ CmpEqD(FTMP, lhs, rhs);
4975          __ Bc1nez(FTMP, label);
4976          break;
4977        case kCondNE:
4978          __ CmpEqD(FTMP, lhs, rhs);
4979          __ Bc1eqz(FTMP, label);
4980          break;
4981        case kCondLT:
4982          if (gt_bias) {
4983            __ CmpLtD(FTMP, lhs, rhs);
4984          } else {
4985            __ CmpUltD(FTMP, lhs, rhs);
4986          }
4987          __ Bc1nez(FTMP, label);
4988          break;
4989        case kCondLE:
4990          if (gt_bias) {
4991            __ CmpLeD(FTMP, lhs, rhs);
4992          } else {
4993            __ CmpUleD(FTMP, lhs, rhs);
4994          }
4995          __ Bc1nez(FTMP, label);
4996          break;
4997        case kCondGT:
4998          if (gt_bias) {
4999            __ CmpUltD(FTMP, rhs, lhs);
5000          } else {
5001            __ CmpLtD(FTMP, rhs, lhs);
5002          }
5003          __ Bc1nez(FTMP, label);
5004          break;
5005        case kCondGE:
5006          if (gt_bias) {
5007            __ CmpUleD(FTMP, rhs, lhs);
5008          } else {
5009            __ CmpLeD(FTMP, rhs, lhs);
5010          }
5011          __ Bc1nez(FTMP, label);
5012          break;
5013        default:
5014          LOG(FATAL) << "Unexpected non-floating-point condition";
5015          UNREACHABLE();
5016      }
5017    } else {
5018      switch (cond) {
5019        case kCondEQ:
5020          __ CeqD(0, lhs, rhs);
5021          __ Bc1t(0, label);
5022          break;
5023        case kCondNE:
5024          __ CeqD(0, lhs, rhs);
5025          __ Bc1f(0, label);
5026          break;
5027        case kCondLT:
5028          if (gt_bias) {
5029            __ ColtD(0, lhs, rhs);
5030          } else {
5031            __ CultD(0, lhs, rhs);
5032          }
5033          __ Bc1t(0, label);
5034          break;
5035        case kCondLE:
5036          if (gt_bias) {
5037            __ ColeD(0, lhs, rhs);
5038          } else {
5039            __ CuleD(0, lhs, rhs);
5040          }
5041          __ Bc1t(0, label);
5042          break;
5043        case kCondGT:
5044          if (gt_bias) {
5045            __ CultD(0, rhs, lhs);
5046          } else {
5047            __ ColtD(0, rhs, lhs);
5048          }
5049          __ Bc1t(0, label);
5050          break;
5051        case kCondGE:
5052          if (gt_bias) {
5053            __ CuleD(0, rhs, lhs);
5054          } else {
5055            __ ColeD(0, rhs, lhs);
5056          }
5057          __ Bc1t(0, label);
5058          break;
5059        default:
5060          LOG(FATAL) << "Unexpected non-floating-point condition";
5061          UNREACHABLE();
5062      }
5063    }
5064  }
5065}
5066
5067void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
5068                                                         size_t condition_input_index,
5069                                                         MipsLabel* true_target,
5070                                                         MipsLabel* false_target) {
5071  HInstruction* cond = instruction->InputAt(condition_input_index);
5072
5073  if (true_target == nullptr && false_target == nullptr) {
5074    // Nothing to do. The code always falls through.
5075    return;
5076  } else if (cond->IsIntConstant()) {
5077    // Constant condition, statically compared against "true" (integer value 1).
5078    if (cond->AsIntConstant()->IsTrue()) {
5079      if (true_target != nullptr) {
5080        __ B(true_target);
5081      }
5082    } else {
5083      DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
5084      if (false_target != nullptr) {
5085        __ B(false_target);
5086      }
5087    }
5088    return;
5089  }
5090
5091  // The following code generates these patterns:
5092  //  (1) true_target == nullptr && false_target != nullptr
5093  //        - opposite condition true => branch to false_target
5094  //  (2) true_target != nullptr && false_target == nullptr
5095  //        - condition true => branch to true_target
5096  //  (3) true_target != nullptr && false_target != nullptr
5097  //        - condition true => branch to true_target
5098  //        - branch to false_target
5099  if (IsBooleanValueOrMaterializedCondition(cond)) {
5100    // The condition instruction has been materialized, compare the output to 0.
5101    Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
5102    DCHECK(cond_val.IsRegister());
5103    if (true_target == nullptr) {
5104      __ Beqz(cond_val.AsRegister<Register>(), false_target);
5105    } else {
5106      __ Bnez(cond_val.AsRegister<Register>(), true_target);
5107    }
5108  } else {
5109    // The condition instruction has not been materialized, use its inputs as
5110    // the comparison and its condition as the branch condition.
5111    HCondition* condition = cond->AsCondition();
5112    Primitive::Type type = condition->InputAt(0)->GetType();
5113    LocationSummary* locations = cond->GetLocations();
5114    IfCondition if_cond = condition->GetCondition();
5115    MipsLabel* branch_target = true_target;
5116
5117    if (true_target == nullptr) {
5118      if_cond = condition->GetOppositeCondition();
5119      branch_target = false_target;
5120    }
5121
5122    switch (type) {
5123      default:
5124        GenerateIntCompareAndBranch(if_cond, locations, branch_target);
5125        break;
5126      case Primitive::kPrimLong:
5127        GenerateLongCompareAndBranch(if_cond, locations, branch_target);
5128        break;
5129      case Primitive::kPrimFloat:
5130      case Primitive::kPrimDouble:
5131        GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
5132        break;
5133    }
5134  }
5135
5136  // If neither branch falls through (case 3), the conditional branch to `true_target`
5137  // was already emitted (case 2) and we need to emit a jump to `false_target`.
5138  if (true_target != nullptr && false_target != nullptr) {
5139    __ B(false_target);
5140  }
5141}
5142
5143void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
5144  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
5145  if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
5146    locations->SetInAt(0, Location::RequiresRegister());
5147  }
5148}
5149
5150void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
5151  HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
5152  HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
5153  MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
5154      nullptr : codegen_->GetLabelOf(true_successor);
5155  MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
5156      nullptr : codegen_->GetLabelOf(false_successor);
5157  GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
5158}
5159
5160void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
5161  LocationSummary* locations = new (GetGraph()->GetArena())
5162      LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
5163  InvokeRuntimeCallingConvention calling_convention;
5164  RegisterSet caller_saves = RegisterSet::Empty();
5165  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5166  locations->SetCustomSlowPathCallerSaves(caller_saves);
5167  if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
5168    locations->SetInAt(0, Location::RequiresRegister());
5169  }
5170}
5171
5172void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
5173  SlowPathCodeMIPS* slow_path =
5174      deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
5175  GenerateTestAndBranch(deoptimize,
5176                        /* condition_input_index */ 0,
5177                        slow_path->GetEntryLabel(),
5178                        /* false_target */ nullptr);
5179}
5180
5181// This function returns true if a conditional move can be generated for HSelect.
5182// Otherwise it returns false and HSelect must be implemented in terms of conditonal
5183// branches and regular moves.
5184//
5185// If `locations_to_set` isn't nullptr, its inputs and outputs are set for HSelect.
5186//
5187// While determining feasibility of a conditional move and setting inputs/outputs
5188// are two distinct tasks, this function does both because they share quite a bit
5189// of common logic.
5190static bool CanMoveConditionally(HSelect* select, bool is_r6, LocationSummary* locations_to_set) {
5191  bool materialized = IsBooleanValueOrMaterializedCondition(select->GetCondition());
5192  HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5193  HCondition* condition = cond->AsCondition();
5194
5195  Primitive::Type cond_type = materialized ? Primitive::kPrimInt : condition->InputAt(0)->GetType();
5196  Primitive::Type dst_type = select->GetType();
5197
5198  HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
5199  HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
5200  bool is_true_value_zero_constant =
5201      (cst_true_value != nullptr && cst_true_value->IsZeroBitPattern());
5202  bool is_false_value_zero_constant =
5203      (cst_false_value != nullptr && cst_false_value->IsZeroBitPattern());
5204
5205  bool can_move_conditionally = false;
5206  bool use_const_for_false_in = false;
5207  bool use_const_for_true_in = false;
5208
5209  if (!cond->IsConstant()) {
5210    switch (cond_type) {
5211      default:
5212        switch (dst_type) {
5213          default:
5214            // Moving int on int condition.
5215            if (is_r6) {
5216              if (is_true_value_zero_constant) {
5217                // seleqz out_reg, false_reg, cond_reg
5218                can_move_conditionally = true;
5219                use_const_for_true_in = true;
5220              } else if (is_false_value_zero_constant) {
5221                // selnez out_reg, true_reg, cond_reg
5222                can_move_conditionally = true;
5223                use_const_for_false_in = true;
5224              } else if (materialized) {
5225                // Not materializing unmaterialized int conditions
5226                // to keep the instruction count low.
5227                // selnez AT, true_reg, cond_reg
5228                // seleqz TMP, false_reg, cond_reg
5229                // or out_reg, AT, TMP
5230                can_move_conditionally = true;
5231              }
5232            } else {
5233              // movn out_reg, true_reg/ZERO, cond_reg
5234              can_move_conditionally = true;
5235              use_const_for_true_in = is_true_value_zero_constant;
5236            }
5237            break;
5238          case Primitive::kPrimLong:
5239            // Moving long on int condition.
5240            if (is_r6) {
5241              if (is_true_value_zero_constant) {
5242                // seleqz out_reg_lo, false_reg_lo, cond_reg
5243                // seleqz out_reg_hi, false_reg_hi, cond_reg
5244                can_move_conditionally = true;
5245                use_const_for_true_in = true;
5246              } else if (is_false_value_zero_constant) {
5247                // selnez out_reg_lo, true_reg_lo, cond_reg
5248                // selnez out_reg_hi, true_reg_hi, cond_reg
5249                can_move_conditionally = true;
5250                use_const_for_false_in = true;
5251              }
5252              // Other long conditional moves would generate 6+ instructions,
5253              // which is too many.
5254            } else {
5255              // movn out_reg_lo, true_reg_lo/ZERO, cond_reg
5256              // movn out_reg_hi, true_reg_hi/ZERO, cond_reg
5257              can_move_conditionally = true;
5258              use_const_for_true_in = is_true_value_zero_constant;
5259            }
5260            break;
5261          case Primitive::kPrimFloat:
5262          case Primitive::kPrimDouble:
5263            // Moving float/double on int condition.
5264            if (is_r6) {
5265              if (materialized) {
5266                // Not materializing unmaterialized int conditions
5267                // to keep the instruction count low.
5268                can_move_conditionally = true;
5269                if (is_true_value_zero_constant) {
5270                  // sltu TMP, ZERO, cond_reg
5271                  // mtc1 TMP, temp_cond_reg
5272                  // seleqz.fmt out_reg, false_reg, temp_cond_reg
5273                  use_const_for_true_in = true;
5274                } else if (is_false_value_zero_constant) {
5275                  // sltu TMP, ZERO, cond_reg
5276                  // mtc1 TMP, temp_cond_reg
5277                  // selnez.fmt out_reg, true_reg, temp_cond_reg
5278                  use_const_for_false_in = true;
5279                } else {
5280                  // sltu TMP, ZERO, cond_reg
5281                  // mtc1 TMP, temp_cond_reg
5282                  // sel.fmt temp_cond_reg, false_reg, true_reg
5283                  // mov.fmt out_reg, temp_cond_reg
5284                }
5285              }
5286            } else {
5287              // movn.fmt out_reg, true_reg, cond_reg
5288              can_move_conditionally = true;
5289            }
5290            break;
5291        }
5292        break;
5293      case Primitive::kPrimLong:
5294        // We don't materialize long comparison now
5295        // and use conditional branches instead.
5296        break;
5297      case Primitive::kPrimFloat:
5298      case Primitive::kPrimDouble:
5299        switch (dst_type) {
5300          default:
5301            // Moving int on float/double condition.
5302            if (is_r6) {
5303              if (is_true_value_zero_constant) {
5304                // mfc1 TMP, temp_cond_reg
5305                // seleqz out_reg, false_reg, TMP
5306                can_move_conditionally = true;
5307                use_const_for_true_in = true;
5308              } else if (is_false_value_zero_constant) {
5309                // mfc1 TMP, temp_cond_reg
5310                // selnez out_reg, true_reg, TMP
5311                can_move_conditionally = true;
5312                use_const_for_false_in = true;
5313              } else {
5314                // mfc1 TMP, temp_cond_reg
5315                // selnez AT, true_reg, TMP
5316                // seleqz TMP, false_reg, TMP
5317                // or out_reg, AT, TMP
5318                can_move_conditionally = true;
5319              }
5320            } else {
5321              // movt out_reg, true_reg/ZERO, cc
5322              can_move_conditionally = true;
5323              use_const_for_true_in = is_true_value_zero_constant;
5324            }
5325            break;
5326          case Primitive::kPrimLong:
5327            // Moving long on float/double condition.
5328            if (is_r6) {
5329              if (is_true_value_zero_constant) {
5330                // mfc1 TMP, temp_cond_reg
5331                // seleqz out_reg_lo, false_reg_lo, TMP
5332                // seleqz out_reg_hi, false_reg_hi, TMP
5333                can_move_conditionally = true;
5334                use_const_for_true_in = true;
5335              } else if (is_false_value_zero_constant) {
5336                // mfc1 TMP, temp_cond_reg
5337                // selnez out_reg_lo, true_reg_lo, TMP
5338                // selnez out_reg_hi, true_reg_hi, TMP
5339                can_move_conditionally = true;
5340                use_const_for_false_in = true;
5341              }
5342              // Other long conditional moves would generate 6+ instructions,
5343              // which is too many.
5344            } else {
5345              // movt out_reg_lo, true_reg_lo/ZERO, cc
5346              // movt out_reg_hi, true_reg_hi/ZERO, cc
5347              can_move_conditionally = true;
5348              use_const_for_true_in = is_true_value_zero_constant;
5349            }
5350            break;
5351          case Primitive::kPrimFloat:
5352          case Primitive::kPrimDouble:
5353            // Moving float/double on float/double condition.
5354            if (is_r6) {
5355              can_move_conditionally = true;
5356              if (is_true_value_zero_constant) {
5357                // seleqz.fmt out_reg, false_reg, temp_cond_reg
5358                use_const_for_true_in = true;
5359              } else if (is_false_value_zero_constant) {
5360                // selnez.fmt out_reg, true_reg, temp_cond_reg
5361                use_const_for_false_in = true;
5362              } else {
5363                // sel.fmt temp_cond_reg, false_reg, true_reg
5364                // mov.fmt out_reg, temp_cond_reg
5365              }
5366            } else {
5367              // movt.fmt out_reg, true_reg, cc
5368              can_move_conditionally = true;
5369            }
5370            break;
5371        }
5372        break;
5373    }
5374  }
5375
5376  if (can_move_conditionally) {
5377    DCHECK(!use_const_for_false_in || !use_const_for_true_in);
5378  } else {
5379    DCHECK(!use_const_for_false_in);
5380    DCHECK(!use_const_for_true_in);
5381  }
5382
5383  if (locations_to_set != nullptr) {
5384    if (use_const_for_false_in) {
5385      locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
5386    } else {
5387      locations_to_set->SetInAt(0,
5388                                Primitive::IsFloatingPointType(dst_type)
5389                                    ? Location::RequiresFpuRegister()
5390                                    : Location::RequiresRegister());
5391    }
5392    if (use_const_for_true_in) {
5393      locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
5394    } else {
5395      locations_to_set->SetInAt(1,
5396                                Primitive::IsFloatingPointType(dst_type)
5397                                    ? Location::RequiresFpuRegister()
5398                                    : Location::RequiresRegister());
5399    }
5400    if (materialized) {
5401      locations_to_set->SetInAt(2, Location::RequiresRegister());
5402    }
5403    // On R6 we don't require the output to be the same as the
5404    // first input for conditional moves unlike on R2.
5405    bool is_out_same_as_first_in = !can_move_conditionally || !is_r6;
5406    if (is_out_same_as_first_in) {
5407      locations_to_set->SetOut(Location::SameAsFirstInput());
5408    } else {
5409      locations_to_set->SetOut(Primitive::IsFloatingPointType(dst_type)
5410                                   ? Location::RequiresFpuRegister()
5411                                   : Location::RequiresRegister());
5412    }
5413  }
5414
5415  return can_move_conditionally;
5416}
5417
5418void InstructionCodeGeneratorMIPS::GenConditionalMoveR2(HSelect* select) {
5419  LocationSummary* locations = select->GetLocations();
5420  Location dst = locations->Out();
5421  Location src = locations->InAt(1);
5422  Register src_reg = ZERO;
5423  Register src_reg_high = ZERO;
5424  HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5425  Register cond_reg = TMP;
5426  int cond_cc = 0;
5427  Primitive::Type cond_type = Primitive::kPrimInt;
5428  bool cond_inverted = false;
5429  Primitive::Type dst_type = select->GetType();
5430
5431  if (IsBooleanValueOrMaterializedCondition(cond)) {
5432    cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
5433  } else {
5434    HCondition* condition = cond->AsCondition();
5435    LocationSummary* cond_locations = cond->GetLocations();
5436    IfCondition if_cond = condition->GetCondition();
5437    cond_type = condition->InputAt(0)->GetType();
5438    switch (cond_type) {
5439      default:
5440        DCHECK_NE(cond_type, Primitive::kPrimLong);
5441        cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
5442        break;
5443      case Primitive::kPrimFloat:
5444      case Primitive::kPrimDouble:
5445        cond_inverted = MaterializeFpCompareR2(if_cond,
5446                                               condition->IsGtBias(),
5447                                               cond_type,
5448                                               cond_locations,
5449                                               cond_cc);
5450        break;
5451    }
5452  }
5453
5454  DCHECK(dst.Equals(locations->InAt(0)));
5455  if (src.IsRegister()) {
5456    src_reg = src.AsRegister<Register>();
5457  } else if (src.IsRegisterPair()) {
5458    src_reg = src.AsRegisterPairLow<Register>();
5459    src_reg_high = src.AsRegisterPairHigh<Register>();
5460  } else if (src.IsConstant()) {
5461    DCHECK(src.GetConstant()->IsZeroBitPattern());
5462  }
5463
5464  switch (cond_type) {
5465    default:
5466      switch (dst_type) {
5467        default:
5468          if (cond_inverted) {
5469            __ Movz(dst.AsRegister<Register>(), src_reg, cond_reg);
5470          } else {
5471            __ Movn(dst.AsRegister<Register>(), src_reg, cond_reg);
5472          }
5473          break;
5474        case Primitive::kPrimLong:
5475          if (cond_inverted) {
5476            __ Movz(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
5477            __ Movz(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
5478          } else {
5479            __ Movn(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
5480            __ Movn(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
5481          }
5482          break;
5483        case Primitive::kPrimFloat:
5484          if (cond_inverted) {
5485            __ MovzS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5486          } else {
5487            __ MovnS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5488          }
5489          break;
5490        case Primitive::kPrimDouble:
5491          if (cond_inverted) {
5492            __ MovzD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5493          } else {
5494            __ MovnD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5495          }
5496          break;
5497      }
5498      break;
5499    case Primitive::kPrimLong:
5500      LOG(FATAL) << "Unreachable";
5501      UNREACHABLE();
5502    case Primitive::kPrimFloat:
5503    case Primitive::kPrimDouble:
5504      switch (dst_type) {
5505        default:
5506          if (cond_inverted) {
5507            __ Movf(dst.AsRegister<Register>(), src_reg, cond_cc);
5508          } else {
5509            __ Movt(dst.AsRegister<Register>(), src_reg, cond_cc);
5510          }
5511          break;
5512        case Primitive::kPrimLong:
5513          if (cond_inverted) {
5514            __ Movf(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
5515            __ Movf(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
5516          } else {
5517            __ Movt(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
5518            __ Movt(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
5519          }
5520          break;
5521        case Primitive::kPrimFloat:
5522          if (cond_inverted) {
5523            __ MovfS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5524          } else {
5525            __ MovtS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5526          }
5527          break;
5528        case Primitive::kPrimDouble:
5529          if (cond_inverted) {
5530            __ MovfD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5531          } else {
5532            __ MovtD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5533          }
5534          break;
5535      }
5536      break;
5537  }
5538}
5539
5540void InstructionCodeGeneratorMIPS::GenConditionalMoveR6(HSelect* select) {
5541  LocationSummary* locations = select->GetLocations();
5542  Location dst = locations->Out();
5543  Location false_src = locations->InAt(0);
5544  Location true_src = locations->InAt(1);
5545  HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5546  Register cond_reg = TMP;
5547  FRegister fcond_reg = FTMP;
5548  Primitive::Type cond_type = Primitive::kPrimInt;
5549  bool cond_inverted = false;
5550  Primitive::Type dst_type = select->GetType();
5551
5552  if (IsBooleanValueOrMaterializedCondition(cond)) {
5553    cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
5554  } else {
5555    HCondition* condition = cond->AsCondition();
5556    LocationSummary* cond_locations = cond->GetLocations();
5557    IfCondition if_cond = condition->GetCondition();
5558    cond_type = condition->InputAt(0)->GetType();
5559    switch (cond_type) {
5560      default:
5561        DCHECK_NE(cond_type, Primitive::kPrimLong);
5562        cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
5563        break;
5564      case Primitive::kPrimFloat:
5565      case Primitive::kPrimDouble:
5566        cond_inverted = MaterializeFpCompareR6(if_cond,
5567                                               condition->IsGtBias(),
5568                                               cond_type,
5569                                               cond_locations,
5570                                               fcond_reg);
5571        break;
5572    }
5573  }
5574
5575  if (true_src.IsConstant()) {
5576    DCHECK(true_src.GetConstant()->IsZeroBitPattern());
5577  }
5578  if (false_src.IsConstant()) {
5579    DCHECK(false_src.GetConstant()->IsZeroBitPattern());
5580  }
5581
5582  switch (dst_type) {
5583    default:
5584      if (Primitive::IsFloatingPointType(cond_type)) {
5585        __ Mfc1(cond_reg, fcond_reg);
5586      }
5587      if (true_src.IsConstant()) {
5588        if (cond_inverted) {
5589          __ Selnez(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
5590        } else {
5591          __ Seleqz(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
5592        }
5593      } else if (false_src.IsConstant()) {
5594        if (cond_inverted) {
5595          __ Seleqz(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
5596        } else {
5597          __ Selnez(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
5598        }
5599      } else {
5600        DCHECK_NE(cond_reg, AT);
5601        if (cond_inverted) {
5602          __ Seleqz(AT, true_src.AsRegister<Register>(), cond_reg);
5603          __ Selnez(TMP, false_src.AsRegister<Register>(), cond_reg);
5604        } else {
5605          __ Selnez(AT, true_src.AsRegister<Register>(), cond_reg);
5606          __ Seleqz(TMP, false_src.AsRegister<Register>(), cond_reg);
5607        }
5608        __ Or(dst.AsRegister<Register>(), AT, TMP);
5609      }
5610      break;
5611    case Primitive::kPrimLong: {
5612      if (Primitive::IsFloatingPointType(cond_type)) {
5613        __ Mfc1(cond_reg, fcond_reg);
5614      }
5615      Register dst_lo = dst.AsRegisterPairLow<Register>();
5616      Register dst_hi = dst.AsRegisterPairHigh<Register>();
5617      if (true_src.IsConstant()) {
5618        Register src_lo = false_src.AsRegisterPairLow<Register>();
5619        Register src_hi = false_src.AsRegisterPairHigh<Register>();
5620        if (cond_inverted) {
5621          __ Selnez(dst_lo, src_lo, cond_reg);
5622          __ Selnez(dst_hi, src_hi, cond_reg);
5623        } else {
5624          __ Seleqz(dst_lo, src_lo, cond_reg);
5625          __ Seleqz(dst_hi, src_hi, cond_reg);
5626        }
5627      } else {
5628        DCHECK(false_src.IsConstant());
5629        Register src_lo = true_src.AsRegisterPairLow<Register>();
5630        Register src_hi = true_src.AsRegisterPairHigh<Register>();
5631        if (cond_inverted) {
5632          __ Seleqz(dst_lo, src_lo, cond_reg);
5633          __ Seleqz(dst_hi, src_hi, cond_reg);
5634        } else {
5635          __ Selnez(dst_lo, src_lo, cond_reg);
5636          __ Selnez(dst_hi, src_hi, cond_reg);
5637        }
5638      }
5639      break;
5640    }
5641    case Primitive::kPrimFloat: {
5642      if (!Primitive::IsFloatingPointType(cond_type)) {
5643        // sel*.fmt tests bit 0 of the condition register, account for that.
5644        __ Sltu(TMP, ZERO, cond_reg);
5645        __ Mtc1(TMP, fcond_reg);
5646      }
5647      FRegister dst_reg = dst.AsFpuRegister<FRegister>();
5648      if (true_src.IsConstant()) {
5649        FRegister src_reg = false_src.AsFpuRegister<FRegister>();
5650        if (cond_inverted) {
5651          __ SelnezS(dst_reg, src_reg, fcond_reg);
5652        } else {
5653          __ SeleqzS(dst_reg, src_reg, fcond_reg);
5654        }
5655      } else if (false_src.IsConstant()) {
5656        FRegister src_reg = true_src.AsFpuRegister<FRegister>();
5657        if (cond_inverted) {
5658          __ SeleqzS(dst_reg, src_reg, fcond_reg);
5659        } else {
5660          __ SelnezS(dst_reg, src_reg, fcond_reg);
5661        }
5662      } else {
5663        if (cond_inverted) {
5664          __ SelS(fcond_reg,
5665                  true_src.AsFpuRegister<FRegister>(),
5666                  false_src.AsFpuRegister<FRegister>());
5667        } else {
5668          __ SelS(fcond_reg,
5669                  false_src.AsFpuRegister<FRegister>(),
5670                  true_src.AsFpuRegister<FRegister>());
5671        }
5672        __ MovS(dst_reg, fcond_reg);
5673      }
5674      break;
5675    }
5676    case Primitive::kPrimDouble: {
5677      if (!Primitive::IsFloatingPointType(cond_type)) {
5678        // sel*.fmt tests bit 0 of the condition register, account for that.
5679        __ Sltu(TMP, ZERO, cond_reg);
5680        __ Mtc1(TMP, fcond_reg);
5681      }
5682      FRegister dst_reg = dst.AsFpuRegister<FRegister>();
5683      if (true_src.IsConstant()) {
5684        FRegister src_reg = false_src.AsFpuRegister<FRegister>();
5685        if (cond_inverted) {
5686          __ SelnezD(dst_reg, src_reg, fcond_reg);
5687        } else {
5688          __ SeleqzD(dst_reg, src_reg, fcond_reg);
5689        }
5690      } else if (false_src.IsConstant()) {
5691        FRegister src_reg = true_src.AsFpuRegister<FRegister>();
5692        if (cond_inverted) {
5693          __ SeleqzD(dst_reg, src_reg, fcond_reg);
5694        } else {
5695          __ SelnezD(dst_reg, src_reg, fcond_reg);
5696        }
5697      } else {
5698        if (cond_inverted) {
5699          __ SelD(fcond_reg,
5700                  true_src.AsFpuRegister<FRegister>(),
5701                  false_src.AsFpuRegister<FRegister>());
5702        } else {
5703          __ SelD(fcond_reg,
5704                  false_src.AsFpuRegister<FRegister>(),
5705                  true_src.AsFpuRegister<FRegister>());
5706        }
5707        __ MovD(dst_reg, fcond_reg);
5708      }
5709      break;
5710    }
5711  }
5712}
5713
5714void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
5715  LocationSummary* locations = new (GetGraph()->GetArena())
5716      LocationSummary(flag, LocationSummary::kNoCall);
5717  locations->SetOut(Location::RequiresRegister());
5718}
5719
5720void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
5721  __ LoadFromOffset(kLoadWord,
5722                    flag->GetLocations()->Out().AsRegister<Register>(),
5723                    SP,
5724                    codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
5725}
5726
5727void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
5728  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
5729  CanMoveConditionally(select, codegen_->GetInstructionSetFeatures().IsR6(), locations);
5730}
5731
5732void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
5733  bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
5734  if (CanMoveConditionally(select, is_r6, /* locations_to_set */ nullptr)) {
5735    if (is_r6) {
5736      GenConditionalMoveR6(select);
5737    } else {
5738      GenConditionalMoveR2(select);
5739    }
5740  } else {
5741    LocationSummary* locations = select->GetLocations();
5742    MipsLabel false_target;
5743    GenerateTestAndBranch(select,
5744                          /* condition_input_index */ 2,
5745                          /* true_target */ nullptr,
5746                          &false_target);
5747    codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
5748    __ Bind(&false_target);
5749  }
5750}
5751
5752void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
5753  new (GetGraph()->GetArena()) LocationSummary(info);
5754}
5755
5756void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
5757  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
5758}
5759
5760void CodeGeneratorMIPS::GenerateNop() {
5761  __ Nop();
5762}
5763
5764void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5765  Primitive::Type field_type = field_info.GetFieldType();
5766  bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
5767  bool generate_volatile = field_info.IsVolatile() && is_wide;
5768  bool object_field_get_with_read_barrier =
5769      kEmitCompilerReadBarrier && (field_type == Primitive::kPrimNot);
5770  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
5771      instruction,
5772      generate_volatile
5773          ? LocationSummary::kCallOnMainOnly
5774          : (object_field_get_with_read_barrier
5775              ? LocationSummary::kCallOnSlowPath
5776              : LocationSummary::kNoCall));
5777
5778  locations->SetInAt(0, Location::RequiresRegister());
5779  if (generate_volatile) {
5780    InvokeRuntimeCallingConvention calling_convention;
5781    // need A0 to hold base + offset
5782    locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5783    if (field_type == Primitive::kPrimLong) {
5784      locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimLong));
5785    } else {
5786      // Use Location::Any() to prevent situations when running out of available fp registers.
5787      locations->SetOut(Location::Any());
5788      // Need some temp core regs since FP results are returned in core registers
5789      Location reg = calling_convention.GetReturnLocation(Primitive::kPrimLong);
5790      locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
5791      locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
5792    }
5793  } else {
5794    if (Primitive::IsFloatingPointType(instruction->GetType())) {
5795      locations->SetOut(Location::RequiresFpuRegister());
5796    } else {
5797      // The output overlaps in the case of an object field get with
5798      // read barriers enabled: we do not want the move to overwrite the
5799      // object's location, as we need it to emit the read barrier.
5800      locations->SetOut(Location::RequiresRegister(),
5801                        object_field_get_with_read_barrier
5802                            ? Location::kOutputOverlap
5803                            : Location::kNoOutputOverlap);
5804    }
5805    if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5806      // We need a temporary register for the read barrier marking slow
5807      // path in CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier.
5808      locations->AddTemp(Location::RequiresRegister());
5809    }
5810  }
5811}
5812
5813void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
5814                                                  const FieldInfo& field_info,
5815                                                  uint32_t dex_pc) {
5816  Primitive::Type type = field_info.GetFieldType();
5817  LocationSummary* locations = instruction->GetLocations();
5818  Location obj_loc = locations->InAt(0);
5819  Register obj = obj_loc.AsRegister<Register>();
5820  Location dst_loc = locations->Out();
5821  LoadOperandType load_type = kLoadUnsignedByte;
5822  bool is_volatile = field_info.IsVolatile();
5823  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5824  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
5825
5826  switch (type) {
5827    case Primitive::kPrimBoolean:
5828      load_type = kLoadUnsignedByte;
5829      break;
5830    case Primitive::kPrimByte:
5831      load_type = kLoadSignedByte;
5832      break;
5833    case Primitive::kPrimShort:
5834      load_type = kLoadSignedHalfword;
5835      break;
5836    case Primitive::kPrimChar:
5837      load_type = kLoadUnsignedHalfword;
5838      break;
5839    case Primitive::kPrimInt:
5840    case Primitive::kPrimFloat:
5841    case Primitive::kPrimNot:
5842      load_type = kLoadWord;
5843      break;
5844    case Primitive::kPrimLong:
5845    case Primitive::kPrimDouble:
5846      load_type = kLoadDoubleword;
5847      break;
5848    case Primitive::kPrimVoid:
5849      LOG(FATAL) << "Unreachable type " << type;
5850      UNREACHABLE();
5851  }
5852
5853  if (is_volatile && load_type == kLoadDoubleword) {
5854    InvokeRuntimeCallingConvention calling_convention;
5855    __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
5856    // Do implicit Null check
5857    __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
5858    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5859    codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
5860    CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
5861    if (type == Primitive::kPrimDouble) {
5862      // FP results are returned in core registers. Need to move them.
5863      if (dst_loc.IsFpuRegister()) {
5864        __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), dst_loc.AsFpuRegister<FRegister>());
5865        __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
5866                         dst_loc.AsFpuRegister<FRegister>());
5867      } else {
5868        DCHECK(dst_loc.IsDoubleStackSlot());
5869        __ StoreToOffset(kStoreWord,
5870                         locations->GetTemp(1).AsRegister<Register>(),
5871                         SP,
5872                         dst_loc.GetStackIndex());
5873        __ StoreToOffset(kStoreWord,
5874                         locations->GetTemp(2).AsRegister<Register>(),
5875                         SP,
5876                         dst_loc.GetStackIndex() + 4);
5877      }
5878    }
5879  } else {
5880    if (type == Primitive::kPrimNot) {
5881      // /* HeapReference<Object> */ dst = *(obj + offset)
5882      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5883        Location temp_loc = locations->GetTemp(0);
5884        // Note that a potential implicit null check is handled in this
5885        // CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier call.
5886        codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
5887                                                        dst_loc,
5888                                                        obj,
5889                                                        offset,
5890                                                        temp_loc,
5891                                                        /* needs_null_check */ true);
5892        if (is_volatile) {
5893          GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5894        }
5895      } else {
5896        __ LoadFromOffset(kLoadWord, dst_loc.AsRegister<Register>(), obj, offset, null_checker);
5897        if (is_volatile) {
5898          GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5899        }
5900        // If read barriers are enabled, emit read barriers other than
5901        // Baker's using a slow path (and also unpoison the loaded
5902        // reference, if heap poisoning is enabled).
5903        codegen_->MaybeGenerateReadBarrierSlow(instruction, dst_loc, dst_loc, obj_loc, offset);
5904      }
5905    } else if (!Primitive::IsFloatingPointType(type)) {
5906      Register dst;
5907      if (type == Primitive::kPrimLong) {
5908        DCHECK(dst_loc.IsRegisterPair());
5909        dst = dst_loc.AsRegisterPairLow<Register>();
5910      } else {
5911        DCHECK(dst_loc.IsRegister());
5912        dst = dst_loc.AsRegister<Register>();
5913      }
5914      __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
5915    } else {
5916      DCHECK(dst_loc.IsFpuRegister());
5917      FRegister dst = dst_loc.AsFpuRegister<FRegister>();
5918      if (type == Primitive::kPrimFloat) {
5919        __ LoadSFromOffset(dst, obj, offset, null_checker);
5920      } else {
5921        __ LoadDFromOffset(dst, obj, offset, null_checker);
5922      }
5923    }
5924  }
5925
5926  // Memory barriers, in the case of references, are handled in the
5927  // previous switch statement.
5928  if (is_volatile && (type != Primitive::kPrimNot)) {
5929    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5930  }
5931}
5932
5933void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5934  Primitive::Type field_type = field_info.GetFieldType();
5935  bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
5936  bool generate_volatile = field_info.IsVolatile() && is_wide;
5937  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
5938      instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
5939
5940  locations->SetInAt(0, Location::RequiresRegister());
5941  if (generate_volatile) {
5942    InvokeRuntimeCallingConvention calling_convention;
5943    // need A0 to hold base + offset
5944    locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5945    if (field_type == Primitive::kPrimLong) {
5946      locations->SetInAt(1, Location::RegisterPairLocation(
5947          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
5948    } else {
5949      // Use Location::Any() to prevent situations when running out of available fp registers.
5950      locations->SetInAt(1, Location::Any());
5951      // Pass FP parameters in core registers.
5952      locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
5953      locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
5954    }
5955  } else {
5956    if (Primitive::IsFloatingPointType(field_type)) {
5957      locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
5958    } else {
5959      locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
5960    }
5961  }
5962}
5963
5964void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
5965                                                  const FieldInfo& field_info,
5966                                                  uint32_t dex_pc,
5967                                                  bool value_can_be_null) {
5968  Primitive::Type type = field_info.GetFieldType();
5969  LocationSummary* locations = instruction->GetLocations();
5970  Register obj = locations->InAt(0).AsRegister<Register>();
5971  Location value_location = locations->InAt(1);
5972  StoreOperandType store_type = kStoreByte;
5973  bool is_volatile = field_info.IsVolatile();
5974  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5975  bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1));
5976  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
5977
5978  switch (type) {
5979    case Primitive::kPrimBoolean:
5980    case Primitive::kPrimByte:
5981      store_type = kStoreByte;
5982      break;
5983    case Primitive::kPrimShort:
5984    case Primitive::kPrimChar:
5985      store_type = kStoreHalfword;
5986      break;
5987    case Primitive::kPrimInt:
5988    case Primitive::kPrimFloat:
5989    case Primitive::kPrimNot:
5990      store_type = kStoreWord;
5991      break;
5992    case Primitive::kPrimLong:
5993    case Primitive::kPrimDouble:
5994      store_type = kStoreDoubleword;
5995      break;
5996    case Primitive::kPrimVoid:
5997      LOG(FATAL) << "Unreachable type " << type;
5998      UNREACHABLE();
5999  }
6000
6001  if (is_volatile) {
6002    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
6003  }
6004
6005  if (is_volatile && store_type == kStoreDoubleword) {
6006    InvokeRuntimeCallingConvention calling_convention;
6007    __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
6008    // Do implicit Null check.
6009    __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
6010    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
6011    if (type == Primitive::kPrimDouble) {
6012      // Pass FP parameters in core registers.
6013      if (value_location.IsFpuRegister()) {
6014        __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
6015                value_location.AsFpuRegister<FRegister>());
6016        __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
6017                           value_location.AsFpuRegister<FRegister>());
6018      } else if (value_location.IsDoubleStackSlot()) {
6019        __ LoadFromOffset(kLoadWord,
6020                          locations->GetTemp(1).AsRegister<Register>(),
6021                          SP,
6022                          value_location.GetStackIndex());
6023        __ LoadFromOffset(kLoadWord,
6024                          locations->GetTemp(2).AsRegister<Register>(),
6025                          SP,
6026                          value_location.GetStackIndex() + 4);
6027      } else {
6028        DCHECK(value_location.IsConstant());
6029        DCHECK(value_location.GetConstant()->IsDoubleConstant());
6030        int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
6031        __ LoadConst64(locations->GetTemp(2).AsRegister<Register>(),
6032                       locations->GetTemp(1).AsRegister<Register>(),
6033                       value);
6034      }
6035    }
6036    codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc);
6037    CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
6038  } else {
6039    if (value_location.IsConstant()) {
6040      int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
6041      __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
6042    } else if (!Primitive::IsFloatingPointType(type)) {
6043      Register src;
6044      if (type == Primitive::kPrimLong) {
6045        src = value_location.AsRegisterPairLow<Register>();
6046      } else {
6047        src = value_location.AsRegister<Register>();
6048      }
6049      if (kPoisonHeapReferences && needs_write_barrier) {
6050        // Note that in the case where `value` is a null reference,
6051        // we do not enter this block, as a null reference does not
6052        // need poisoning.
6053        DCHECK_EQ(type, Primitive::kPrimNot);
6054        __ PoisonHeapReference(TMP, src);
6055        __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
6056      } else {
6057        __ StoreToOffset(store_type, src, obj, offset, null_checker);
6058      }
6059    } else {
6060      FRegister src = value_location.AsFpuRegister<FRegister>();
6061      if (type == Primitive::kPrimFloat) {
6062        __ StoreSToOffset(src, obj, offset, null_checker);
6063      } else {
6064        __ StoreDToOffset(src, obj, offset, null_checker);
6065      }
6066    }
6067  }
6068
6069  if (needs_write_barrier) {
6070    Register src = value_location.AsRegister<Register>();
6071    codegen_->MarkGCCard(obj, src, value_can_be_null);
6072  }
6073
6074  if (is_volatile) {
6075    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
6076  }
6077}
6078
6079void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6080  HandleFieldGet(instruction, instruction->GetFieldInfo());
6081}
6082
6083void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6084  HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
6085}
6086
6087void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6088  HandleFieldSet(instruction, instruction->GetFieldInfo());
6089}
6090
6091void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6092  HandleFieldSet(instruction,
6093                 instruction->GetFieldInfo(),
6094                 instruction->GetDexPc(),
6095                 instruction->GetValueCanBeNull());
6096}
6097
6098void InstructionCodeGeneratorMIPS::GenerateReferenceLoadOneRegister(
6099    HInstruction* instruction,
6100    Location out,
6101    uint32_t offset,
6102    Location maybe_temp,
6103    ReadBarrierOption read_barrier_option) {
6104  Register out_reg = out.AsRegister<Register>();
6105  if (read_barrier_option == kWithReadBarrier) {
6106    CHECK(kEmitCompilerReadBarrier);
6107    DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6108    if (kUseBakerReadBarrier) {
6109      // Load with fast path based Baker's read barrier.
6110      // /* HeapReference<Object> */ out = *(out + offset)
6111      codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6112                                                      out,
6113                                                      out_reg,
6114                                                      offset,
6115                                                      maybe_temp,
6116                                                      /* needs_null_check */ false);
6117    } else {
6118      // Load with slow path based read barrier.
6119      // Save the value of `out` into `maybe_temp` before overwriting it
6120      // in the following move operation, as we will need it for the
6121      // read barrier below.
6122      __ Move(maybe_temp.AsRegister<Register>(), out_reg);
6123      // /* HeapReference<Object> */ out = *(out + offset)
6124      __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6125      codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6126    }
6127  } else {
6128    // Plain load with no read barrier.
6129    // /* HeapReference<Object> */ out = *(out + offset)
6130    __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6131    __ MaybeUnpoisonHeapReference(out_reg);
6132  }
6133}
6134
6135void InstructionCodeGeneratorMIPS::GenerateReferenceLoadTwoRegisters(
6136    HInstruction* instruction,
6137    Location out,
6138    Location obj,
6139    uint32_t offset,
6140    Location maybe_temp,
6141    ReadBarrierOption read_barrier_option) {
6142  Register out_reg = out.AsRegister<Register>();
6143  Register obj_reg = obj.AsRegister<Register>();
6144  if (read_barrier_option == kWithReadBarrier) {
6145    CHECK(kEmitCompilerReadBarrier);
6146    if (kUseBakerReadBarrier) {
6147      DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6148      // Load with fast path based Baker's read barrier.
6149      // /* HeapReference<Object> */ out = *(obj + offset)
6150      codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6151                                                      out,
6152                                                      obj_reg,
6153                                                      offset,
6154                                                      maybe_temp,
6155                                                      /* needs_null_check */ false);
6156    } else {
6157      // Load with slow path based read barrier.
6158      // /* HeapReference<Object> */ out = *(obj + offset)
6159      __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6160      codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6161    }
6162  } else {
6163    // Plain load with no read barrier.
6164    // /* HeapReference<Object> */ out = *(obj + offset)
6165    __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6166    __ MaybeUnpoisonHeapReference(out_reg);
6167  }
6168}
6169
6170void InstructionCodeGeneratorMIPS::GenerateGcRootFieldLoad(HInstruction* instruction,
6171                                                           Location root,
6172                                                           Register obj,
6173                                                           uint32_t offset,
6174                                                           ReadBarrierOption read_barrier_option) {
6175  Register root_reg = root.AsRegister<Register>();
6176  if (read_barrier_option == kWithReadBarrier) {
6177    DCHECK(kEmitCompilerReadBarrier);
6178    if (kUseBakerReadBarrier) {
6179      // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6180      // Baker's read barrier are used:
6181      //
6182      //   root = obj.field;
6183      //   temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6184      //   if (temp != null) {
6185      //     root = temp(root)
6186      //   }
6187
6188      // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6189      __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6190      static_assert(
6191          sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6192          "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6193          "have different sizes.");
6194      static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6195                    "art::mirror::CompressedReference<mirror::Object> and int32_t "
6196                    "have different sizes.");
6197
6198      // Slow path marking the GC root `root`.
6199      Location temp = Location::RegisterLocation(T9);
6200      SlowPathCodeMIPS* slow_path =
6201          new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathMIPS(
6202              instruction,
6203              root,
6204              /*entrypoint*/ temp);
6205      codegen_->AddSlowPath(slow_path);
6206
6207      // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6208      const int32_t entry_point_offset =
6209          CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(root.reg() - 1);
6210      // Loading the entrypoint does not require a load acquire since it is only changed when
6211      // threads are suspended or running a checkpoint.
6212      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
6213      // The entrypoint is null when the GC is not marking, this prevents one load compared to
6214      // checking GetIsGcMarking.
6215      __ Bnez(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
6216      __ Bind(slow_path->GetExitLabel());
6217    } else {
6218      // GC root loaded through a slow path for read barriers other
6219      // than Baker's.
6220      // /* GcRoot<mirror::Object>* */ root = obj + offset
6221      __ Addiu32(root_reg, obj, offset);
6222      // /* mirror::Object* */ root = root->Read()
6223      codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6224    }
6225  } else {
6226    // Plain GC root load with no read barrier.
6227    // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6228    __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6229    // Note that GC roots are not affected by heap poisoning, thus we
6230    // do not have to unpoison `root_reg` here.
6231  }
6232}
6233
6234void CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6235                                                              Location ref,
6236                                                              Register obj,
6237                                                              uint32_t offset,
6238                                                              Location temp,
6239                                                              bool needs_null_check) {
6240  DCHECK(kEmitCompilerReadBarrier);
6241  DCHECK(kUseBakerReadBarrier);
6242
6243  // /* HeapReference<Object> */ ref = *(obj + offset)
6244  Location no_index = Location::NoLocation();
6245  ScaleFactor no_scale_factor = TIMES_1;
6246  GenerateReferenceLoadWithBakerReadBarrier(instruction,
6247                                            ref,
6248                                            obj,
6249                                            offset,
6250                                            no_index,
6251                                            no_scale_factor,
6252                                            temp,
6253                                            needs_null_check);
6254}
6255
6256void CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6257                                                              Location ref,
6258                                                              Register obj,
6259                                                              uint32_t data_offset,
6260                                                              Location index,
6261                                                              Location temp,
6262                                                              bool needs_null_check) {
6263  DCHECK(kEmitCompilerReadBarrier);
6264  DCHECK(kUseBakerReadBarrier);
6265
6266  static_assert(
6267      sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6268      "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6269  // /* HeapReference<Object> */ ref =
6270  //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
6271  ScaleFactor scale_factor = TIMES_4;
6272  GenerateReferenceLoadWithBakerReadBarrier(instruction,
6273                                            ref,
6274                                            obj,
6275                                            data_offset,
6276                                            index,
6277                                            scale_factor,
6278                                            temp,
6279                                            needs_null_check);
6280}
6281
6282void CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6283                                                                  Location ref,
6284                                                                  Register obj,
6285                                                                  uint32_t offset,
6286                                                                  Location index,
6287                                                                  ScaleFactor scale_factor,
6288                                                                  Location temp,
6289                                                                  bool needs_null_check,
6290                                                                  bool always_update_field) {
6291  DCHECK(kEmitCompilerReadBarrier);
6292  DCHECK(kUseBakerReadBarrier);
6293
6294  // In slow path based read barriers, the read barrier call is
6295  // inserted after the original load. However, in fast path based
6296  // Baker's read barriers, we need to perform the load of
6297  // mirror::Object::monitor_ *before* the original reference load.
6298  // This load-load ordering is required by the read barrier.
6299  // The fast path/slow path (for Baker's algorithm) should look like:
6300  //
6301  //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6302  //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
6303  //   HeapReference<Object> ref = *src;  // Original reference load.
6304  //   bool is_gray = (rb_state == ReadBarrier::GrayState());
6305  //   if (is_gray) {
6306  //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
6307  //   }
6308  //
6309  // Note: the original implementation in ReadBarrier::Barrier is
6310  // slightly more complex as it performs additional checks that we do
6311  // not do here for performance reasons.
6312
6313  Register ref_reg = ref.AsRegister<Register>();
6314  Register temp_reg = temp.AsRegister<Register>();
6315  uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6316
6317  // /* int32_t */ monitor = obj->monitor_
6318  __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6319  if (needs_null_check) {
6320    MaybeRecordImplicitNullCheck(instruction);
6321  }
6322  // /* LockWord */ lock_word = LockWord(monitor)
6323  static_assert(sizeof(LockWord) == sizeof(int32_t),
6324                "art::LockWord and int32_t have different sizes.");
6325
6326  __ Sync(0);  // Barrier to prevent load-load reordering.
6327
6328  // The actual reference load.
6329  if (index.IsValid()) {
6330    // Load types involving an "index": ArrayGet,
6331    // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
6332    // intrinsics.
6333    // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
6334    if (index.IsConstant()) {
6335      size_t computed_offset =
6336          (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
6337      __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6338    } else {
6339      // Handle the special case of the
6340      // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
6341      // intrinsics, which use a register pair as index ("long
6342      // offset"), of which only the low part contains data.
6343      Register index_reg = index.IsRegisterPair()
6344          ? index.AsRegisterPairLow<Register>()
6345          : index.AsRegister<Register>();
6346      __ ShiftAndAdd(TMP, index_reg, obj, scale_factor, TMP);
6347      __ LoadFromOffset(kLoadWord, ref_reg, TMP, offset);
6348    }
6349  } else {
6350    // /* HeapReference<Object> */ ref = *(obj + offset)
6351    __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6352  }
6353
6354  // Object* ref = ref_addr->AsMirrorPtr()
6355  __ MaybeUnpoisonHeapReference(ref_reg);
6356
6357  // Slow path marking the object `ref` when it is gray.
6358  SlowPathCodeMIPS* slow_path;
6359  if (always_update_field) {
6360    // ReadBarrierMarkAndUpdateFieldSlowPathMIPS only supports address
6361    // of the form `obj + field_offset`, where `obj` is a register and
6362    // `field_offset` is a register pair (of which only the lower half
6363    // is used). Thus `offset` and `scale_factor` above are expected
6364    // to be null in this code path.
6365    DCHECK_EQ(offset, 0u);
6366    DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
6367    slow_path = new (GetGraph()->GetArena())
6368        ReadBarrierMarkAndUpdateFieldSlowPathMIPS(instruction,
6369                                                  ref,
6370                                                  obj,
6371                                                  /* field_offset */ index,
6372                                                  temp_reg);
6373  } else {
6374    slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathMIPS(instruction, ref);
6375  }
6376  AddSlowPath(slow_path);
6377
6378  // if (rb_state == ReadBarrier::GrayState())
6379  //   ref = ReadBarrier::Mark(ref);
6380  // Given the numeric representation, it's enough to check the low bit of the
6381  // rb_state. We do that by shifting the bit into the sign bit (31) and
6382  // performing a branch on less than zero.
6383  static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
6384  static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
6385  static_assert(LockWord::kReadBarrierStateSize == 1, "Expecting 1-bit read barrier state size");
6386  __ Sll(temp_reg, temp_reg, 31 - LockWord::kReadBarrierStateShift);
6387  __ Bltz(temp_reg, slow_path->GetEntryLabel());
6388  __ Bind(slow_path->GetExitLabel());
6389}
6390
6391void CodeGeneratorMIPS::GenerateReadBarrierSlow(HInstruction* instruction,
6392                                                Location out,
6393                                                Location ref,
6394                                                Location obj,
6395                                                uint32_t offset,
6396                                                Location index) {
6397  DCHECK(kEmitCompilerReadBarrier);
6398
6399  // Insert a slow path based read barrier *after* the reference load.
6400  //
6401  // If heap poisoning is enabled, the unpoisoning of the loaded
6402  // reference will be carried out by the runtime within the slow
6403  // path.
6404  //
6405  // Note that `ref` currently does not get unpoisoned (when heap
6406  // poisoning is enabled), which is alright as the `ref` argument is
6407  // not used by the artReadBarrierSlow entry point.
6408  //
6409  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6410  SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena())
6411      ReadBarrierForHeapReferenceSlowPathMIPS(instruction, out, ref, obj, offset, index);
6412  AddSlowPath(slow_path);
6413
6414  __ B(slow_path->GetEntryLabel());
6415  __ Bind(slow_path->GetExitLabel());
6416}
6417
6418void CodeGeneratorMIPS::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6419                                                     Location out,
6420                                                     Location ref,
6421                                                     Location obj,
6422                                                     uint32_t offset,
6423                                                     Location index) {
6424  if (kEmitCompilerReadBarrier) {
6425    // Baker's read barriers shall be handled by the fast path
6426    // (CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier).
6427    DCHECK(!kUseBakerReadBarrier);
6428    // If heap poisoning is enabled, unpoisoning will be taken care of
6429    // by the runtime within the slow path.
6430    GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
6431  } else if (kPoisonHeapReferences) {
6432    __ UnpoisonHeapReference(out.AsRegister<Register>());
6433  }
6434}
6435
6436void CodeGeneratorMIPS::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6437                                                       Location out,
6438                                                       Location root) {
6439  DCHECK(kEmitCompilerReadBarrier);
6440
6441  // Insert a slow path based read barrier *after* the GC root load.
6442  //
6443  // Note that GC roots are not affected by heap poisoning, so we do
6444  // not need to do anything special for this here.
6445  SlowPathCodeMIPS* slow_path =
6446      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathMIPS(instruction, out, root);
6447  AddSlowPath(slow_path);
6448
6449  __ B(slow_path->GetEntryLabel());
6450  __ Bind(slow_path->GetExitLabel());
6451}
6452
6453void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
6454  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
6455  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6456  switch (type_check_kind) {
6457    case TypeCheckKind::kExactCheck:
6458    case TypeCheckKind::kAbstractClassCheck:
6459    case TypeCheckKind::kClassHierarchyCheck:
6460    case TypeCheckKind::kArrayObjectCheck:
6461      call_kind =
6462          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
6463      break;
6464    case TypeCheckKind::kArrayCheck:
6465    case TypeCheckKind::kUnresolvedCheck:
6466    case TypeCheckKind::kInterfaceCheck:
6467      call_kind = LocationSummary::kCallOnSlowPath;
6468      break;
6469  }
6470
6471  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6472  locations->SetInAt(0, Location::RequiresRegister());
6473  locations->SetInAt(1, Location::RequiresRegister());
6474  // The output does overlap inputs.
6475  // Note that TypeCheckSlowPathMIPS uses this register too.
6476  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
6477  locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
6478}
6479
6480void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
6481  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6482  LocationSummary* locations = instruction->GetLocations();
6483  Location obj_loc = locations->InAt(0);
6484  Register obj = obj_loc.AsRegister<Register>();
6485  Register cls = locations->InAt(1).AsRegister<Register>();
6486  Location out_loc = locations->Out();
6487  Register out = out_loc.AsRegister<Register>();
6488  const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
6489  DCHECK_LE(num_temps, 1u);
6490  Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
6491  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6492  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6493  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6494  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6495  MipsLabel done;
6496  SlowPathCodeMIPS* slow_path = nullptr;
6497
6498  // Return 0 if `obj` is null.
6499  // Avoid this check if we know `obj` is not null.
6500  if (instruction->MustDoNullCheck()) {
6501    __ Move(out, ZERO);
6502    __ Beqz(obj, &done);
6503  }
6504
6505  switch (type_check_kind) {
6506    case TypeCheckKind::kExactCheck: {
6507      // /* HeapReference<Class> */ out = obj->klass_
6508      GenerateReferenceLoadTwoRegisters(instruction,
6509                                        out_loc,
6510                                        obj_loc,
6511                                        class_offset,
6512                                        maybe_temp_loc,
6513                                        kCompilerReadBarrierOption);
6514      // Classes must be equal for the instanceof to succeed.
6515      __ Xor(out, out, cls);
6516      __ Sltiu(out, out, 1);
6517      break;
6518    }
6519
6520    case TypeCheckKind::kAbstractClassCheck: {
6521      // /* HeapReference<Class> */ out = obj->klass_
6522      GenerateReferenceLoadTwoRegisters(instruction,
6523                                        out_loc,
6524                                        obj_loc,
6525                                        class_offset,
6526                                        maybe_temp_loc,
6527                                        kCompilerReadBarrierOption);
6528      // If the class is abstract, we eagerly fetch the super class of the
6529      // object to avoid doing a comparison we know will fail.
6530      MipsLabel loop;
6531      __ Bind(&loop);
6532      // /* HeapReference<Class> */ out = out->super_class_
6533      GenerateReferenceLoadOneRegister(instruction,
6534                                       out_loc,
6535                                       super_offset,
6536                                       maybe_temp_loc,
6537                                       kCompilerReadBarrierOption);
6538      // If `out` is null, we use it for the result, and jump to `done`.
6539      __ Beqz(out, &done);
6540      __ Bne(out, cls, &loop);
6541      __ LoadConst32(out, 1);
6542      break;
6543    }
6544
6545    case TypeCheckKind::kClassHierarchyCheck: {
6546      // /* HeapReference<Class> */ out = obj->klass_
6547      GenerateReferenceLoadTwoRegisters(instruction,
6548                                        out_loc,
6549                                        obj_loc,
6550                                        class_offset,
6551                                        maybe_temp_loc,
6552                                        kCompilerReadBarrierOption);
6553      // Walk over the class hierarchy to find a match.
6554      MipsLabel loop, success;
6555      __ Bind(&loop);
6556      __ Beq(out, cls, &success);
6557      // /* HeapReference<Class> */ out = out->super_class_
6558      GenerateReferenceLoadOneRegister(instruction,
6559                                       out_loc,
6560                                       super_offset,
6561                                       maybe_temp_loc,
6562                                       kCompilerReadBarrierOption);
6563      __ Bnez(out, &loop);
6564      // If `out` is null, we use it for the result, and jump to `done`.
6565      __ B(&done);
6566      __ Bind(&success);
6567      __ LoadConst32(out, 1);
6568      break;
6569    }
6570
6571    case TypeCheckKind::kArrayObjectCheck: {
6572      // /* HeapReference<Class> */ out = obj->klass_
6573      GenerateReferenceLoadTwoRegisters(instruction,
6574                                        out_loc,
6575                                        obj_loc,
6576                                        class_offset,
6577                                        maybe_temp_loc,
6578                                        kCompilerReadBarrierOption);
6579      // Do an exact check.
6580      MipsLabel success;
6581      __ Beq(out, cls, &success);
6582      // Otherwise, we need to check that the object's class is a non-primitive array.
6583      // /* HeapReference<Class> */ out = out->component_type_
6584      GenerateReferenceLoadOneRegister(instruction,
6585                                       out_loc,
6586                                       component_offset,
6587                                       maybe_temp_loc,
6588                                       kCompilerReadBarrierOption);
6589      // If `out` is null, we use it for the result, and jump to `done`.
6590      __ Beqz(out, &done);
6591      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
6592      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
6593      __ Sltiu(out, out, 1);
6594      __ B(&done);
6595      __ Bind(&success);
6596      __ LoadConst32(out, 1);
6597      break;
6598    }
6599
6600    case TypeCheckKind::kArrayCheck: {
6601      // No read barrier since the slow path will retry upon failure.
6602      // /* HeapReference<Class> */ out = obj->klass_
6603      GenerateReferenceLoadTwoRegisters(instruction,
6604                                        out_loc,
6605                                        obj_loc,
6606                                        class_offset,
6607                                        maybe_temp_loc,
6608                                        kWithoutReadBarrier);
6609      DCHECK(locations->OnlyCallsOnSlowPath());
6610      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction,
6611                                                                     /* is_fatal */ false);
6612      codegen_->AddSlowPath(slow_path);
6613      __ Bne(out, cls, slow_path->GetEntryLabel());
6614      __ LoadConst32(out, 1);
6615      break;
6616    }
6617
6618    case TypeCheckKind::kUnresolvedCheck:
6619    case TypeCheckKind::kInterfaceCheck: {
6620      // Note that we indeed only call on slow path, but we always go
6621      // into the slow path for the unresolved and interface check
6622      // cases.
6623      //
6624      // We cannot directly call the InstanceofNonTrivial runtime
6625      // entry point without resorting to a type checking slow path
6626      // here (i.e. by calling InvokeRuntime directly), as it would
6627      // require to assign fixed registers for the inputs of this
6628      // HInstanceOf instruction (following the runtime calling
6629      // convention), which might be cluttered by the potential first
6630      // read barrier emission at the beginning of this method.
6631      //
6632      // TODO: Introduce a new runtime entry point taking the object
6633      // to test (instead of its class) as argument, and let it deal
6634      // with the read barrier issues. This will let us refactor this
6635      // case of the `switch` code as it was previously (with a direct
6636      // call to the runtime not using a type checking slow path).
6637      // This should also be beneficial for the other cases above.
6638      DCHECK(locations->OnlyCallsOnSlowPath());
6639      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction,
6640                                                                     /* is_fatal */ false);
6641      codegen_->AddSlowPath(slow_path);
6642      __ B(slow_path->GetEntryLabel());
6643      break;
6644    }
6645  }
6646
6647  __ Bind(&done);
6648
6649  if (slow_path != nullptr) {
6650    __ Bind(slow_path->GetExitLabel());
6651  }
6652}
6653
6654void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
6655  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
6656  locations->SetOut(Location::ConstantLocation(constant));
6657}
6658
6659void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
6660  // Will be generated at use site.
6661}
6662
6663void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
6664  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
6665  locations->SetOut(Location::ConstantLocation(constant));
6666}
6667
6668void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
6669  // Will be generated at use site.
6670}
6671
6672void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
6673  InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
6674  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
6675}
6676
6677void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
6678  HandleInvoke(invoke);
6679  // The register T7 is required to be used for the hidden argument in
6680  // art_quick_imt_conflict_trampoline, so add the hidden argument.
6681  invoke->GetLocations()->AddTemp(Location::RegisterLocation(T7));
6682}
6683
6684void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
6685  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
6686  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
6687  Location receiver = invoke->GetLocations()->InAt(0);
6688  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6689  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
6690
6691  // Set the hidden argument.
6692  __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
6693                 invoke->GetDexMethodIndex());
6694
6695  // temp = object->GetClass();
6696  if (receiver.IsStackSlot()) {
6697    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
6698    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
6699  } else {
6700    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
6701  }
6702  codegen_->MaybeRecordImplicitNullCheck(invoke);
6703  // Instead of simply (possibly) unpoisoning `temp` here, we should
6704  // emit a read barrier for the previous class reference load.
6705  // However this is not required in practice, as this is an
6706  // intermediate/temporary reference and because the current
6707  // concurrent copying collector keeps the from-space memory
6708  // intact/accessible until the end of the marking phase (the
6709  // concurrent copying collector may not in the future).
6710  __ MaybeUnpoisonHeapReference(temp);
6711  __ LoadFromOffset(kLoadWord, temp, temp,
6712      mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
6713  uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
6714      invoke->GetImtIndex(), kMipsPointerSize));
6715  // temp = temp->GetImtEntryAt(method_offset);
6716  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6717  // T9 = temp->GetEntryPoint();
6718  __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
6719  // T9();
6720  __ Jalr(T9);
6721  __ NopIfNoReordering();
6722  DCHECK(!codegen_->IsLeafMethod());
6723  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
6724}
6725
6726void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
6727  IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
6728  if (intrinsic.TryDispatch(invoke)) {
6729    return;
6730  }
6731
6732  HandleInvoke(invoke);
6733}
6734
6735void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
6736  // Explicit clinit checks triggered by static invokes must have been pruned by
6737  // art::PrepareForRegisterAllocation.
6738  DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
6739
6740  bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
6741  bool has_extra_input = invoke->HasPcRelativeDexCache() && !is_r6;
6742
6743  IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
6744  if (intrinsic.TryDispatch(invoke)) {
6745    if (invoke->GetLocations()->CanCall() && has_extra_input) {
6746      invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
6747    }
6748    return;
6749  }
6750
6751  HandleInvoke(invoke);
6752
6753  // Add the extra input register if either the dex cache array base register
6754  // or the PC-relative base register for accessing literals is needed.
6755  if (has_extra_input) {
6756    invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
6757  }
6758}
6759
6760void LocationsBuilderMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
6761  HandleInvoke(invoke);
6762}
6763
6764void InstructionCodeGeneratorMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
6765  codegen_->GenerateInvokePolymorphicCall(invoke);
6766}
6767
6768static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
6769  if (invoke->GetLocations()->Intrinsified()) {
6770    IntrinsicCodeGeneratorMIPS intrinsic(codegen);
6771    intrinsic.Dispatch(invoke);
6772    return true;
6773  }
6774  return false;
6775}
6776
6777HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
6778    HLoadString::LoadKind desired_string_load_kind) {
6779  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
6780  // is incompatible with it.
6781  // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
6782  // with irreducible loops.
6783  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
6784  bool is_r6 = GetInstructionSetFeatures().IsR6();
6785  bool fallback_load = has_irreducible_loops && !is_r6;
6786  switch (desired_string_load_kind) {
6787    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
6788      DCHECK(!GetCompilerOptions().GetCompilePic());
6789      break;
6790    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
6791      DCHECK(GetCompilerOptions().GetCompilePic());
6792      break;
6793    case HLoadString::LoadKind::kBootImageAddress:
6794      break;
6795    case HLoadString::LoadKind::kBssEntry:
6796      DCHECK(!Runtime::Current()->UseJitCompilation());
6797      break;
6798    case HLoadString::LoadKind::kJitTableAddress:
6799      DCHECK(Runtime::Current()->UseJitCompilation());
6800      fallback_load = false;
6801      break;
6802    case HLoadString::LoadKind::kDexCacheViaMethod:
6803      fallback_load = false;
6804      break;
6805  }
6806  if (fallback_load) {
6807    desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
6808  }
6809  return desired_string_load_kind;
6810}
6811
6812HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
6813    HLoadClass::LoadKind desired_class_load_kind) {
6814  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
6815  // is incompatible with it.
6816  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
6817  bool is_r6 = GetInstructionSetFeatures().IsR6();
6818  bool fallback_load = has_irreducible_loops && !is_r6;
6819  switch (desired_class_load_kind) {
6820    case HLoadClass::LoadKind::kInvalid:
6821      LOG(FATAL) << "UNREACHABLE";
6822      UNREACHABLE();
6823    case HLoadClass::LoadKind::kReferrersClass:
6824      fallback_load = false;
6825      break;
6826    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
6827      DCHECK(!GetCompilerOptions().GetCompilePic());
6828      break;
6829    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
6830      DCHECK(GetCompilerOptions().GetCompilePic());
6831      break;
6832    case HLoadClass::LoadKind::kBootImageAddress:
6833      break;
6834    case HLoadClass::LoadKind::kBssEntry:
6835      DCHECK(!Runtime::Current()->UseJitCompilation());
6836      break;
6837    case HLoadClass::LoadKind::kJitTableAddress:
6838      DCHECK(Runtime::Current()->UseJitCompilation());
6839      fallback_load = false;
6840      break;
6841    case HLoadClass::LoadKind::kDexCacheViaMethod:
6842      fallback_load = false;
6843      break;
6844  }
6845  if (fallback_load) {
6846    desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
6847  }
6848  return desired_class_load_kind;
6849}
6850
6851Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6852                                                                  Register temp) {
6853  CHECK(!GetInstructionSetFeatures().IsR6());
6854  CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6855  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6856  if (!invoke->GetLocations()->Intrinsified()) {
6857    return location.AsRegister<Register>();
6858  }
6859  // For intrinsics we allow any location, so it may be on the stack.
6860  if (!location.IsRegister()) {
6861    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6862    return temp;
6863  }
6864  // For register locations, check if the register was saved. If so, get it from the stack.
6865  // Note: There is a chance that the register was saved but not overwritten, so we could
6866  // save one load. However, since this is just an intrinsic slow path we prefer this
6867  // simple and more robust approach rather that trying to determine if that's the case.
6868  SlowPathCode* slow_path = GetCurrentSlowPath();
6869  DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
6870  if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6871    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6872    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6873    return temp;
6874  }
6875  return location.AsRegister<Register>();
6876}
6877
6878HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
6879      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6880      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
6881  HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6882  // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
6883  // is incompatible with it.
6884  bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
6885  bool is_r6 = GetInstructionSetFeatures().IsR6();
6886  bool fallback_load = has_irreducible_loops && !is_r6;
6887  switch (dispatch_info.method_load_kind) {
6888    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
6889      break;
6890    default:
6891      fallback_load = false;
6892      break;
6893  }
6894  if (fallback_load) {
6895    dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6896    dispatch_info.method_load_data = 0;
6897  }
6898  return dispatch_info;
6899}
6900
6901void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
6902  // All registers are assumed to be correctly set up per the calling convention.
6903  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
6904  HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
6905  HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
6906  bool is_r6 = GetInstructionSetFeatures().IsR6();
6907  Register base_reg = (invoke->HasPcRelativeDexCache() && !is_r6)
6908      ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
6909      : ZERO;
6910
6911  switch (method_load_kind) {
6912    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
6913      // temp = thread->string_init_entrypoint
6914      uint32_t offset =
6915          GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
6916      __ LoadFromOffset(kLoadWord,
6917                        temp.AsRegister<Register>(),
6918                        TR,
6919                        offset);
6920      break;
6921    }
6922    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
6923      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6924      break;
6925    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6926      __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6927      break;
6928    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
6929      if (is_r6) {
6930        uint32_t offset = invoke->GetDexCacheArrayOffset();
6931        CodeGeneratorMIPS::PcRelativePatchInfo* info =
6932            NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
6933        bool reordering = __ SetReorder(false);
6934        EmitPcRelativeAddressPlaceholderHigh(info, TMP, ZERO);
6935        __ Lw(temp.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
6936        __ SetReorder(reordering);
6937      } else {
6938        HMipsDexCacheArraysBase* base =
6939            invoke->InputAt(invoke->GetSpecialInputIndex())->AsMipsDexCacheArraysBase();
6940        int32_t offset =
6941            invoke->GetDexCacheArrayOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset;
6942        __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6943      }
6944      break;
6945    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
6946      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6947      Register reg = temp.AsRegister<Register>();
6948      Register method_reg;
6949      if (current_method.IsRegister()) {
6950        method_reg = current_method.AsRegister<Register>();
6951      } else {
6952        // TODO: use the appropriate DCHECK() here if possible.
6953        // DCHECK(invoke->GetLocations()->Intrinsified());
6954        DCHECK(!current_method.IsValid());
6955        method_reg = reg;
6956        __ Lw(reg, SP, kCurrentMethodStackOffset);
6957      }
6958
6959      // temp = temp->dex_cache_resolved_methods_;
6960      __ LoadFromOffset(kLoadWord,
6961                        reg,
6962                        method_reg,
6963                        ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value());
6964      // temp = temp[index_in_cache];
6965      // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6966      uint32_t index_in_cache = invoke->GetDexMethodIndex();
6967      __ LoadFromOffset(kLoadWord,
6968                        reg,
6969                        reg,
6970                        CodeGenerator::GetCachePointerOffset(index_in_cache));
6971      break;
6972    }
6973  }
6974
6975  switch (code_ptr_location) {
6976    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6977      __ Bal(&frame_entry_label_);
6978      break;
6979    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6980      // T9 = callee_method->entry_point_from_quick_compiled_code_;
6981      __ LoadFromOffset(kLoadWord,
6982                        T9,
6983                        callee_method.AsRegister<Register>(),
6984                        ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6985                            kMipsPointerSize).Int32Value());
6986      // T9()
6987      __ Jalr(T9);
6988      __ NopIfNoReordering();
6989      break;
6990  }
6991  DCHECK(!IsLeafMethod());
6992}
6993
6994void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
6995  // Explicit clinit checks triggered by static invokes must have been pruned by
6996  // art::PrepareForRegisterAllocation.
6997  DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
6998
6999  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
7000    return;
7001  }
7002
7003  LocationSummary* locations = invoke->GetLocations();
7004  codegen_->GenerateStaticOrDirectCall(invoke,
7005                                       locations->HasTemps()
7006                                           ? locations->GetTemp(0)
7007                                           : Location::NoLocation());
7008  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
7009}
7010
7011void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
7012  // Use the calling convention instead of the location of the receiver, as
7013  // intrinsics may have put the receiver in a different register. In the intrinsics
7014  // slow path, the arguments have been moved to the right place, so here we are
7015  // guaranteed that the receiver is the first register of the calling convention.
7016  InvokeDexCallingConvention calling_convention;
7017  Register receiver = calling_convention.GetRegisterAt(0);
7018
7019  Register temp = temp_location.AsRegister<Register>();
7020  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7021      invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
7022  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7023  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
7024
7025  // temp = object->GetClass();
7026  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
7027  MaybeRecordImplicitNullCheck(invoke);
7028  // Instead of simply (possibly) unpoisoning `temp` here, we should
7029  // emit a read barrier for the previous class reference load.
7030  // However this is not required in practice, as this is an
7031  // intermediate/temporary reference and because the current
7032  // concurrent copying collector keeps the from-space memory
7033  // intact/accessible until the end of the marking phase (the
7034  // concurrent copying collector may not in the future).
7035  __ MaybeUnpoisonHeapReference(temp);
7036  // temp = temp->GetMethodAt(method_offset);
7037  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7038  // T9 = temp->GetEntryPoint();
7039  __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
7040  // T9();
7041  __ Jalr(T9);
7042  __ NopIfNoReordering();
7043}
7044
7045void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
7046  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
7047    return;
7048  }
7049
7050  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
7051  DCHECK(!codegen_->IsLeafMethod());
7052  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
7053}
7054
7055void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
7056  HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7057  if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
7058    InvokeRuntimeCallingConvention calling_convention;
7059    CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
7060        cls,
7061        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
7062        calling_convention.GetReturnLocation(Primitive::kPrimNot));
7063    return;
7064  }
7065  DCHECK(!cls->NeedsAccessCheck());
7066
7067  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
7068  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
7069      ? LocationSummary::kCallOnSlowPath
7070      : LocationSummary::kNoCall;
7071  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
7072  switch (load_kind) {
7073    // We need an extra register for PC-relative literals on R2.
7074    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
7075    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
7076    case HLoadClass::LoadKind::kBootImageAddress:
7077    case HLoadClass::LoadKind::kBssEntry:
7078      if (codegen_->GetInstructionSetFeatures().IsR6()) {
7079        break;
7080      }
7081      FALLTHROUGH_INTENDED;
7082    case HLoadClass::LoadKind::kReferrersClass:
7083      locations->SetInAt(0, Location::RequiresRegister());
7084      break;
7085    default:
7086      break;
7087  }
7088  locations->SetOut(Location::RequiresRegister());
7089}
7090
7091// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7092// move.
7093void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
7094  HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7095  if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
7096    codegen_->GenerateLoadClassRuntimeCall(cls);
7097    return;
7098  }
7099  DCHECK(!cls->NeedsAccessCheck());
7100
7101  LocationSummary* locations = cls->GetLocations();
7102  Location out_loc = locations->Out();
7103  Register out = out_loc.AsRegister<Register>();
7104  Register base_or_current_method_reg;
7105  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
7106  switch (load_kind) {
7107    // We need an extra register for PC-relative literals on R2.
7108    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
7109    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
7110    case HLoadClass::LoadKind::kBootImageAddress:
7111    case HLoadClass::LoadKind::kBssEntry:
7112      base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
7113      break;
7114    case HLoadClass::LoadKind::kReferrersClass:
7115    case HLoadClass::LoadKind::kDexCacheViaMethod:
7116      base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
7117      break;
7118    default:
7119      base_or_current_method_reg = ZERO;
7120      break;
7121  }
7122
7123  const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
7124      ? kWithoutReadBarrier
7125      : kCompilerReadBarrierOption;
7126  bool generate_null_check = false;
7127  switch (load_kind) {
7128    case HLoadClass::LoadKind::kReferrersClass: {
7129      DCHECK(!cls->CanCallRuntime());
7130      DCHECK(!cls->MustGenerateClinitCheck());
7131      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7132      GenerateGcRootFieldLoad(cls,
7133                              out_loc,
7134                              base_or_current_method_reg,
7135                              ArtMethod::DeclaringClassOffset().Int32Value(),
7136                              read_barrier_option);
7137      break;
7138    }
7139    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
7140      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
7141      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7142      __ LoadLiteral(out,
7143                     base_or_current_method_reg,
7144                     codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
7145                                                               cls->GetTypeIndex()));
7146      break;
7147    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
7148      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
7149      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7150      CodeGeneratorMIPS::PcRelativePatchInfo* info =
7151          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
7152      bool reordering = __ SetReorder(false);
7153      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
7154      __ Addiu(out, out, /* placeholder */ 0x5678);
7155      __ SetReorder(reordering);
7156      break;
7157    }
7158    case HLoadClass::LoadKind::kBootImageAddress: {
7159      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7160      uint32_t address = dchecked_integral_cast<uint32_t>(
7161          reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
7162      DCHECK_NE(address, 0u);
7163      __ LoadLiteral(out,
7164                     base_or_current_method_reg,
7165                     codegen_->DeduplicateBootImageAddressLiteral(address));
7166      break;
7167    }
7168    case HLoadClass::LoadKind::kBssEntry: {
7169      CodeGeneratorMIPS::PcRelativePatchInfo* info =
7170          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
7171      bool reordering = __ SetReorder(false);
7172      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
7173      GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
7174      __ SetReorder(reordering);
7175      generate_null_check = true;
7176      break;
7177    }
7178    case HLoadClass::LoadKind::kJitTableAddress: {
7179      CodeGeneratorMIPS::JitPatchInfo* info = codegen_->NewJitRootClassPatch(cls->GetDexFile(),
7180                                                                             cls->GetTypeIndex(),
7181                                                                             cls->GetClass());
7182      bool reordering = __ SetReorder(false);
7183      __ Bind(&info->high_label);
7184      __ Lui(out, /* placeholder */ 0x1234);
7185      GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
7186      __ SetReorder(reordering);
7187      break;
7188    }
7189    case HLoadClass::LoadKind::kDexCacheViaMethod:
7190    case HLoadClass::LoadKind::kInvalid:
7191      LOG(FATAL) << "UNREACHABLE";
7192      UNREACHABLE();
7193  }
7194
7195  if (generate_null_check || cls->MustGenerateClinitCheck()) {
7196    DCHECK(cls->CanCallRuntime());
7197    SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
7198        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
7199    codegen_->AddSlowPath(slow_path);
7200    if (generate_null_check) {
7201      __ Beqz(out, slow_path->GetEntryLabel());
7202    }
7203    if (cls->MustGenerateClinitCheck()) {
7204      GenerateClassInitializationCheck(slow_path, out);
7205    } else {
7206      __ Bind(slow_path->GetExitLabel());
7207    }
7208  }
7209}
7210
7211static int32_t GetExceptionTlsOffset() {
7212  return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
7213}
7214
7215void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
7216  LocationSummary* locations =
7217      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
7218  locations->SetOut(Location::RequiresRegister());
7219}
7220
7221void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
7222  Register out = load->GetLocations()->Out().AsRegister<Register>();
7223  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
7224}
7225
7226void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
7227  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
7228}
7229
7230void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
7231  __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
7232}
7233
7234void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
7235  LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
7236  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
7237  HLoadString::LoadKind load_kind = load->GetLoadKind();
7238  switch (load_kind) {
7239    // We need an extra register for PC-relative literals on R2.
7240    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
7241    case HLoadString::LoadKind::kBootImageAddress:
7242    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
7243    case HLoadString::LoadKind::kBssEntry:
7244      if (codegen_->GetInstructionSetFeatures().IsR6()) {
7245        break;
7246      }
7247      FALLTHROUGH_INTENDED;
7248    // We need an extra register for PC-relative dex cache accesses.
7249    case HLoadString::LoadKind::kDexCacheViaMethod:
7250      locations->SetInAt(0, Location::RequiresRegister());
7251      break;
7252    default:
7253      break;
7254  }
7255  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
7256    InvokeRuntimeCallingConvention calling_convention;
7257    locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
7258  } else {
7259    locations->SetOut(Location::RequiresRegister());
7260  }
7261}
7262
7263// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7264// move.
7265void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
7266  HLoadString::LoadKind load_kind = load->GetLoadKind();
7267  LocationSummary* locations = load->GetLocations();
7268  Location out_loc = locations->Out();
7269  Register out = out_loc.AsRegister<Register>();
7270  Register base_or_current_method_reg;
7271  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
7272  switch (load_kind) {
7273    // We need an extra register for PC-relative literals on R2.
7274    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
7275    case HLoadString::LoadKind::kBootImageAddress:
7276    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
7277    case HLoadString::LoadKind::kBssEntry:
7278      base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
7279      break;
7280    default:
7281      base_or_current_method_reg = ZERO;
7282      break;
7283  }
7284
7285  switch (load_kind) {
7286    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
7287      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
7288      __ LoadLiteral(out,
7289                     base_or_current_method_reg,
7290                     codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
7291                                                                 load->GetStringIndex()));
7292      return;  // No dex cache slow path.
7293    case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
7294      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
7295      CodeGeneratorMIPS::PcRelativePatchInfo* info =
7296          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
7297      bool reordering = __ SetReorder(false);
7298      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
7299      __ Addiu(out, out, /* placeholder */ 0x5678);
7300      __ SetReorder(reordering);
7301      return;  // No dex cache slow path.
7302    }
7303    case HLoadString::LoadKind::kBootImageAddress: {
7304      uint32_t address = dchecked_integral_cast<uint32_t>(
7305          reinterpret_cast<uintptr_t>(load->GetString().Get()));
7306      DCHECK_NE(address, 0u);
7307      __ LoadLiteral(out,
7308                     base_or_current_method_reg,
7309                     codegen_->DeduplicateBootImageAddressLiteral(address));
7310      return;  // No dex cache slow path.
7311    }
7312    case HLoadString::LoadKind::kBssEntry: {
7313      DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7314      CodeGeneratorMIPS::PcRelativePatchInfo* info =
7315          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
7316      bool reordering = __ SetReorder(false);
7317      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
7318      GenerateGcRootFieldLoad(load,
7319                              out_loc,
7320                              out,
7321                              /* placeholder */ 0x5678,
7322                              kCompilerReadBarrierOption);
7323      __ SetReorder(reordering);
7324      SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
7325      codegen_->AddSlowPath(slow_path);
7326      __ Beqz(out, slow_path->GetEntryLabel());
7327      __ Bind(slow_path->GetExitLabel());
7328      return;
7329    }
7330    case HLoadString::LoadKind::kJitTableAddress: {
7331      CodeGeneratorMIPS::JitPatchInfo* info =
7332          codegen_->NewJitRootStringPatch(load->GetDexFile(),
7333                                          load->GetStringIndex(),
7334                                          load->GetString());
7335      bool reordering = __ SetReorder(false);
7336      __ Bind(&info->high_label);
7337      __ Lui(out, /* placeholder */ 0x1234);
7338      GenerateGcRootFieldLoad(load,
7339                              out_loc,
7340                              out,
7341                              /* placeholder */ 0x5678,
7342                              kCompilerReadBarrierOption);
7343      __ SetReorder(reordering);
7344      return;
7345    }
7346    default:
7347      break;
7348  }
7349
7350  // TODO: Re-add the compiler code to do string dex cache lookup again.
7351  DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
7352  InvokeRuntimeCallingConvention calling_convention;
7353  __ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
7354  codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7355  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
7356}
7357
7358void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
7359  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
7360  locations->SetOut(Location::ConstantLocation(constant));
7361}
7362
7363void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
7364  // Will be generated at use site.
7365}
7366
7367void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
7368  LocationSummary* locations =
7369      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
7370  InvokeRuntimeCallingConvention calling_convention;
7371  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7372}
7373
7374void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
7375  if (instruction->IsEnter()) {
7376    codegen_->InvokeRuntime(kQuickLockObject, instruction, instruction->GetDexPc());
7377    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7378  } else {
7379    codegen_->InvokeRuntime(kQuickUnlockObject, instruction, instruction->GetDexPc());
7380  }
7381  CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7382}
7383
7384void LocationsBuilderMIPS::VisitMul(HMul* mul) {
7385  LocationSummary* locations =
7386      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
7387  switch (mul->GetResultType()) {
7388    case Primitive::kPrimInt:
7389    case Primitive::kPrimLong:
7390      locations->SetInAt(0, Location::RequiresRegister());
7391      locations->SetInAt(1, Location::RequiresRegister());
7392      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7393      break;
7394
7395    case Primitive::kPrimFloat:
7396    case Primitive::kPrimDouble:
7397      locations->SetInAt(0, Location::RequiresFpuRegister());
7398      locations->SetInAt(1, Location::RequiresFpuRegister());
7399      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
7400      break;
7401
7402    default:
7403      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
7404  }
7405}
7406
7407void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
7408  Primitive::Type type = instruction->GetType();
7409  LocationSummary* locations = instruction->GetLocations();
7410  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
7411
7412  switch (type) {
7413    case Primitive::kPrimInt: {
7414      Register dst = locations->Out().AsRegister<Register>();
7415      Register lhs = locations->InAt(0).AsRegister<Register>();
7416      Register rhs = locations->InAt(1).AsRegister<Register>();
7417
7418      if (isR6) {
7419        __ MulR6(dst, lhs, rhs);
7420      } else {
7421        __ MulR2(dst, lhs, rhs);
7422      }
7423      break;
7424    }
7425    case Primitive::kPrimLong: {
7426      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
7427      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
7428      Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
7429      Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
7430      Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
7431      Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
7432
7433      // Extra checks to protect caused by the existance of A1_A2.
7434      // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
7435      // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
7436      DCHECK_NE(dst_high, lhs_low);
7437      DCHECK_NE(dst_high, rhs_low);
7438
7439      // A_B * C_D
7440      // dst_hi:  [ low(A*D) + low(B*C) + hi(B*D) ]
7441      // dst_lo:  [ low(B*D) ]
7442      // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
7443
7444      if (isR6) {
7445        __ MulR6(TMP, lhs_high, rhs_low);
7446        __ MulR6(dst_high, lhs_low, rhs_high);
7447        __ Addu(dst_high, dst_high, TMP);
7448        __ MuhuR6(TMP, lhs_low, rhs_low);
7449        __ Addu(dst_high, dst_high, TMP);
7450        __ MulR6(dst_low, lhs_low, rhs_low);
7451      } else {
7452        __ MulR2(TMP, lhs_high, rhs_low);
7453        __ MulR2(dst_high, lhs_low, rhs_high);
7454        __ Addu(dst_high, dst_high, TMP);
7455        __ MultuR2(lhs_low, rhs_low);
7456        __ Mfhi(TMP);
7457        __ Addu(dst_high, dst_high, TMP);
7458        __ Mflo(dst_low);
7459      }
7460      break;
7461    }
7462    case Primitive::kPrimFloat:
7463    case Primitive::kPrimDouble: {
7464      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
7465      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
7466      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
7467      if (type == Primitive::kPrimFloat) {
7468        __ MulS(dst, lhs, rhs);
7469      } else {
7470        __ MulD(dst, lhs, rhs);
7471      }
7472      break;
7473    }
7474    default:
7475      LOG(FATAL) << "Unexpected mul type " << type;
7476  }
7477}
7478
7479void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
7480  LocationSummary* locations =
7481      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
7482  switch (neg->GetResultType()) {
7483    case Primitive::kPrimInt:
7484    case Primitive::kPrimLong:
7485      locations->SetInAt(0, Location::RequiresRegister());
7486      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7487      break;
7488
7489    case Primitive::kPrimFloat:
7490    case Primitive::kPrimDouble:
7491      locations->SetInAt(0, Location::RequiresFpuRegister());
7492      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
7493      break;
7494
7495    default:
7496      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
7497  }
7498}
7499
7500void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
7501  Primitive::Type type = instruction->GetType();
7502  LocationSummary* locations = instruction->GetLocations();
7503
7504  switch (type) {
7505    case Primitive::kPrimInt: {
7506      Register dst = locations->Out().AsRegister<Register>();
7507      Register src = locations->InAt(0).AsRegister<Register>();
7508      __ Subu(dst, ZERO, src);
7509      break;
7510    }
7511    case Primitive::kPrimLong: {
7512      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
7513      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
7514      Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
7515      Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
7516      __ Subu(dst_low, ZERO, src_low);
7517      __ Sltu(TMP, ZERO, dst_low);
7518      __ Subu(dst_high, ZERO, src_high);
7519      __ Subu(dst_high, dst_high, TMP);
7520      break;
7521    }
7522    case Primitive::kPrimFloat:
7523    case Primitive::kPrimDouble: {
7524      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
7525      FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
7526      if (type == Primitive::kPrimFloat) {
7527        __ NegS(dst, src);
7528      } else {
7529        __ NegD(dst, src);
7530      }
7531      break;
7532    }
7533    default:
7534      LOG(FATAL) << "Unexpected neg type " << type;
7535  }
7536}
7537
7538void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
7539  LocationSummary* locations =
7540      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
7541  InvokeRuntimeCallingConvention calling_convention;
7542  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
7543  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7544  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
7545}
7546
7547void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
7548  // Note: if heap poisoning is enabled, the entry point takes care
7549  // of poisoning the reference.
7550  codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
7551  CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
7552}
7553
7554void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
7555  LocationSummary* locations =
7556      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
7557  InvokeRuntimeCallingConvention calling_convention;
7558  if (instruction->IsStringAlloc()) {
7559    locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
7560  } else {
7561    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7562  }
7563  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
7564}
7565
7566void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
7567  // Note: if heap poisoning is enabled, the entry point takes care
7568  // of poisoning the reference.
7569  if (instruction->IsStringAlloc()) {
7570    // String is allocated through StringFactory. Call NewEmptyString entry point.
7571    Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
7572    MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
7573    __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
7574    __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
7575    __ Jalr(T9);
7576    __ NopIfNoReordering();
7577    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
7578  } else {
7579    codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
7580    CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
7581  }
7582}
7583
7584void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
7585  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
7586  locations->SetInAt(0, Location::RequiresRegister());
7587  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7588}
7589
7590void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
7591  Primitive::Type type = instruction->GetType();
7592  LocationSummary* locations = instruction->GetLocations();
7593
7594  switch (type) {
7595    case Primitive::kPrimInt: {
7596      Register dst = locations->Out().AsRegister<Register>();
7597      Register src = locations->InAt(0).AsRegister<Register>();
7598      __ Nor(dst, src, ZERO);
7599      break;
7600    }
7601
7602    case Primitive::kPrimLong: {
7603      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
7604      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
7605      Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
7606      Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
7607      __ Nor(dst_high, src_high, ZERO);
7608      __ Nor(dst_low, src_low, ZERO);
7609      break;
7610    }
7611
7612    default:
7613      LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
7614  }
7615}
7616
7617void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
7618  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
7619  locations->SetInAt(0, Location::RequiresRegister());
7620  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7621}
7622
7623void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
7624  LocationSummary* locations = instruction->GetLocations();
7625  __ Xori(locations->Out().AsRegister<Register>(),
7626          locations->InAt(0).AsRegister<Register>(),
7627          1);
7628}
7629
7630void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
7631  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
7632  locations->SetInAt(0, Location::RequiresRegister());
7633}
7634
7635void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
7636  if (CanMoveNullCheckToUser(instruction)) {
7637    return;
7638  }
7639  Location obj = instruction->GetLocations()->InAt(0);
7640
7641  __ Lw(ZERO, obj.AsRegister<Register>(), 0);
7642  RecordPcInfo(instruction, instruction->GetDexPc());
7643}
7644
7645void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
7646  SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS(instruction);
7647  AddSlowPath(slow_path);
7648
7649  Location obj = instruction->GetLocations()->InAt(0);
7650
7651  __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
7652}
7653
7654void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
7655  codegen_->GenerateNullCheck(instruction);
7656}
7657
7658void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
7659  HandleBinaryOp(instruction);
7660}
7661
7662void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
7663  HandleBinaryOp(instruction);
7664}
7665
7666void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
7667  LOG(FATAL) << "Unreachable";
7668}
7669
7670void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
7671  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
7672}
7673
7674void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
7675  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
7676  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
7677  if (location.IsStackSlot()) {
7678    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
7679  } else if (location.IsDoubleStackSlot()) {
7680    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
7681  }
7682  locations->SetOut(location);
7683}
7684
7685void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
7686                                                         ATTRIBUTE_UNUSED) {
7687  // Nothing to do, the parameter is already at its location.
7688}
7689
7690void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
7691  LocationSummary* locations =
7692      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7693  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
7694}
7695
7696void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
7697                                                        ATTRIBUTE_UNUSED) {
7698  // Nothing to do, the method is already at its location.
7699}
7700
7701void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
7702  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
7703  for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
7704    locations->SetInAt(i, Location::Any());
7705  }
7706  locations->SetOut(Location::Any());
7707}
7708
7709void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
7710  LOG(FATAL) << "Unreachable";
7711}
7712
7713void LocationsBuilderMIPS::VisitRem(HRem* rem) {
7714  Primitive::Type type = rem->GetResultType();
7715  LocationSummary::CallKind call_kind =
7716      (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCallOnMainOnly;
7717  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
7718
7719  switch (type) {
7720    case Primitive::kPrimInt:
7721      locations->SetInAt(0, Location::RequiresRegister());
7722      locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
7723      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7724      break;
7725
7726    case Primitive::kPrimLong: {
7727      InvokeRuntimeCallingConvention calling_convention;
7728      locations->SetInAt(0, Location::RegisterPairLocation(
7729          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
7730      locations->SetInAt(1, Location::RegisterPairLocation(
7731          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
7732      locations->SetOut(calling_convention.GetReturnLocation(type));
7733      break;
7734    }
7735
7736    case Primitive::kPrimFloat:
7737    case Primitive::kPrimDouble: {
7738      InvokeRuntimeCallingConvention calling_convention;
7739      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
7740      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
7741      locations->SetOut(calling_convention.GetReturnLocation(type));
7742      break;
7743    }
7744
7745    default:
7746      LOG(FATAL) << "Unexpected rem type " << type;
7747  }
7748}
7749
7750void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
7751  Primitive::Type type = instruction->GetType();
7752
7753  switch (type) {
7754    case Primitive::kPrimInt:
7755      GenerateDivRemIntegral(instruction);
7756      break;
7757    case Primitive::kPrimLong: {
7758      codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
7759      CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
7760      break;
7761    }
7762    case Primitive::kPrimFloat: {
7763      codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
7764      CheckEntrypointTypes<kQuickFmodf, float, float, float>();
7765      break;
7766    }
7767    case Primitive::kPrimDouble: {
7768      codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
7769      CheckEntrypointTypes<kQuickFmod, double, double, double>();
7770      break;
7771    }
7772    default:
7773      LOG(FATAL) << "Unexpected rem type " << type;
7774  }
7775}
7776
7777void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
7778  memory_barrier->SetLocations(nullptr);
7779}
7780
7781void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
7782  GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
7783}
7784
7785void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
7786  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
7787  Primitive::Type return_type = ret->InputAt(0)->GetType();
7788  locations->SetInAt(0, MipsReturnLocation(return_type));
7789}
7790
7791void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
7792  codegen_->GenerateFrameExit();
7793}
7794
7795void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
7796  ret->SetLocations(nullptr);
7797}
7798
7799void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
7800  codegen_->GenerateFrameExit();
7801}
7802
7803void LocationsBuilderMIPS::VisitRor(HRor* ror) {
7804  HandleShift(ror);
7805}
7806
7807void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
7808  HandleShift(ror);
7809}
7810
7811void LocationsBuilderMIPS::VisitShl(HShl* shl) {
7812  HandleShift(shl);
7813}
7814
7815void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
7816  HandleShift(shl);
7817}
7818
7819void LocationsBuilderMIPS::VisitShr(HShr* shr) {
7820  HandleShift(shr);
7821}
7822
7823void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
7824  HandleShift(shr);
7825}
7826
7827void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
7828  HandleBinaryOp(instruction);
7829}
7830
7831void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
7832  HandleBinaryOp(instruction);
7833}
7834
7835void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
7836  HandleFieldGet(instruction, instruction->GetFieldInfo());
7837}
7838
7839void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
7840  HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
7841}
7842
7843void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
7844  HandleFieldSet(instruction, instruction->GetFieldInfo());
7845}
7846
7847void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
7848  HandleFieldSet(instruction,
7849                 instruction->GetFieldInfo(),
7850                 instruction->GetDexPc(),
7851                 instruction->GetValueCanBeNull());
7852}
7853
7854void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
7855    HUnresolvedInstanceFieldGet* instruction) {
7856  FieldAccessCallingConventionMIPS calling_convention;
7857  codegen_->CreateUnresolvedFieldLocationSummary(instruction,
7858                                                 instruction->GetFieldType(),
7859                                                 calling_convention);
7860}
7861
7862void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
7863    HUnresolvedInstanceFieldGet* instruction) {
7864  FieldAccessCallingConventionMIPS calling_convention;
7865  codegen_->GenerateUnresolvedFieldAccess(instruction,
7866                                          instruction->GetFieldType(),
7867                                          instruction->GetFieldIndex(),
7868                                          instruction->GetDexPc(),
7869                                          calling_convention);
7870}
7871
7872void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
7873    HUnresolvedInstanceFieldSet* instruction) {
7874  FieldAccessCallingConventionMIPS calling_convention;
7875  codegen_->CreateUnresolvedFieldLocationSummary(instruction,
7876                                                 instruction->GetFieldType(),
7877                                                 calling_convention);
7878}
7879
7880void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
7881    HUnresolvedInstanceFieldSet* instruction) {
7882  FieldAccessCallingConventionMIPS calling_convention;
7883  codegen_->GenerateUnresolvedFieldAccess(instruction,
7884                                          instruction->GetFieldType(),
7885                                          instruction->GetFieldIndex(),
7886                                          instruction->GetDexPc(),
7887                                          calling_convention);
7888}
7889
7890void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
7891    HUnresolvedStaticFieldGet* instruction) {
7892  FieldAccessCallingConventionMIPS calling_convention;
7893  codegen_->CreateUnresolvedFieldLocationSummary(instruction,
7894                                                 instruction->GetFieldType(),
7895                                                 calling_convention);
7896}
7897
7898void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
7899    HUnresolvedStaticFieldGet* instruction) {
7900  FieldAccessCallingConventionMIPS calling_convention;
7901  codegen_->GenerateUnresolvedFieldAccess(instruction,
7902                                          instruction->GetFieldType(),
7903                                          instruction->GetFieldIndex(),
7904                                          instruction->GetDexPc(),
7905                                          calling_convention);
7906}
7907
7908void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
7909    HUnresolvedStaticFieldSet* instruction) {
7910  FieldAccessCallingConventionMIPS calling_convention;
7911  codegen_->CreateUnresolvedFieldLocationSummary(instruction,
7912                                                 instruction->GetFieldType(),
7913                                                 calling_convention);
7914}
7915
7916void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
7917    HUnresolvedStaticFieldSet* instruction) {
7918  FieldAccessCallingConventionMIPS calling_convention;
7919  codegen_->GenerateUnresolvedFieldAccess(instruction,
7920                                          instruction->GetFieldType(),
7921                                          instruction->GetFieldIndex(),
7922                                          instruction->GetDexPc(),
7923                                          calling_convention);
7924}
7925
7926void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
7927  LocationSummary* locations =
7928      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
7929  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
7930}
7931
7932void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
7933  HBasicBlock* block = instruction->GetBlock();
7934  if (block->GetLoopInformation() != nullptr) {
7935    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
7936    // The back edge will generate the suspend check.
7937    return;
7938  }
7939  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
7940    // The goto will generate the suspend check.
7941    return;
7942  }
7943  GenerateSuspendCheck(instruction, nullptr);
7944}
7945
7946void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
7947  LocationSummary* locations =
7948      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
7949  InvokeRuntimeCallingConvention calling_convention;
7950  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7951}
7952
7953void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
7954  codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
7955  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
7956}
7957
7958void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
7959  Primitive::Type input_type = conversion->GetInputType();
7960  Primitive::Type result_type = conversion->GetResultType();
7961  DCHECK_NE(input_type, result_type);
7962  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
7963
7964  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
7965      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
7966    LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
7967  }
7968
7969  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7970  if (!isR6 &&
7971      ((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
7972       (result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
7973    call_kind = LocationSummary::kCallOnMainOnly;
7974  }
7975
7976  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
7977
7978  if (call_kind == LocationSummary::kNoCall) {
7979    if (Primitive::IsFloatingPointType(input_type)) {
7980      locations->SetInAt(0, Location::RequiresFpuRegister());
7981    } else {
7982      locations->SetInAt(0, Location::RequiresRegister());
7983    }
7984
7985    if (Primitive::IsFloatingPointType(result_type)) {
7986      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
7987    } else {
7988      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7989    }
7990  } else {
7991    InvokeRuntimeCallingConvention calling_convention;
7992
7993    if (Primitive::IsFloatingPointType(input_type)) {
7994      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
7995    } else {
7996      DCHECK_EQ(input_type, Primitive::kPrimLong);
7997      locations->SetInAt(0, Location::RegisterPairLocation(
7998                 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
7999    }
8000
8001    locations->SetOut(calling_convention.GetReturnLocation(result_type));
8002  }
8003}
8004
8005void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
8006  LocationSummary* locations = conversion->GetLocations();
8007  Primitive::Type result_type = conversion->GetResultType();
8008  Primitive::Type input_type = conversion->GetInputType();
8009  bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
8010  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
8011
8012  DCHECK_NE(input_type, result_type);
8013
8014  if (result_type == Primitive::kPrimLong && Primitive::IsIntegralType(input_type)) {
8015    Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8016    Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8017    Register src = locations->InAt(0).AsRegister<Register>();
8018
8019    if (dst_low != src) {
8020      __ Move(dst_low, src);
8021    }
8022    __ Sra(dst_high, src, 31);
8023  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
8024    Register dst = locations->Out().AsRegister<Register>();
8025    Register src = (input_type == Primitive::kPrimLong)
8026        ? locations->InAt(0).AsRegisterPairLow<Register>()
8027        : locations->InAt(0).AsRegister<Register>();
8028
8029    switch (result_type) {
8030      case Primitive::kPrimChar:
8031        __ Andi(dst, src, 0xFFFF);
8032        break;
8033      case Primitive::kPrimByte:
8034        if (has_sign_extension) {
8035          __ Seb(dst, src);
8036        } else {
8037          __ Sll(dst, src, 24);
8038          __ Sra(dst, dst, 24);
8039        }
8040        break;
8041      case Primitive::kPrimShort:
8042        if (has_sign_extension) {
8043          __ Seh(dst, src);
8044        } else {
8045          __ Sll(dst, src, 16);
8046          __ Sra(dst, dst, 16);
8047        }
8048        break;
8049      case Primitive::kPrimInt:
8050        if (dst != src) {
8051          __ Move(dst, src);
8052        }
8053        break;
8054
8055      default:
8056        LOG(FATAL) << "Unexpected type conversion from " << input_type
8057                   << " to " << result_type;
8058    }
8059  } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
8060    if (input_type == Primitive::kPrimLong) {
8061      if (isR6) {
8062        // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
8063        // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
8064        Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8065        Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8066        FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8067        __ Mtc1(src_low, FTMP);
8068        __ Mthc1(src_high, FTMP);
8069        if (result_type == Primitive::kPrimFloat) {
8070          __ Cvtsl(dst, FTMP);
8071        } else {
8072          __ Cvtdl(dst, FTMP);
8073        }
8074      } else {
8075        QuickEntrypointEnum entrypoint = (result_type == Primitive::kPrimFloat) ? kQuickL2f
8076                                                                                : kQuickL2d;
8077        codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
8078        if (result_type == Primitive::kPrimFloat) {
8079          CheckEntrypointTypes<kQuickL2f, float, int64_t>();
8080        } else {
8081          CheckEntrypointTypes<kQuickL2d, double, int64_t>();
8082        }
8083      }
8084    } else {
8085      Register src = locations->InAt(0).AsRegister<Register>();
8086      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8087      __ Mtc1(src, FTMP);
8088      if (result_type == Primitive::kPrimFloat) {
8089        __ Cvtsw(dst, FTMP);
8090      } else {
8091        __ Cvtdw(dst, FTMP);
8092      }
8093    }
8094  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
8095    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
8096    if (result_type == Primitive::kPrimLong) {
8097      if (isR6) {
8098        // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
8099        // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
8100        FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
8101        Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8102        Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8103        MipsLabel truncate;
8104        MipsLabel done;
8105
8106        // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
8107        // value when the input is either a NaN or is outside of the range of the output type
8108        // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
8109        // the same result.
8110        //
8111        // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
8112        // value of the output type if the input is outside of the range after the truncation or
8113        // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
8114        // results. This matches the desired float/double-to-int/long conversion exactly.
8115        //
8116        // So, NAN2008 affects handling of negative values and NaNs by the truncate instruction.
8117        //
8118        // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
8119        // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
8120        // even though it must be NAN2008=1 on R6.
8121        //
8122        // The code takes care of the different behaviors by first comparing the input to the
8123        // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
8124        // If the input is greater than or equal to the minimum, it procedes to the truncate
8125        // instruction, which will handle such an input the same way irrespective of NAN2008.
8126        // Otherwise the input is compared to itself to determine whether it is a NaN or not
8127        // in order to return either zero or the minimum value.
8128        //
8129        // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
8130        // truncate instruction for MIPS64R6.
8131        if (input_type == Primitive::kPrimFloat) {
8132          uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int64_t>::min());
8133          __ LoadConst32(TMP, min_val);
8134          __ Mtc1(TMP, FTMP);
8135          __ CmpLeS(FTMP, FTMP, src);
8136        } else {
8137          uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int64_t>::min());
8138          __ LoadConst32(TMP, High32Bits(min_val));
8139          __ Mtc1(ZERO, FTMP);
8140          __ Mthc1(TMP, FTMP);
8141          __ CmpLeD(FTMP, FTMP, src);
8142        }
8143
8144        __ Bc1nez(FTMP, &truncate);
8145
8146        if (input_type == Primitive::kPrimFloat) {
8147          __ CmpEqS(FTMP, src, src);
8148        } else {
8149          __ CmpEqD(FTMP, src, src);
8150        }
8151        __ Move(dst_low, ZERO);
8152        __ LoadConst32(dst_high, std::numeric_limits<int32_t>::min());
8153        __ Mfc1(TMP, FTMP);
8154        __ And(dst_high, dst_high, TMP);
8155
8156        __ B(&done);
8157
8158        __ Bind(&truncate);
8159
8160        if (input_type == Primitive::kPrimFloat) {
8161          __ TruncLS(FTMP, src);
8162        } else {
8163          __ TruncLD(FTMP, src);
8164        }
8165        __ Mfc1(dst_low, FTMP);
8166        __ Mfhc1(dst_high, FTMP);
8167
8168        __ Bind(&done);
8169      } else {
8170        QuickEntrypointEnum entrypoint = (input_type == Primitive::kPrimFloat) ? kQuickF2l
8171                                                                               : kQuickD2l;
8172        codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
8173        if (input_type == Primitive::kPrimFloat) {
8174          CheckEntrypointTypes<kQuickF2l, int64_t, float>();
8175        } else {
8176          CheckEntrypointTypes<kQuickD2l, int64_t, double>();
8177        }
8178      }
8179    } else {
8180      FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
8181      Register dst = locations->Out().AsRegister<Register>();
8182      MipsLabel truncate;
8183      MipsLabel done;
8184
8185      // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
8186      // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
8187      // even though it must be NAN2008=1 on R6.
8188      //
8189      // For details see the large comment above for the truncation of float/double to long on R6.
8190      //
8191      // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
8192      // truncate instruction for MIPS64R6.
8193      if (input_type == Primitive::kPrimFloat) {
8194        uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
8195        __ LoadConst32(TMP, min_val);
8196        __ Mtc1(TMP, FTMP);
8197      } else {
8198        uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
8199        __ LoadConst32(TMP, High32Bits(min_val));
8200        __ Mtc1(ZERO, FTMP);
8201        __ MoveToFpuHigh(TMP, FTMP);
8202      }
8203
8204      if (isR6) {
8205        if (input_type == Primitive::kPrimFloat) {
8206          __ CmpLeS(FTMP, FTMP, src);
8207        } else {
8208          __ CmpLeD(FTMP, FTMP, src);
8209        }
8210        __ Bc1nez(FTMP, &truncate);
8211
8212        if (input_type == Primitive::kPrimFloat) {
8213          __ CmpEqS(FTMP, src, src);
8214        } else {
8215          __ CmpEqD(FTMP, src, src);
8216        }
8217        __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
8218        __ Mfc1(TMP, FTMP);
8219        __ And(dst, dst, TMP);
8220      } else {
8221        if (input_type == Primitive::kPrimFloat) {
8222          __ ColeS(0, FTMP, src);
8223        } else {
8224          __ ColeD(0, FTMP, src);
8225        }
8226        __ Bc1t(0, &truncate);
8227
8228        if (input_type == Primitive::kPrimFloat) {
8229          __ CeqS(0, src, src);
8230        } else {
8231          __ CeqD(0, src, src);
8232        }
8233        __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
8234        __ Movf(dst, ZERO, 0);
8235      }
8236
8237      __ B(&done);
8238
8239      __ Bind(&truncate);
8240
8241      if (input_type == Primitive::kPrimFloat) {
8242        __ TruncWS(FTMP, src);
8243      } else {
8244        __ TruncWD(FTMP, src);
8245      }
8246      __ Mfc1(dst, FTMP);
8247
8248      __ Bind(&done);
8249    }
8250  } else if (Primitive::IsFloatingPointType(result_type) &&
8251             Primitive::IsFloatingPointType(input_type)) {
8252    FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8253    FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
8254    if (result_type == Primitive::kPrimFloat) {
8255      __ Cvtsd(dst, src);
8256    } else {
8257      __ Cvtds(dst, src);
8258    }
8259  } else {
8260    LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
8261                << " to " << result_type;
8262  }
8263}
8264
8265void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
8266  HandleShift(ushr);
8267}
8268
8269void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
8270  HandleShift(ushr);
8271}
8272
8273void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
8274  HandleBinaryOp(instruction);
8275}
8276
8277void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
8278  HandleBinaryOp(instruction);
8279}
8280
8281void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
8282  // Nothing to do, this should be removed during prepare for register allocator.
8283  LOG(FATAL) << "Unreachable";
8284}
8285
8286void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
8287  // Nothing to do, this should be removed during prepare for register allocator.
8288  LOG(FATAL) << "Unreachable";
8289}
8290
8291void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
8292  HandleCondition(comp);
8293}
8294
8295void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
8296  HandleCondition(comp);
8297}
8298
8299void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
8300  HandleCondition(comp);
8301}
8302
8303void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
8304  HandleCondition(comp);
8305}
8306
8307void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
8308  HandleCondition(comp);
8309}
8310
8311void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
8312  HandleCondition(comp);
8313}
8314
8315void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
8316  HandleCondition(comp);
8317}
8318
8319void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
8320  HandleCondition(comp);
8321}
8322
8323void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
8324  HandleCondition(comp);
8325}
8326
8327void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
8328  HandleCondition(comp);
8329}
8330
8331void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
8332  HandleCondition(comp);
8333}
8334
8335void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
8336  HandleCondition(comp);
8337}
8338
8339void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
8340  HandleCondition(comp);
8341}
8342
8343void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
8344  HandleCondition(comp);
8345}
8346
8347void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
8348  HandleCondition(comp);
8349}
8350
8351void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
8352  HandleCondition(comp);
8353}
8354
8355void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
8356  HandleCondition(comp);
8357}
8358
8359void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
8360  HandleCondition(comp);
8361}
8362
8363void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
8364  HandleCondition(comp);
8365}
8366
8367void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
8368  HandleCondition(comp);
8369}
8370
8371void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8372  LocationSummary* locations =
8373      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8374  locations->SetInAt(0, Location::RequiresRegister());
8375}
8376
8377void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
8378                                                               int32_t lower_bound,
8379                                                               uint32_t num_entries,
8380                                                               HBasicBlock* switch_block,
8381                                                               HBasicBlock* default_block) {
8382  // Create a set of compare/jumps.
8383  Register temp_reg = TMP;
8384  __ Addiu32(temp_reg, value_reg, -lower_bound);
8385  // Jump to default if index is negative
8386  // Note: We don't check the case that index is positive while value < lower_bound, because in
8387  // this case, index >= num_entries must be true. So that we can save one branch instruction.
8388  __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
8389
8390  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
8391  // Jump to successors[0] if value == lower_bound.
8392  __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
8393  int32_t last_index = 0;
8394  for (; num_entries - last_index > 2; last_index += 2) {
8395    __ Addiu(temp_reg, temp_reg, -2);
8396    // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
8397    __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
8398    // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
8399    __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
8400  }
8401  if (num_entries - last_index == 2) {
8402    // The last missing case_value.
8403    __ Addiu(temp_reg, temp_reg, -1);
8404    __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
8405  }
8406
8407  // And the default for any other value.
8408  if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
8409    __ B(codegen_->GetLabelOf(default_block));
8410  }
8411}
8412
8413void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
8414                                                             Register constant_area,
8415                                                             int32_t lower_bound,
8416                                                             uint32_t num_entries,
8417                                                             HBasicBlock* switch_block,
8418                                                             HBasicBlock* default_block) {
8419  // Create a jump table.
8420  std::vector<MipsLabel*> labels(num_entries);
8421  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
8422  for (uint32_t i = 0; i < num_entries; i++) {
8423    labels[i] = codegen_->GetLabelOf(successors[i]);
8424  }
8425  JumpTable* table = __ CreateJumpTable(std::move(labels));
8426
8427  // Is the value in range?
8428  __ Addiu32(TMP, value_reg, -lower_bound);
8429  if (IsInt<16>(static_cast<int32_t>(num_entries))) {
8430    __ Sltiu(AT, TMP, num_entries);
8431    __ Beqz(AT, codegen_->GetLabelOf(default_block));
8432  } else {
8433    __ LoadConst32(AT, num_entries);
8434    __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
8435  }
8436
8437  // We are in the range of the table.
8438  // Load the target address from the jump table, indexing by the value.
8439  __ LoadLabelAddress(AT, constant_area, table->GetLabel());
8440  __ ShiftAndAdd(TMP, TMP, AT, 2, TMP);
8441  __ Lw(TMP, TMP, 0);
8442  // Compute the absolute target address by adding the table start address
8443  // (the table contains offsets to targets relative to its start).
8444  __ Addu(TMP, TMP, AT);
8445  // And jump.
8446  __ Jr(TMP);
8447  __ NopIfNoReordering();
8448}
8449
8450void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8451  int32_t lower_bound = switch_instr->GetStartValue();
8452  uint32_t num_entries = switch_instr->GetNumEntries();
8453  LocationSummary* locations = switch_instr->GetLocations();
8454  Register value_reg = locations->InAt(0).AsRegister<Register>();
8455  HBasicBlock* switch_block = switch_instr->GetBlock();
8456  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8457
8458  if (codegen_->GetInstructionSetFeatures().IsR6() &&
8459      num_entries > kPackedSwitchJumpTableThreshold) {
8460    // R6 uses PC-relative addressing to access the jump table.
8461    // R2, OTOH, requires an HMipsComputeBaseMethodAddress input to access
8462    // the jump table and it is implemented by changing HPackedSwitch to
8463    // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress.
8464    // See VisitMipsPackedSwitch() for the table-based implementation on R2.
8465    GenTableBasedPackedSwitch(value_reg,
8466                              ZERO,
8467                              lower_bound,
8468                              num_entries,
8469                              switch_block,
8470                              default_block);
8471  } else {
8472    GenPackedSwitchWithCompares(value_reg,
8473                                lower_bound,
8474                                num_entries,
8475                                switch_block,
8476                                default_block);
8477  }
8478}
8479
8480void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
8481  LocationSummary* locations =
8482      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8483  locations->SetInAt(0, Location::RequiresRegister());
8484  // Constant area pointer (HMipsComputeBaseMethodAddress).
8485  locations->SetInAt(1, Location::RequiresRegister());
8486}
8487
8488void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
8489  int32_t lower_bound = switch_instr->GetStartValue();
8490  uint32_t num_entries = switch_instr->GetNumEntries();
8491  LocationSummary* locations = switch_instr->GetLocations();
8492  Register value_reg = locations->InAt(0).AsRegister<Register>();
8493  Register constant_area = locations->InAt(1).AsRegister<Register>();
8494  HBasicBlock* switch_block = switch_instr->GetBlock();
8495  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8496
8497  // This is an R2-only path. HPackedSwitch has been changed to
8498  // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
8499  // required to address the jump table relative to PC.
8500  GenTableBasedPackedSwitch(value_reg,
8501                            constant_area,
8502                            lower_bound,
8503                            num_entries,
8504                            switch_block,
8505                            default_block);
8506}
8507
8508void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
8509    HMipsComputeBaseMethodAddress* insn) {
8510  LocationSummary* locations =
8511      new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
8512  locations->SetOut(Location::RequiresRegister());
8513}
8514
8515void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress(
8516    HMipsComputeBaseMethodAddress* insn) {
8517  LocationSummary* locations = insn->GetLocations();
8518  Register reg = locations->Out().AsRegister<Register>();
8519
8520  CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
8521
8522  // Generate a dummy PC-relative call to obtain PC.
8523  __ Nal();
8524  // Grab the return address off RA.
8525  __ Move(reg, RA);
8526  // TODO: Can we share this code with that of VisitMipsDexCacheArraysBase()?
8527
8528  // Remember this offset (the obtained PC value) for later use with constant area.
8529  __ BindPcRelBaseLabel();
8530}
8531
8532void LocationsBuilderMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
8533  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
8534  locations->SetOut(Location::RequiresRegister());
8535}
8536
8537void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
8538  Register reg = base->GetLocations()->Out().AsRegister<Register>();
8539  CodeGeneratorMIPS::PcRelativePatchInfo* info =
8540      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
8541  CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
8542  bool reordering = __ SetReorder(false);
8543  // TODO: Reuse MipsComputeBaseMethodAddress on R2 instead of passing ZERO to force emitting NAL.
8544  codegen_->EmitPcRelativeAddressPlaceholderHigh(info, reg, ZERO);
8545  __ Addiu(reg, reg, /* placeholder */ 0x5678);
8546  __ SetReorder(reordering);
8547}
8548
8549void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
8550  // The trampoline uses the same calling convention as dex calling conventions,
8551  // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
8552  // the method_idx.
8553  HandleInvoke(invoke);
8554}
8555
8556void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
8557  codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
8558}
8559
8560void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
8561  LocationSummary* locations =
8562      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8563  locations->SetInAt(0, Location::RequiresRegister());
8564  locations->SetOut(Location::RequiresRegister());
8565}
8566
8567void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
8568  LocationSummary* locations = instruction->GetLocations();
8569  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
8570    uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8571        instruction->GetIndex(), kMipsPointerSize).SizeValue();
8572    __ LoadFromOffset(kLoadWord,
8573                      locations->Out().AsRegister<Register>(),
8574                      locations->InAt(0).AsRegister<Register>(),
8575                      method_offset);
8576  } else {
8577    uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
8578        instruction->GetIndex(), kMipsPointerSize));
8579    __ LoadFromOffset(kLoadWord,
8580                      locations->Out().AsRegister<Register>(),
8581                      locations->InAt(0).AsRegister<Register>(),
8582                      mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
8583    __ LoadFromOffset(kLoadWord,
8584                      locations->Out().AsRegister<Register>(),
8585                      locations->Out().AsRegister<Register>(),
8586                      method_offset);
8587  }
8588}
8589
8590#undef __
8591#undef QUICK_ENTRY_POINT
8592
8593}  // namespace mips
8594}  // namespace art
8595